Compare commits

...

150 Commits

Author SHA1 Message Date
Nuno Cruces
831a34a4c4 Updated dependencies. 2023-12-07 14:00:08 +00:00
Nuno Cruces
7c820ede3c Driver time formatting. 2023-12-07 13:49:33 +00:00
Nuno Cruces
089a0c0670 Pivot virtual table. 2023-12-06 17:49:48 +00:00
Nuno Cruces
8b45cac16b Improved error handling. 2023-12-05 18:17:33 +00:00
Nuno Cruces
06d2ff6752 Optimize VFS find. 2023-12-05 14:11:20 +00:00
Nuno Cruces
987f0f13a2 Test CPUs. 2023-12-04 14:01:25 +00:00
Nuno Cruces
cd40213898 Reuse statement, API. 2023-12-04 13:46:48 +00:00
Nuno Cruces
8a0baedc10 Tests, fixes. 2023-12-02 12:17:18 +00:00
Nuno Cruces
c667a1f469 Declared type. 2023-12-02 12:17:18 +00:00
Nuno Cruces
9c562f5d8b Cache functions. 2023-12-02 12:17:18 +00:00
Nuno Cruces
d862f47d95 Deoptimize. 2023-12-02 12:17:18 +00:00
Nuno Cruces
a9e32fd3f0 Fix compiler crash. 2023-12-02 12:17:18 +00:00
Nuno Cruces
b262f5cd01 Statement virtual table. 2023-12-02 12:17:18 +00:00
Nuno Cruces
4160b9a4bb Simplify tails. 2023-11-30 18:18:27 +00:00
Nuno Cruces
dbaf2d99cd Unprotected values. 2023-11-30 00:29:41 +00:00
Nuno Cruces
3f05115cd7 Virtual table API. 2023-11-29 10:46:11 +00:00
Nuno Cruces
9bf14becaf Reentrant arenas. 2023-11-29 10:46:02 +00:00
Nuno Cruces
997e197f54 VFS tweaks. 2023-11-28 16:38:02 +00:00
Nuno Cruces
b81fe284b6 memdb WAL. 2023-11-28 11:40:04 +00:00
dependabot[bot]
269306c5c8 Bump golang.org/x/sys from 0.14.0 to 0.15.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.14.0 to 0.15.0.
- [Commits](https://github.com/golang/sys/compare/v0.14.0...v0.15.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-28 02:00:06 +00:00
Nuno Cruces
8a18243830 Reproducible builds. 2023-11-28 01:55:26 +00:00
Nuno Cruces
fcd6cc91d8 Skip BOM. 2023-11-27 23:35:43 +00:00
Nuno Cruces
c1838fc0bc Fix encoding issues. 2023-11-27 15:37:53 +00:00
Nuno Cruces
dc0d8236bf Updated dependencies. 2023-11-25 00:39:20 +00:00
Nuno Cruces
ba18facb0d SQLite 3.44.2. 2023-11-25 00:10:38 +00:00
Nuno Cruces
5653efa70e Limits. 2023-11-25 00:10:32 +00:00
Nuno Cruces
1acb95917a Simplify aggregate context. 2023-11-24 15:33:17 +00:00
Nuno Cruces
e31a42fb22 Lines virtual table. 2023-11-23 15:59:24 +00:00
Nuno Cruces
aec69acca9 Update README.md 2023-11-23 13:03:38 +00:00
Nuno Cruces
f2d6bdb8b7 Tests. 2023-11-23 12:53:28 +00:00
Nuno Cruces
9bb01d1f8b CSV virtual table. 2023-11-23 03:36:54 +00:00
Nuno Cruces
83c15f2ddc Virtual table API. 2023-11-22 15:06:39 +00:00
Nuno Cruces
97d4248176 Array extension. 2023-11-21 13:40:55 +00:00
Nuno Cruces
22d1ae0068 Tweaks. 2023-11-21 09:45:47 +00:00
Nuno Cruces
ae1d696cf3 Virtual tables fixes. 2023-11-20 18:12:56 +00:00
Nuno Cruces
5992403052 Virtual tables. 2023-11-20 00:27:12 +00:00
Nuno Cruces
f212b6712d Error handling. 2023-11-18 10:15:18 +00:00
Nuno Cruces
a49cc084f3 Towards virtual tables. 2023-11-17 22:39:00 +00:00
Nuno Cruces
2c2f825bc5 Towards virtual tables. 2023-11-17 19:06:10 +00:00
Nuno Cruces
787086b8c1 Towards virtual tables. 2023-11-17 02:23:10 +00:00
Nuno Cruces
314098addb Towards virtual tables. 2023-11-15 10:57:19 +00:00
Nuno Cruces
4bf8a79c1d Towards virtual tables. 2023-11-14 13:56:27 +00:00
Nuno Cruces
90628ab8aa Text as byte slices. 2023-11-10 13:42:20 +00:00
Nuno Cruces
aa02c14430 Towards virtual tables. 2023-11-10 13:23:14 +00:00
Nuno Cruces
1dc06bff49 Simplify URLs. 2023-11-09 16:35:45 +00:00
Nuno Cruces
4e9173661b Foreign keys activation. 2023-11-09 16:20:44 +00:00
Nuno Cruces
591480cd39 Fix JSON. 2023-11-09 16:16:48 +00:00
Nuno Cruces
828788912e JSON example. 2023-11-09 12:11:36 +00:00
Nuno Cruces
6f8645cd2e Tests. 2023-11-08 07:28:48 +00:00
Nuno Cruces
c00927e8bb Driver savepoints. 2023-11-07 15:19:40 +00:00
dependabot[bot]
6b28be6d0e Bump golang.org/x/sys from 0.13.0 to 0.14.0 (#36)
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.13.0 to 0.14.0.
- [Commits](https://github.com/golang/sys/compare/v0.13.0...v0.14.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-07 15:00:00 +00:00
dependabot[bot]
310b4ff29d Bump golang.org/x/sync from 0.4.0 to 0.5.0 (#35)
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.4.0 to 0.5.0.
- [Commits](https://github.com/golang/sync/compare/v0.4.0...v0.5.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sync
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-07 12:38:12 +00:00
dependabot[bot]
e82cf16b11 Bump golang.org/x/text from 0.13.0 to 0.14.0 (#34)
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.13.0 to 0.14.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.13.0...v0.14.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-07 00:57:28 +00:00
Nuno Cruces
24c9b57c56 Pointer-passing interfaces. 2023-11-07 00:50:43 +00:00
Nuno Cruces
24b965ac7e Refactor. 2023-11-06 18:29:28 +00:00
Nuno Cruces
446168c572 Update workflows. 2023-11-04 11:21:31 +00:00
Nuno Cruces
a9e2cbbfc5 Quote values, identifiers. 2023-11-04 01:18:25 +00:00
Nuno Cruces
a7c00eb150 SQLite 3.44.0. 2023-11-03 03:43:14 -07:00
Nuno Cruces
0bcdb712ba SQL json_time function. 2023-11-03 03:40:46 -07:00
Nuno Cruces
2157d0f325 Interrupts: avoid goroutine. 2023-10-25 14:12:21 +01:00
Nuno Cruces
6353160619 Improve benchmark repeatability. 2023-10-25 13:17:37 +01:00
Nuno Cruces
501d157279 Update BSD test. 2023-10-24 23:27:10 +01:00
Nuno Cruces
4db18a7b9a JSON encoding fix. 2023-10-19 16:46:58 +01:00
Nuno Cruces
a9dddaa86c Optimize VFS search. 2023-10-19 16:43:54 +01:00
Nuno Cruces
b25936dbec Unix formats return UTC. 2023-10-19 12:07:03 +01:00
dependabot[bot]
bf23041e46 Bump github.com/ncruces/julianday from 0.1.5 to 1.0.0 (#33)
Bumps [github.com/ncruces/julianday](https://github.com/ncruces/julianday) from 0.1.5 to 1.0.0.
- [Commits](https://github.com/ncruces/julianday/compare/v0.1.5...v1.0.0)

---
updated-dependencies:
- dependency-name: github.com/ncruces/julianday
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-19 00:34:35 +01:00
Nuno Cruces
d60fceac92 JSON support. 2023-10-18 23:14:46 +01:00
Nuno Cruces
61da30f44a Allow configuring wazero. 2023-10-18 15:06:32 +01:00
Nuno Cruces
d4ff605983 Time scanner. 2023-10-18 15:06:12 +01:00
Nuno Cruces
8d0c654178 Cross compilation. 2023-10-17 15:30:08 +01:00
Nuno Cruces
728e59951b Test BSD. 2023-10-16 12:51:49 +01:00
Nuno Cruces
f7b16bad5c Patch flaky tests. 2023-10-16 12:26:25 +01:00
Nuno Cruces
db3e6da31a BSD locks. 2023-10-16 02:11:20 +01:00
Nuno Cruces
3f443b2ecc API change. 2023-10-13 18:53:37 +01:00
Nuno Cruces
eec45ea684 Towards JSON. 2023-10-13 17:06:05 +01:00
Nuno Cruces
f6d77f3cf4 GORM v1.25.5. 2023-10-13 00:42:06 +01:00
Nuno Cruces
d5d7cd1f2d SQLite 3.43.2. 2023-10-12 10:52:48 +01:00
dependabot[bot]
a33a187d48 Bump golang.org/x/sys from 0.12.0 to 0.13.0 (#30)
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.12.0 to 0.13.0.
- [Commits](https://github.com/golang/sys/compare/v0.12.0...v0.13.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-05 23:53:11 +01:00
dependabot[bot]
70c6ee15c6 Bump golang.org/x/sync from 0.3.0 to 0.4.0 (#29)
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.3.0 to 0.4.0.
- [Commits](https://github.com/golang/sync/compare/v0.3.0...v0.4.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sync
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-05 23:43:11 +01:00
Nuno Cruces
994d9b1812 Updated dependencies. 2023-10-02 10:09:26 +01:00
Nuno Cruces
b19bd28ed3 Simplify lock timeouts. 2023-10-02 10:06:09 +01:00
Nuno Cruces
e66bd51845 More VFS API. 2023-09-21 02:43:45 +01:00
Nuno Cruces
f5614bc2ed Tweaks. 2023-09-20 15:07:07 +01:00
Nuno Cruces
d9fcf60b7d Driver API. 2023-09-20 02:41:09 +01:00
Nuno Cruces
ac6dd1aa5f Updated dependencies. 2023-09-18 15:22:11 +01:00
Nuno Cruces
b1495bd6cb Build tags, docs. 2023-09-18 15:11:05 +01:00
Nuno Cruces
2d91760295 Portability. 2023-09-18 12:44:18 +01:00
Nuno Cruces
38d4254bc4 Update README.md 2023-09-15 15:37:57 +01:00
Nuno Cruces
c0aa734786 binaryen-version_116. 2023-09-15 15:10:08 +01:00
Nuno Cruces
fa845dbd3d Run test in all platforms. 2023-09-12 15:30:43 +01:00
Nuno Cruces
fed315ab79 Update go.yml 2023-09-12 15:28:11 +01:00
Nuno Cruces
726d7316f7 Update README.md 2023-09-12 00:00:32 +01:00
Nuno Cruces
ddb387b021 Updated dependencies. 2023-09-11 23:54:22 +01:00
Nuno Cruces
d0f19507f5 SQLite 3.43.1. 2023-09-11 23:48:38 +01:00
Nuno Cruces
9d997552ad Pearson correlation. 2023-09-02 00:48:55 +01:00
Nuno Cruces
9d75c39dcc Update README.md 2023-09-01 16:01:42 +01:00
Nuno Cruces
746a84965e Covariance. 2023-09-01 02:38:57 +01:00
Nuno Cruces
312d3b58f2 Statistics functions. 2023-09-01 01:23:25 +01:00
Nuno Cruces
b71cd295c2 Updated dependencies. 2023-08-25 09:56:09 +01:00
Nuno Cruces
5b3b61a304 SQLite 3.43.0. 2023-08-24 18:56:23 +01:00
Nuno Cruces
d661d15723 wazero v1.5.0. 2023-08-24 18:56:10 +01:00
Nuno Cruces
1e38165ad0 Timer resolution. 2023-08-20 03:12:55 +01:00
Nuno Cruces
58a32d7c9d Update GORM. 2023-08-20 00:56:08 +01:00
Nuno Cruces
6765e883c1 Register collation. 2023-08-10 13:39:52 +01:00
Nuno Cruces
18fc608433 Embed database as string. 2023-08-10 13:23:54 +01:00
Nuno Cruces
77f37893b9 Driver connector. 2023-08-10 13:18:13 +01:00
Nuno Cruces
f1e36e2581 Updated dependencies. 2023-08-09 16:30:32 +01:00
Nuno Cruces
772b9153c7 Use clear builtin. 2023-08-09 16:16:45 +01:00
Nuno Cruces
4b280a3a7e Updated dependencies. 2023-08-09 15:22:48 +01:00
Nuno Cruces
19b6098bf6 Update go.yml (#28) 2023-08-05 01:12:16 +01:00
dependabot[bot]
2aa685320f Bump golang.org/x/text from 0.11.0 to 0.12.0 (#26)
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.11.0 to 0.12.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.11.0...v0.12.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-05 00:36:56 +01:00
dependabot[bot]
9941be05c2 Bump golang.org/x/sys from 0.10.0 to 0.11.0 (#27)
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.10.0 to 0.11.0.
- [Commits](https://github.com/golang/sys/compare/v0.10.0...v0.11.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-05 00:35:11 +01:00
Nuno Cruces
a0a9ab7737 Avoid unnecessary alloc. 2023-08-04 14:12:36 +01:00
Nuno Cruces
a77727a1ce Port script. 2023-07-31 15:27:10 +01:00
Nuno Cruces
47fe032078 Updated dependencies. 2023-07-26 12:42:18 +01:00
Nuno Cruces
bdfe279444 Soundex. 2023-07-26 02:02:39 +01:00
dependabot[bot]
a86937a54e Bump github.com/tetratelabs/wazero from 1.3.0 to 1.3.1
Bumps [github.com/tetratelabs/wazero](https://github.com/tetratelabs/wazero) from 1.3.0 to 1.3.1.
- [Release notes](https://github.com/tetratelabs/wazero/releases)
- [Commits](https://github.com/tetratelabs/wazero/compare/v1.3.0...v1.3.1)

---
updated-dependencies:
- dependency-name: github.com/tetratelabs/wazero
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-25 08:02:20 +01:00
Nuno Cruces
6ef422fbde Unicode tests. 2023-07-13 12:19:32 +01:00
Nuno Cruces
ff0cb6fb88 Unicode tests, fixes. 2023-07-12 13:39:07 +01:00
Nuno Cruces
72db90efdf Unicode. 2023-07-11 16:34:15 +01:00
Nuno Cruces
5a3fdef3c5 wazero v1.3.0. 2023-07-11 12:30:39 +01:00
dependabot[bot]
ff34b0cae1 Bump golang.org/x/text from 0.10.0 to 0.11.0
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.10.0 to 0.11.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.10.0...v0.11.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-04 23:55:17 +01:00
Nuno Cruces
f064492bb1 Updated dependencies. 2023-07-04 19:55:11 +01:00
Nuno Cruces
1427d30541 Updated dependencies. 2023-07-04 19:48:55 +01:00
Nuno Cruces
d3730341f0 Unknown collations. 2023-07-04 11:16:29 +01:00
Nuno Cruces
78ac2386f6 Refactor. 2023-07-04 02:29:38 +01:00
Nuno Cruces
632ea933b3 Function aux data. 2023-07-04 02:18:03 +01:00
Nuno Cruces
0f7fa6ebc9 Tests. 2023-07-03 18:28:46 +01:00
Nuno Cruces
6f7f776488 Refactor. 2023-07-03 17:42:53 +01:00
Nuno Cruces
f6d7c5e9c5 Refactor. 2023-07-03 17:08:16 +01:00
Nuno Cruces
1cc7ecfe8d Custom aggregate functions. 2023-07-03 15:45:16 +01:00
Nuno Cruces
3844e81404 Custom aggregate functions. 2023-07-01 15:19:45 +01:00
Nuno Cruces
fec1f8d32a Custom scalar functions. 2023-07-01 00:16:42 +01:00
Nuno Cruces
31572e6095 Fix nil/zero handles. 2023-06-30 17:09:01 +01:00
Nuno Cruces
4aee38b957 Error handling. 2023-06-30 12:25:07 +01:00
Nuno Cruces
232a7705b5 Wrap context. 2023-06-30 11:48:54 +01:00
Nuno Cruces
a6c2fccd74 Wrap value. 2023-06-30 10:45:16 +01:00
Nuno Cruces
6a982559cd Custom collating sequences. 2023-06-30 02:49:21 +01:00
Nuno Cruces
c7904d30de Refactor file handles. 2023-06-30 01:52:18 +01:00
Nuno Cruces
ce4386604d GORM v1.25.1. 2023-06-29 20:06:56 +01:00
Nuno Cruces
26b62c520d Towards SQL functions. 2023-06-29 14:21:59 +01:00
Nuno Cruces
738714bf32 Fix WAL. 2023-06-26 13:31:42 +01:00
Nuno Cruces
41b020bafc go-sqlite3 v0.8.0. 2023-06-16 17:21:50 +01:00
Nuno Cruces
d0e720272b Optimization flags. 2023-06-15 15:57:39 +01:00
Nuno Cruces
76171da12b go-sqlite3 v0.7.3. 2023-06-15 03:56:02 +01:00
Nuno Cruces
dcc845d684 wazero v1.2.1. 2023-06-15 03:43:25 +01:00
dependabot[bot]
f1b42c26d5 Bump golang.org/x/sync from 0.2.0 to 0.3.0
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.2.0 to 0.3.0.
- [Commits](https://github.com/golang/sync/compare/v0.2.0...v0.3.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sync
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-15 00:13:43 +01:00
dependabot[bot]
1e94407ae7 Bump golang.org/x/sys from 0.8.0 to 0.9.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.8.0 to 0.9.0.
- [Commits](https://github.com/golang/sys/compare/v0.8.0...v0.9.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-13 00:31:02 +01:00
Nuno Cruces
eb8d9b95fd Consistent lock timeouts. 2023-06-12 13:04:37 +01:00
Nuno Cruces
04037a75ed GORM driver sync. 2023-06-12 10:56:03 +01:00
165 changed files with 8971 additions and 1937 deletions

29
.github/workflows/bsd.yml vendored Normal file
View File

@@ -0,0 +1,29 @@
name: BSD
on:
workflow_dispatch:
jobs:
test:
runs-on: macos-12
steps:
- uses: actions/checkout@v4
with:
lfs: 'true'
- name: Set up
uses: actions/setup-go@v4
with:
go-version: stable
- name: Build
run: GOOS=freebsd go test -c ./...
- name: Test
uses: cross-platform-actions/action@v0.21.1
with:
operating_system: freebsd
version: '13.2'
sync_files: runner-to-vm
run: find . -name '*.test' -maxdepth 1 -exec {} -test.v \;

View File

@@ -1,76 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ "main" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "main" ]
schedule:
- cron: '15 18 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'go' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Use only 'java' to analyze code written in Java, Kotlin or both
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{matrix.language}}"

40
.github/workflows/cpu.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
name: CPUs
on:
workflow_dispatch:
jobs:
test-386:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
lfs: 'true'
- name: Set up
uses: actions/setup-go@v4
with:
go-version: stable
- name: Test
run: GOARCH=386 go test -v ./...
test-arm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
lfs: 'true'
- name: Set up
uses: actions/setup-go@v4
with:
go-version: stable
- name: Install QEMU
uses: docker/setup-qemu-action@v3
- name: Test
run: GOARCH=arm64 go test -v ./...

22
.github/workflows/cross.sh vendored Executable file
View File

@@ -0,0 +1,22 @@
#!/usr/bin/env bash
echo android ; GOOS=android GOARCH=amd64 go build .
echo darwin ; GOOS=darwin GOARCH=amd64 go build .
echo dragonfly ; GOOS=dragonfly GOARCH=amd64 go build .
echo freebsd ; GOOS=freebsd GOARCH=amd64 go build .
echo illumos ; GOOS=illumos GOARCH=amd64 go build .
echo ios ; GOOS=ios GOARCH=amd64 go build .
echo linux ; GOOS=linux GOARCH=amd64 go build .
echo netbsd ; GOOS=netbsd GOARCH=amd64 go build .
echo openbsd ; GOOS=openbsd GOARCH=amd64 go build .
echo plan9 ; GOOS=plan9 GOARCH=amd64 go build .
echo solaris ; GOOS=solaris GOARCH=amd64 go build .
echo windows ; GOOS=windows GOARCH=amd64 go build .
# echo aix ; GOOS=aix GOARCH=ppc64 go build .
echo js ; GOOS=js GOARCH=wasm go build .
echo wasip1 ; GOOS=wasip1 GOARCH=wasm go build .
echo darwin-flock ; GOOS=darwin GOARCH=amd64 go build -tags sqlite3_flock .
echo darwin-nosys ; GOOS=darwin GOARCH=amd64 go build -tags sqlite3_nosys .
echo linux-nosys ; GOOS=linux GOARCH=amd64 go build -tags sqlite3_nosys .
echo windows-nosys ; GOOS=windows GOARCH=amd64 go build -tags sqlite3_nosys .
echo freebsd-nosys ; GOOS=freebsd GOARCH=amd64 go build -tags sqlite3_nosys .

19
.github/workflows/cross.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Cross compile
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up
uses: actions/setup-go@v4
with:
go-version: stable
- name: Build
run: .github/workflows/cross.sh

View File

@@ -15,7 +15,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
lfs: 'true'
@@ -39,7 +39,6 @@ jobs:
- name: Vet
run: go vet ./...
continue-on-error: true
- name: Build
run: go build -v ./...
@@ -47,16 +46,19 @@ jobs:
- name: Test
run: go test -v ./...
- name: Test no locks
run: go test -v -tags sqlite3_nosys ./tests -run TestDB_nolock
- name: Test BSD locks
run: go test -v -tags sqlite3_bsd ./...
run: go test -v -tags sqlite3_flock ./...
if: matrix.os == 'macos-latest'
- name: Coverage report
uses: ncruces/go-coverage-report@v0
with:
chart: 'true'
amend: 'true'
chart: true
amend: true
reuse-go: true
if: |
matrix.os == 'ubuntu-latest' &&
github.event_name == 'push'
continue-on-error: true
github.event_name == 'push' &&
matrix.os == 'ubuntu-latest'

23
.github/workflows/repro.sh vendored Executable file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ "$OSTYPE" == "linux"* ]]; then
WASI_SDK="https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sdk-20.0-linux.tar.gz"
BINARYEN="https://github.com/WebAssembly/binaryen/releases/download/version_116/binaryen-version_116-x86_64-linux.tar.gz"
elif [[ "$OSTYPE" == "darwin"* ]]; then
WASI_SDK="https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sdk-20.0-macos.tar.gz"
BINARYEN="https://github.com/WebAssembly/binaryen/releases/download/version_116/binaryen-version_116-x86_64-macos.tar.gz"
elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ]]; then
WASI_SDK="https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sdk-20.0.m-mingw.tar.gz"
BINARYEN="https://github.com/WebAssembly/binaryen/releases/download/version_116/binaryen-version_116-x86_64-windows.tar.gz"
fi
# Download tools
mkdir -p tools
[ -d "tools/wasi-sdk"* ] || curl -#L "$WASI_SDK" | tar xzC tools &
[ -d "tools/binaryen-version"* ] || curl -#L "$BINARYEN" | tar xzC tools &
wait
sqlite3/download.sh # Download SQLite
embed/build.sh # Build WASM
git diff --exit-code # Check diffs

24
.github/workflows/repro.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
name: Reproducible build
on:
workflow_dispatch:
jobs:
build:
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
lfs: 'true'
- name: Set up
uses: actions/setup-go@v4
with:
go-version: stable
- name: Build
run: .github/workflows/repro.sh

114
README.md
View File

@@ -7,81 +7,107 @@
Go module `github.com/ncruces/go-sqlite3` wraps a [WASM](https://webassembly.org/) build of [SQLite](https://sqlite.org/),
and uses [wazero](https://wazero.io/) to provide `cgo`-free SQLite bindings.
- Package [`github.com/ncruces/go-sqlite3`](https://pkg.go.dev/github.com/ncruces/go-sqlite3)
wraps the [C SQLite API](https://www.sqlite.org/cintro.html)
([example usage](https://pkg.go.dev/github.com/ncruces/go-sqlite3#example-package)).
- Package [`github.com/ncruces/go-sqlite3/driver`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/driver)
provides a [`database/sql`](https://pkg.go.dev/database/sql) driver
([example usage](https://pkg.go.dev/github.com/ncruces/go-sqlite3/driver#example-package)).
- Package [`github.com/ncruces/go-sqlite3/embed`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/embed)
embeds a build of SQLite into your application.
- Package [`github.com/ncruces/go-sqlite3/vfs`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs)
wraps the [C SQLite VFS API](https://www.sqlite.org/vfs.html) and provides a pure Go implementation.
- Package [`github.com/ncruces/go-sqlite3/gormlite`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/gormlite)
provides a [GORM](https://gorm.io) driver.
- [`github.com/ncruces/go-sqlite3`](https://pkg.go.dev/github.com/ncruces/go-sqlite3)
wraps the [C SQLite API](https://sqlite.org/cintro.html)
([example usage](https://pkg.go.dev/github.com/ncruces/go-sqlite3#example-package)).
- [`github.com/ncruces/go-sqlite3/driver`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/driver)
provides a [`database/sql`](https://pkg.go.dev/database/sql) driver
([example usage](https://pkg.go.dev/github.com/ncruces/go-sqlite3/driver#example-package)).
- [`github.com/ncruces/go-sqlite3/embed`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/embed)
embeds a build of SQLite into your application.
- [`github.com/ncruces/go-sqlite3/vfs`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs)
wraps the [C SQLite VFS API](https://sqlite.org/vfs.html) and provides a pure Go implementation.
- [`github.com/ncruces/go-sqlite3/gormlite`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/gormlite)
provides a [GORM](https://gorm.io) driver.
### Loadable extensions
- [`github.com/ncruces/go-sqlite3/ext/array`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/blob)
provides the [`array`](https://sqlite.org/carray.html) table-valued function.
- [`github.com/ncruces/go-sqlite3/ext/blob`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/blob)
simplifies [incremental BLOB I/O](https://sqlite.org/c3ref/blob_open.html).
- [`github.com/ncruces/go-sqlite3/ext/csv`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/csv)
reads [comma-separated values](https://sqlite.org/csv.html).
- [`github.com/ncruces/go-sqlite3/ext/lines`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/lines)
reads files [line-by-line](https://github.com/asg017/sqlite-lines).
- [`github.com/ncruces/go-sqlite3/ext/pivot`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/pivot)
creates [pivot tables](https://github.com/jakethaw/pivot_vtab).
- [`github.com/ncruces/go-sqlite3/ext/statement`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/statement)
creates [table-valued functions with SQL](https://github.com/0x09/sqlite-statement-vtab).
- [`github.com/ncruces/go-sqlite3/ext/stats`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/stats)
provides [statistics functions](https://www.oreilly.com/library/view/sql-in-a/9780596155322/ch04s02.html).
- [`github.com/ncruces/go-sqlite3/ext/unicode`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/unicode)
provides [Unicode aware](https://sqlite.org/src/dir/ext/icu) functions.
- [`github.com/ncruces/go-sqlite3/vfs/memdb`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/memdb)
implements an in-memory VFS.
- [`github.com/ncruces/go-sqlite3/vfs/readervfs`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/readervfs)
implements a VFS for immutable databases.
### Advanced features
- [x] [incremental BLOB I/O](https://sqlite.org/c3ref/blob_open.html)
- [x] [nested transactions](https://sqlite.org/lang_savepoint.html)
- [x] [custom functions](https://sqlite.org/c3ref/create_function.html)
- [x] [virtual tables](https://sqlite.org/vtab.html)
- [x] [custom VFSes](https://sqlite.org/vfs.html)
- [x] [online backup](https://sqlite.org/backup.html)
- [x] [JSON support](https://sqlite.org/json1.html)
- [x] [Unicode support](https://sqlite.org/src/dir/ext/icu)
### Caveats
This module replaces the SQLite [OS Interface](https://www.sqlite.org/vfs.html)
This module replaces the SQLite [OS Interface](https://sqlite.org/vfs.html)
(aka VFS) with a [pure Go](vfs/) implementation.
This has benefits, but also comes with some drawbacks.
#### Write-Ahead Logging
Because WASM does not support shared memory,
[WAL](https://www.sqlite.org/wal.html) support is [limited](https://www.sqlite.org/wal.html#noshm).
[WAL](https://sqlite.org/wal.html) support is [limited](https://sqlite.org/wal.html#noshm).
To work around this limitation, SQLite is compiled with
[`SQLITE_DEFAULT_LOCKING_MODE=1`](https://www.sqlite.org/compile.html#default_locking_mode),
making `EXCLUSIVE` the default locking mode.
For non-WAL databases, `NORMAL` locking mode can be activated with
[`PRAGMA locking_mode=NORMAL`](https://www.sqlite.org/pragma.html#pragma_locking_mode).
To work around this limitation, SQLite is [patched](sqlite3/locking_mode.patch)
to always use `EXCLUSIVE` locking mode for WAL databases.
Because connection pooling is incompatible with `EXCLUSIVE` locking mode,
the `database/sql` driver defaults to `NORMAL` locking mode.
To open WAL databases, or use `EXCLUSIVE` locking mode,
disable connection pooling by calling
to use the [`database/sql`](https://pkg.go.dev/database/sql) driver
with WAL mode databases you should disable connection pooling by calling
[`db.SetMaxOpenConns(1)`](https://pkg.go.dev/database/sql#DB.SetMaxOpenConns).
#### POSIX Advisory Locks
#### File Locking
POSIX advisory locks, which SQLite uses, are
[broken by design](https://www.sqlite.org/src/artifact/90c4fa?ln=1073-1161).
POSIX advisory locks, which SQLite uses on Unix, are
[broken by design](https://sqlite.org/src/artifact/2e8b12?ln=1073-1161).
On Linux, macOS and illumos, this module uses
[OFD locks](https://www.gnu.org/software/libc/manual/html_node/Open-File-Description-Locks.html)
to synchronize access to database files.
OFD locks are fully compatible with process-associated POSIX advisory locks.
OFD locks are fully compatible with POSIX advisory locks.
On BSD Unixes, this module uses
[BSD locks](https://man.freebsd.org/cgi/man.cgi?query=flock&sektion=2).
BSD locks may _not_ be compatible with process-associated POSIX advisory locks.
On BSD Unixes, BSD locks are fully compatible with POSIX advisory locks.
On Windows, this module uses `LockFile`, `LockFileEx`, and `UnlockFile`,
like SQLite.
On all other platforms, file locking is not supported, and you must use
[`nolock=1`](https://sqlite.org/uri.html#urinolock)
to open database files.
To use the [`database/sql`](https://pkg.go.dev/database/sql) driver
with `nolock=1` you must disable connection pooling by calling
[`db.SetMaxOpenConns(1)`](https://pkg.go.dev/database/sql#DB.SetMaxOpenConns).
#### Testing
The pure Go VFS is tested by running an unmodified build of SQLite's
The pure Go VFS is tested by running SQLite's
[mptest](https://github.com/sqlite/sqlite/blob/master/mptest/mptest.c)
on Linux, macOS and Windows.
on Linux, macOS, Windows and FreeBSD.
Performance is tested by running
[speedtest1](https://github.com/sqlite/sqlite/blob/master/test/speedtest1.c).
### Roadmap
- [ ] advanced SQLite features
- [x] nested transactions
- [x] incremental BLOB I/O
- [x] online backup
- [ ] session extension
- [ ] custom VFSes
- [x] custom VFS API
- [x] in-memory VFS
- [x] read-only VFS, wrapping an [`io.ReaderAt`](https://pkg.go.dev/io#ReaderAt)
- [ ] cloud-based VFS, based on [Cloud Backed SQLite](https://sqlite.org/cloudsqlite/doc/trunk/www/index.wiki)
- [ ] custom SQL functions
### Alternatives
- [`modernc.org/sqlite`](https://pkg.go.dev/modernc.org/sqlite)
- [`crawshaw.io/sqlite`](https://pkg.go.dev/crawshaw.io/sqlite)
- [`github.com/mattn/go-sqlite3`](https://pkg.go.dev/github.com/mattn/go-sqlite3)
- [`github.com/zombiezen/go-sqlite`](https://pkg.go.dev/github.com/zombiezen/go-sqlite)
- [`github.com/zombiezen/go-sqlite`](https://pkg.go.dev/github.com/zombiezen/go-sqlite)

View File

@@ -2,7 +2,7 @@ package sqlite3
// Backup is an handle to an ongoing online backup operation.
//
// https://www.sqlite.org/c3ref/backup.html
// https://sqlite.org/c3ref/backup.html
type Backup struct {
c *Conn
handle uint32
@@ -15,7 +15,7 @@ type Backup struct {
// and blocks until the entire backup is complete.
// Use [Conn.BackupInit] for incremental backup.
//
// https://www.sqlite.org/backup.html
// https://sqlite.org/backup.html
func (src *Conn) Backup(srcDB, dstURI string) error {
b, err := src.BackupInit(srcDB, dstURI)
if err != nil {
@@ -31,7 +31,7 @@ func (src *Conn) Backup(srcDB, dstURI string) error {
// Restore opens the SQLite database file srcURI,
// and blocks until the entire restore is complete.
//
// https://www.sqlite.org/backup.html
// https://sqlite.org/backup.html
func (dst *Conn) Restore(dstDB, srcURI string) error {
src, err := dst.openDB(srcURI, OPEN_READONLY|OPEN_URI)
if err != nil {
@@ -52,7 +52,7 @@ func (dst *Conn) Restore(dstDB, srcURI string) error {
// then initializes a backup that copies the contents of srcDB on the src connection
// to the "main" database in dstURI.
//
// https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupinit
// https://sqlite.org/c3ref/backup_finish.html#sqlite3backupinit
func (src *Conn) BackupInit(srcDB, dstURI string) (*Backup, error) {
dst, err := src.openDB(dstURI, OPEN_READWRITE|OPEN_CREATE|OPEN_URI)
if err != nil {
@@ -62,7 +62,7 @@ func (src *Conn) BackupInit(srcDB, dstURI string) (*Backup, error) {
}
func (c *Conn) backupInit(dst uint32, dstName string, src uint32, srcName string) (*Backup, error) {
defer c.arena.reset()
defer c.arena.mark()()
dstPtr := c.arena.string(dstName)
srcPtr := c.arena.string(srcName)
@@ -71,13 +71,13 @@ func (c *Conn) backupInit(dst uint32, dstName string, src uint32, srcName string
other = src
}
r := c.call(c.api.backupInit,
r := c.call("sqlite3_backup_init",
uint64(dst), uint64(dstPtr),
uint64(src), uint64(srcPtr))
if r == 0 {
defer c.closeDB(other)
r = c.call(c.api.errcode, uint64(dst))
return nil, c.module.error(r, dst)
r = c.call("sqlite3_errcode", uint64(dst))
return nil, c.sqlite.error(r, dst)
}
return &Backup{
@@ -91,13 +91,13 @@ func (c *Conn) backupInit(dst uint32, dstName string, src uint32, srcName string
//
// It is safe to close a nil, zero or closed Backup.
//
// https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupfinish
// https://sqlite.org/c3ref/backup_finish.html#sqlite3backupfinish
func (b *Backup) Close() error {
if b == nil || b.handle == 0 {
return nil
}
r := b.c.call(b.c.api.backupFinish, uint64(b.handle))
r := b.c.call("sqlite3_backup_finish", uint64(b.handle))
b.c.closeDB(b.otherc)
b.handle = 0
return b.c.error(r)
@@ -106,9 +106,9 @@ func (b *Backup) Close() error {
// Step copies up to nPage pages between the source and destination databases.
// If nPage is negative, all remaining source pages are copied.
//
// https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupstep
// https://sqlite.org/c3ref/backup_finish.html#sqlite3backupstep
func (b *Backup) Step(nPage int) (done bool, err error) {
r := b.c.call(b.c.api.backupStep, uint64(b.handle), uint64(nPage))
r := b.c.call("sqlite3_backup_step", uint64(b.handle), uint64(nPage))
if r == _DONE {
return true, nil
}
@@ -118,17 +118,17 @@ func (b *Backup) Step(nPage int) (done bool, err error) {
// Remaining returns the number of pages still to be backed up
// at the conclusion of the most recent [Backup.Step].
//
// https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupremaining
// https://sqlite.org/c3ref/backup_finish.html#sqlite3backupremaining
func (b *Backup) Remaining() int {
r := b.c.call(b.c.api.backupRemaining, uint64(b.handle))
r := b.c.call("sqlite3_backup_remaining", uint64(b.handle))
return int(r)
}
// PageCount returns the total number of pages in the source database
// at the conclusion of the most recent [Backup.Step].
//
// https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backuppagecount
// https://sqlite.org/c3ref/backup_finish.html#sqlite3backuppagecount
func (b *Backup) PageCount() int {
r := b.c.call(b.c.api.backupPageCount, uint64(b.handle))
r := b.c.call("sqlite3_backup_pagecount", uint64(b.handle))
return int(r)
}

57
blob.go
View File

@@ -15,7 +15,7 @@ type ZeroBlob int64
//
// It implements [io.ReadWriteSeeker] for incremental BLOB I/O.
//
// https://www.sqlite.org/c3ref/blob.html
// https://sqlite.org/c3ref/blob.html
type Blob struct {
c *Conn
bytes int64
@@ -27,10 +27,10 @@ var _ io.ReadWriteSeeker = &Blob{}
// OpenBlob opens a BLOB for incremental I/O.
//
// https://www.sqlite.org/c3ref/blob_open.html
// https://sqlite.org/c3ref/blob_open.html
func (c *Conn) OpenBlob(db, table, column string, row int64, write bool) (*Blob, error) {
c.checkInterrupt()
defer c.arena.reset()
defer c.arena.mark()()
blobPtr := c.arena.new(ptrlen)
dbPtr := c.arena.string(db)
tablePtr := c.arena.string(table)
@@ -41,7 +41,7 @@ func (c *Conn) OpenBlob(db, table, column string, row int64, write bool) (*Blob,
flags = 1
}
r := c.call(c.api.blobOpen, uint64(c.handle),
r := c.call("sqlite3_blob_open", uint64(c.handle),
uint64(dbPtr), uint64(tablePtr), uint64(columnPtr),
uint64(row), flags, uint64(blobPtr))
@@ -51,7 +51,7 @@ func (c *Conn) OpenBlob(db, table, column string, row int64, write bool) (*Blob,
blob := Blob{c: c}
blob.handle = util.ReadUint32(c.mod, blobPtr)
blob.bytes = int64(c.call(c.api.blobBytes, uint64(blob.handle)))
blob.bytes = int64(c.call("sqlite3_blob_bytes", uint64(blob.handle)))
return &blob, nil
}
@@ -59,13 +59,13 @@ func (c *Conn) OpenBlob(db, table, column string, row int64, write bool) (*Blob,
//
// It is safe to close a nil, zero or closed Blob.
//
// https://www.sqlite.org/c3ref/blob_close.html
// https://sqlite.org/c3ref/blob_close.html
func (b *Blob) Close() error {
if b == nil || b.handle == 0 {
return nil
}
r := b.c.call(b.c.api.blobClose, uint64(b.handle))
r := b.c.call("sqlite3_blob_close", uint64(b.handle))
b.handle = 0
return b.c.error(r)
@@ -73,14 +73,14 @@ func (b *Blob) Close() error {
// Size returns the size of the BLOB in bytes.
//
// https://www.sqlite.org/c3ref/blob_bytes.html
// https://sqlite.org/c3ref/blob_bytes.html
func (b *Blob) Size() int64 {
return b.bytes
}
// Read implements the [io.Reader] interface.
//
// https://www.sqlite.org/c3ref/blob_read.html
// https://sqlite.org/c3ref/blob_read.html
func (b *Blob) Read(p []byte) (n int, err error) {
if b.offset >= b.bytes {
return 0, io.EOF
@@ -92,10 +92,10 @@ func (b *Blob) Read(p []byte) (n int, err error) {
want = avail
}
defer b.c.arena.reset()
defer b.c.arena.mark()()
ptr := b.c.arena.new(uint64(want))
r := b.c.call(b.c.api.blobRead, uint64(b.handle),
r := b.c.call("sqlite3_blob_read", uint64(b.handle),
uint64(ptr), uint64(want), uint64(b.offset))
err = b.c.error(r)
if err != nil {
@@ -112,23 +112,23 @@ func (b *Blob) Read(p []byte) (n int, err error) {
// WriteTo implements the [io.WriterTo] interface.
//
// https://www.sqlite.org/c3ref/blob_read.html
// https://sqlite.org/c3ref/blob_read.html
func (b *Blob) WriteTo(w io.Writer) (n int64, err error) {
if b.offset >= b.bytes {
return 0, nil
}
want := int64(1024 * 1024)
avail := b.bytes - b.offset
want := int64(65536)
if want > avail {
want = avail
}
ptr := b.c.new(uint64(want))
defer b.c.free(ptr)
defer b.c.arena.mark()()
ptr := b.c.arena.new(uint64(want))
for want > 0 {
r := b.c.call(b.c.api.blobRead, uint64(b.handle),
r := b.c.call("sqlite3_blob_read", uint64(b.handle),
uint64(ptr), uint64(want), uint64(b.offset))
err = b.c.error(r)
if err != nil {
@@ -156,12 +156,12 @@ func (b *Blob) WriteTo(w io.Writer) (n int64, err error) {
// Write implements the [io.Writer] interface.
//
// https://www.sqlite.org/c3ref/blob_write.html
// https://sqlite.org/c3ref/blob_write.html
func (b *Blob) Write(p []byte) (n int, err error) {
defer b.c.arena.reset()
defer b.c.arena.mark()()
ptr := b.c.arena.bytes(p)
r := b.c.call(b.c.api.blobWrite, uint64(b.handle),
r := b.c.call("sqlite3_blob_write", uint64(b.handle),
uint64(ptr), uint64(len(p)), uint64(b.offset))
err = b.c.error(r)
if err != nil {
@@ -173,10 +173,13 @@ func (b *Blob) Write(p []byte) (n int, err error) {
// ReadFrom implements the [io.ReaderFrom] interface.
//
// https://www.sqlite.org/c3ref/blob_write.html
// https://sqlite.org/c3ref/blob_write.html
func (b *Blob) ReadFrom(r io.Reader) (n int64, err error) {
want := int64(1024 * 1024)
avail := b.bytes - b.offset
want := int64(65536)
if l, ok := r.(*io.LimitedReader); ok && want > l.N {
want = l.N
}
if want > avail {
want = avail
}
@@ -184,14 +187,14 @@ func (b *Blob) ReadFrom(r io.Reader) (n int64, err error) {
want = 1
}
ptr := b.c.new(uint64(want))
defer b.c.free(ptr)
defer b.c.arena.mark()()
ptr := b.c.arena.new(uint64(want))
for {
mem := util.View(b.c.mod, ptr, uint64(want))
m, err := r.Read(mem[:want])
if m > 0 {
r := b.c.call(b.c.api.blobWrite, uint64(b.handle),
r := b.c.call("sqlite3_blob_write", uint64(b.handle),
uint64(ptr), uint64(m), uint64(b.offset))
err := b.c.error(r)
if err != nil {
@@ -238,10 +241,10 @@ func (b *Blob) Seek(offset int64, whence int) (int64, error) {
// Reopen moves a BLOB handle to a new row of the same database table.
//
// https://www.sqlite.org/c3ref/blob_reopen.html
// https://sqlite.org/c3ref/blob_reopen.html
func (b *Blob) Reopen(row int64) error {
err := b.c.error(b.c.call(b.c.api.blobReopen, uint64(b.handle), uint64(row)))
b.bytes = int64(b.c.call(b.c.api.blobBytes, uint64(b.handle)))
err := b.c.error(b.c.call("sqlite3_blob_reopen", uint64(b.handle), uint64(row)))
b.bytes = int64(b.c.call("sqlite3_blob_bytes", uint64(b.handle)))
b.offset = 0
return err
}

180
conn.go
View File

@@ -2,27 +2,23 @@ package sqlite3
import (
"context"
"database/sql/driver"
"errors"
"fmt"
"net/url"
"runtime"
"strings"
"sync/atomic"
"unsafe"
"github.com/ncruces/go-sqlite3/internal/util"
"github.com/tetratelabs/wazero/api"
)
// Conn is a database connection handle.
// A Conn is not safe for concurrent use by multiple goroutines.
//
// https://www.sqlite.org/c3ref/sqlite3.html
// https://sqlite.org/c3ref/sqlite3.html
type Conn struct {
*module
*sqlite
interrupt context.Context
waiter chan struct{}
pending *Stmt
arena arena
@@ -39,9 +35,9 @@ func Open(filename string) (*Conn, error) {
// If none of the required flags is used, a combination of [OPEN_READWRITE] and [OPEN_CREATE] is used.
// If a URI filename is used, PRAGMA statements to execute can be specified using "_pragma":
//
// sqlite3.Open("file:demo.db?_pragma=busy_timeout(10000)&_pragma=locking_mode(normal)")
// sqlite3.Open("file:demo.db?_pragma=busy_timeout(10000)")
//
// https://www.sqlite.org/c3ref/open.html
// https://sqlite.org/c3ref/open.html
func OpenFlags(filename string, flags OpenFlag) (*Conn, error) {
if flags&(OPEN_READONLY|OPEN_READWRITE|OPEN_CREATE) == 0 {
flags |= OPEN_READWRITE | OPEN_CREATE
@@ -49,21 +45,22 @@ func OpenFlags(filename string, flags OpenFlag) (*Conn, error) {
return newConn(filename, flags)
}
type connKey struct{}
func newConn(filename string, flags OpenFlag) (conn *Conn, err error) {
mod, err := instantiateModule()
sqlite, err := instantiateSQLite()
if err != nil {
return nil, err
}
defer func() {
if conn == nil {
mod.close()
} else {
runtime.SetFinalizer(conn, util.Finalizer[Conn](3))
sqlite.close()
}
}()
c := &Conn{module: mod}
c := &Conn{sqlite: sqlite}
c.arena = c.newArena(1024)
c.ctx = context.WithValue(c.ctx, connKey{}, c)
c.handle, err = c.openDB(filename, flags)
if err != nil {
return nil, err
@@ -72,15 +69,15 @@ func newConn(filename string, flags OpenFlag) (conn *Conn, err error) {
}
func (c *Conn) openDB(filename string, flags OpenFlag) (uint32, error) {
defer c.arena.reset()
defer c.arena.mark()()
connPtr := c.arena.new(ptrlen)
namePtr := c.arena.string(filename)
flags |= OPEN_EXRESCODE
r := c.call(c.api.open, uint64(namePtr), uint64(connPtr), uint64(flags), 0)
r := c.call("sqlite3_open_v2", uint64(namePtr), uint64(connPtr), uint64(flags), 0)
handle := util.ReadUint32(c.mod, connPtr)
if err := c.module.error(r, handle); err != nil {
if err := c.sqlite.error(r, handle); err != nil {
c.closeDB(handle)
return 0, err
}
@@ -92,14 +89,13 @@ func (c *Conn) openDB(filename string, flags OpenFlag) (uint32, error) {
for _, p := range query["_pragma"] {
pragmas.WriteString(`PRAGMA `)
pragmas.WriteString(p)
pragmas.WriteByte(';')
pragmas.WriteString(`;`)
}
}
c.arena.reset()
pragmaPtr := c.arena.string(pragmas.String())
r := c.call(c.api.exec, uint64(handle), uint64(pragmaPtr), 0, 0, 0)
if err := c.module.error(r, handle, pragmas.String()); err != nil {
r := c.call("sqlite3_exec", uint64(handle), uint64(pragmaPtr), 0, 0, 0)
if err := c.sqlite.error(r, handle, pragmas.String()); err != nil {
if errors.Is(err, ERROR) {
err = fmt.Errorf("sqlite3: invalid _pragma: %w", err)
}
@@ -112,8 +108,8 @@ func (c *Conn) openDB(filename string, flags OpenFlag) (uint32, error) {
}
func (c *Conn) closeDB(handle uint32) {
r := c.call(c.api.closeZombie, uint64(handle))
if err := c.module.error(r, handle); err != nil {
r := c.call("sqlite3_close_v2", uint64(handle))
if err := c.sqlite.error(r, handle); err != nil {
panic(err)
}
}
@@ -126,37 +122,35 @@ func (c *Conn) closeDB(handle uint32) {
//
// It is safe to close a nil, zero or closed Conn.
//
// https://www.sqlite.org/c3ref/close.html
// https://sqlite.org/c3ref/close.html
func (c *Conn) Close() error {
if c == nil || c.handle == 0 {
return nil
}
c.SetInterrupt(context.Background())
c.pending.Close()
c.pending = nil
r := c.call(c.api.close, uint64(c.handle))
r := c.call("sqlite3_close", uint64(c.handle))
if err := c.error(r); err != nil {
return err
}
c.handle = 0
runtime.SetFinalizer(c, nil)
return c.module.close()
return c.close()
}
// Exec is a convenience function that allows an application to run
// multiple statements of SQL without having to use a lot of code.
//
// https://www.sqlite.org/c3ref/exec.html
// https://sqlite.org/c3ref/exec.html
func (c *Conn) Exec(sql string) error {
c.checkInterrupt()
defer c.arena.reset()
defer c.arena.mark()()
sqlPtr := c.arena.string(sql)
r := c.call(c.api.exec, uint64(c.handle), uint64(sqlPtr), 0, 0, 0)
return c.error(r)
r := c.call("sqlite3_exec", uint64(c.handle), uint64(sqlPtr), 0, 0, 0)
return c.error(r, sql)
}
// Prepare calls [Conn.PrepareFlags] with no flags.
@@ -169,25 +163,26 @@ func (c *Conn) Prepare(sql string) (stmt *Stmt, tail string, err error) {
// If the input text contains no SQL (if the input is an empty string or a comment),
// both stmt and err will be nil.
//
// https://www.sqlite.org/c3ref/prepare.html
// https://sqlite.org/c3ref/prepare.html
func (c *Conn) PrepareFlags(sql string, flags PrepareFlag) (stmt *Stmt, tail string, err error) {
if emptyStatement(sql) {
return nil, "", nil
if len(sql) > _MAX_LENGTH {
return nil, "", TOOBIG
}
defer c.arena.reset()
defer c.arena.mark()()
stmtPtr := c.arena.new(ptrlen)
tailPtr := c.arena.new(ptrlen)
sqlPtr := c.arena.string(sql)
r := c.call(c.api.prepare, uint64(c.handle),
r := c.call("sqlite3_prepare_v3", uint64(c.handle),
uint64(sqlPtr), uint64(len(sql)+1), uint64(flags),
uint64(stmtPtr), uint64(tailPtr))
stmt = &Stmt{c: c}
stmt.handle = util.ReadUint32(c.mod, stmtPtr)
i := util.ReadUint32(c.mod, tailPtr)
tail = sql[i-sqlPtr:]
if sql := sql[util.ReadUint32(c.mod, tailPtr)-sqlPtr:]; sql != "" {
tail = sql
}
if err := c.error(r, sql); err != nil {
return nil, "", err
@@ -195,23 +190,23 @@ func (c *Conn) PrepareFlags(sql string, flags PrepareFlag) (stmt *Stmt, tail str
if stmt.handle == 0 {
return nil, "", nil
}
return
return stmt, tail, nil
}
// GetAutocommit tests the connection for auto-commit mode.
//
// https://www.sqlite.org/c3ref/get_autocommit.html
// https://sqlite.org/c3ref/get_autocommit.html
func (c *Conn) GetAutocommit() bool {
r := c.call(c.api.autocommit, uint64(c.handle))
r := c.call("sqlite3_get_autocommit", uint64(c.handle))
return r != 0
}
// LastInsertRowID returns the rowid of the most recent successful INSERT
// on the database connection.
//
// https://www.sqlite.org/c3ref/last_insert_rowid.html
// https://sqlite.org/c3ref/last_insert_rowid.html
func (c *Conn) LastInsertRowID() int64 {
r := c.call(c.api.lastRowid, uint64(c.handle))
r := c.call("sqlite3_last_insert_rowid", uint64(c.handle))
return int64(r)
}
@@ -219,9 +214,9 @@ func (c *Conn) LastInsertRowID() int64 {
// by the most recently completed INSERT, UPDATE or DELETE statement
// on the database connection.
//
// https://www.sqlite.org/c3ref/changes.html
// https://sqlite.org/c3ref/changes.html
func (c *Conn) Changes() int64 {
r := c.call(c.api.changes, uint64(c.handle))
r := c.call("sqlite3_changes64", uint64(c.handle))
return int64(r)
}
@@ -238,72 +233,52 @@ func (c *Conn) Changes() int64 {
//
// SetInterrupt returns the old context assigned to the connection.
//
// https://www.sqlite.org/c3ref/interrupt.html
// https://sqlite.org/c3ref/interrupt.html
func (c *Conn) SetInterrupt(ctx context.Context) (old context.Context) {
// Is a waiter running?
if c.waiter != nil {
c.waiter <- struct{}{} // Cancel the waiter.
<-c.waiter // Wait for it to finish.
c.waiter = nil
// Is it the same context?
if ctx == c.interrupt {
return ctx
}
// Reset the pending statement.
if c.pending != nil {
// An uncompleted SQL statement prevents SQLite from ignoring
// an interrupt that comes before any other statements are started.
if c.pending == nil {
c.pending, _, _ = c.Prepare(`SELECT 1 UNION ALL SELECT 2`)
} else {
c.pending.Reset()
}
old = c.interrupt
c.interrupt = ctx
// Remove the handler if the context can't be canceled.
if ctx == nil || ctx.Done() == nil {
c.call("sqlite3_progress_handler_go", uint64(c.handle), 0)
return old
}
// Creating an uncompleted SQL statement prevents SQLite from ignoring
// an interrupt that comes before any other statements are started.
if c.pending == nil {
c.pending, _, _ = c.Prepare(`SELECT 1 UNION ALL SELECT 2`)
}
c.pending.Step()
// Don't create the goroutine if we're already interrupted.
// This happens frequently while restoring to a previously interrupted state.
if c.checkInterrupt() {
return old
}
waiter := make(chan struct{})
c.waiter = waiter
go func() {
select {
case <-waiter: // Waiter was cancelled.
break
case <-ctx.Done(): // Done was closed.
const isInterruptedOffset = 280
buf := util.View(c.mod, c.handle+isInterruptedOffset, 4)
(*atomic.Uint32)(unsafe.Pointer(&buf[0])).Store(1)
// Wait for the next call to SetInterrupt.
<-waiter
}
// Signal that the waiter has finished.
waiter <- struct{}{}
}()
c.call("sqlite3_progress_handler_go", uint64(c.handle), 100)
return old
}
func (c *Conn) checkInterrupt() bool {
if c.interrupt == nil || c.interrupt.Err() == nil {
return false
func progressCallback(ctx context.Context, mod api.Module, _ uint32) uint32 {
if c, ok := ctx.Value(connKey{}).(*Conn); ok {
if c.interrupt != nil && c.interrupt.Err() != nil {
return 1
}
}
return 0
}
func (c *Conn) checkInterrupt() {
if c.interrupt != nil && c.interrupt.Err() != nil {
c.call("sqlite3_interrupt", uint64(c.handle))
}
const isInterruptedOffset = 280
buf := util.View(c.mod, c.handle+isInterruptedOffset, 4)
(*atomic.Uint32)(unsafe.Pointer(&buf[0])).Store(1)
return true
}
// Pragma executes a PRAGMA statement and returns any results.
//
// https://www.sqlite.org/pragma.html
// https://sqlite.org/pragma.html
func (c *Conn) Pragma(str string) ([]string, error) {
stmt, _, err := c.Prepare(`PRAGMA ` + str)
if err != nil {
@@ -319,27 +294,14 @@ func (c *Conn) Pragma(str string) ([]string, error) {
}
func (c *Conn) error(rc uint64, sql ...string) error {
return c.module.error(rc, c.handle, sql...)
return c.sqlite.error(rc, c.handle, sql...)
}
// DriverConn is implemented by the SQLite [database/sql] driver connection.
//
// It can be used to access advanced SQLite features like
// [savepoints], [online backup] and [incremental BLOB I/O].
// It can be used to access SQLite features like [online backup].
//
// [savepoints]: https://www.sqlite.org/lang_savepoint.html
// [online backup]: https://www.sqlite.org/backup.html
// [incremental BLOB I/O]: https://www.sqlite.org/c3ref/blob_open.html
// [online backup]: https://sqlite.org/backup.html
type DriverConn interface {
driver.Conn
driver.ConnBeginTx
driver.ExecerContext
driver.ConnPrepareContext
SetInterrupt(ctx context.Context) (old context.Context)
Savepoint() Savepoint
Backup(srcDB, dstURI string) error
Restore(dstDB, srcURI string) error
OpenBlob(db, table, column string, row int64, write bool) (*Blob, error)
Raw() *Conn
}

View File

@@ -9,8 +9,9 @@ const (
_UTF8 = 1
_MAX_STRING = 512 // Used for short strings: names, error messages…
_MAX_NAME = 512 // Used for short strings: names, error messages…
_MAX_LENGTH = 1e9
_MAX_SQL_LENGTH = 1e9
_MAX_ALLOCATION_SIZE = 0x7ffffeff
ptrlen = 4
@@ -18,7 +19,7 @@ const (
// ErrorCode is a result code that [Error.Code] might return.
//
// https://www.sqlite.org/rescode.html
// https://sqlite.org/rescode.html
type ErrorCode uint8
const (
@@ -54,7 +55,7 @@ const (
// ExtendedErrorCode is a result code that [Error.ExtendedCode] might return.
//
// https://www.sqlite.org/rescode.html
// https://sqlite.org/rescode.html
type (
ExtendedErrorCode uint16
xErrorCode = ExtendedErrorCode
@@ -97,6 +98,7 @@ const (
IOERR_ROLLBACK_ATOMIC ExtendedErrorCode = xErrorCode(IOERR) | (31 << 8)
IOERR_DATA ExtendedErrorCode = xErrorCode(IOERR) | (32 << 8)
IOERR_CORRUPTFS ExtendedErrorCode = xErrorCode(IOERR) | (33 << 8)
IOERR_IN_PAGE ExtendedErrorCode = xErrorCode(IOERR) | (34 << 8)
LOCKED_SHAREDCACHE ExtendedErrorCode = xErrorCode(LOCKED) | (1 << 8)
LOCKED_VTAB ExtendedErrorCode = xErrorCode(LOCKED) | (2 << 8)
BUSY_RECOVERY ExtendedErrorCode = xErrorCode(BUSY) | (1 << 8)
@@ -139,7 +141,7 @@ const (
// OpenFlag is a flag for the [OpenFlags] function.
//
// https://www.sqlite.org/c3ref/c_open_autoproxy.html
// https://sqlite.org/c3ref/c_open_autoproxy.html
type OpenFlag uint32
const (
@@ -158,7 +160,7 @@ const (
// PrepareFlag is a flag that can be passed to [Conn.PrepareFlags].
//
// https://www.sqlite.org/c3ref/c_prepare_normalize.html
// https://sqlite.org/c3ref/c_prepare_normalize.html
type PrepareFlag uint32
const (
@@ -167,9 +169,39 @@ const (
PREPARE_NO_VTAB PrepareFlag = 0x04
)
// FunctionFlag is a flag that can be passed to
// [Conn.CreateFunction] and [Conn.CreateWindowFunction].
//
// https://sqlite.org/c3ref/c_deterministic.html
type FunctionFlag uint32
const (
DETERMINISTIC FunctionFlag = 0x000000800
DIRECTONLY FunctionFlag = 0x000080000
SUBTYPE FunctionFlag = 0x000100000
INNOCUOUS FunctionFlag = 0x000200000
)
// StmtStatus name counter values associated with the [Stmt.Status] method.
//
// https://sqlite.org/c3ref/c_stmtstatus_counter.html
type StmtStatus uint32
const (
STMTSTATUS_FULLSCAN_STEP StmtStatus = 1
STMTSTATUS_SORT StmtStatus = 2
STMTSTATUS_AUTOINDEX StmtStatus = 3
STMTSTATUS_VM_STEP StmtStatus = 4
STMTSTATUS_REPREPARE StmtStatus = 5
STMTSTATUS_RUN StmtStatus = 6
STMTSTATUS_FILTER_MISS StmtStatus = 7
STMTSTATUS_FILTER_HIT StmtStatus = 8
STMTSTATUS_MEMUSED StmtStatus = 99
)
// Datatype is a fundamental datatype of SQLite.
//
// https://www.sqlite.org/c3ref/c_blob.html
// https://sqlite.org/c3ref/c_blob.html
type Datatype uint32
const (
@@ -182,18 +214,18 @@ const (
// String implements the [fmt.Stringer] interface.
func (t Datatype) String() string {
const name = "INTEGERFLOATTEXTBLOBNULL"
const name = "INTEGERFLOATEXTBLOBNULL"
switch t {
case INTEGER:
return name[0:7]
case FLOAT:
return name[7:12]
case TEXT:
return name[12:16]
return name[11:15]
case BLOB:
return name[16:20]
return name[15:19]
case NULL:
return name[20:24]
return name[19:23]
}
return strconv.FormatUint(uint64(t), 10)
}

220
context.go Normal file
View File

@@ -0,0 +1,220 @@
package sqlite3
import (
"encoding/json"
"errors"
"math"
"time"
"github.com/ncruces/go-sqlite3/internal/util"
)
// Context is the context in which an SQL function executes.
// An SQLite [Context] is in no way related to a Go [context.Context].
//
// https://sqlite.org/c3ref/context.html
type Context struct {
c *Conn
handle uint32
}
// Conn returns the database connection of the
// [Conn.CreateFunction] or [Conn.CreateWindowFunction]
// routines that originally registered the application defined function.
//
// https://sqlite.org/c3ref/context_db_handle.html
func (ctx Context) Conn() *Conn {
return ctx.c
}
// SetAuxData saves metadata for argument n of the function.
//
// https://sqlite.org/c3ref/get_auxdata.html
func (ctx Context) SetAuxData(n int, data any) {
ptr := util.AddHandle(ctx.c.ctx, data)
ctx.c.call("sqlite3_set_auxdata_go", uint64(ctx.handle), uint64(n), uint64(ptr))
}
// GetAuxData returns metadata for argument n of the function.
//
// https://sqlite.org/c3ref/get_auxdata.html
func (ctx Context) GetAuxData(n int) any {
ptr := uint32(ctx.c.call("sqlite3_get_auxdata", uint64(ctx.handle), uint64(n)))
return util.GetHandle(ctx.c.ctx, ptr)
}
// ResultBool sets the result of the function to a bool.
// SQLite does not have a separate boolean storage class.
// Instead, boolean values are stored as integers 0 (false) and 1 (true).
//
// https://sqlite.org/c3ref/result_blob.html
func (ctx Context) ResultBool(value bool) {
var i int64
if value {
i = 1
}
ctx.ResultInt64(i)
}
// ResultInt sets the result of the function to an int.
//
// https://sqlite.org/c3ref/result_blob.html
func (ctx Context) ResultInt(value int) {
ctx.ResultInt64(int64(value))
}
// ResultInt64 sets the result of the function to an int64.
//
// https://sqlite.org/c3ref/result_blob.html
func (ctx Context) ResultInt64(value int64) {
ctx.c.call("sqlite3_result_int64",
uint64(ctx.handle), uint64(value))
}
// ResultFloat sets the result of the function to a float64.
//
// https://sqlite.org/c3ref/result_blob.html
func (ctx Context) ResultFloat(value float64) {
ctx.c.call("sqlite3_result_double",
uint64(ctx.handle), math.Float64bits(value))
}
// ResultText sets the result of the function to a string.
//
// https://sqlite.org/c3ref/result_blob.html
func (ctx Context) ResultText(value string) {
ptr := ctx.c.newString(value)
ctx.c.call("sqlite3_result_text64",
uint64(ctx.handle), uint64(ptr), uint64(len(value)),
uint64(ctx.c.freer), _UTF8)
}
// ResultRawText sets the text result of the function to a []byte.
//
// https://sqlite.org/c3ref/result_blob.html
func (ctx Context) ResultRawText(value []byte) {
ptr := ctx.c.newBytes(value)
ctx.c.call("sqlite3_result_text64",
uint64(ctx.handle), uint64(ptr), uint64(len(value)),
uint64(ctx.c.freer), _UTF8)
}
// ResultBlob sets the result of the function to a []byte.
// Returning a nil slice is the same as calling [Context.ResultNull].
//
// https://sqlite.org/c3ref/result_blob.html
func (ctx Context) ResultBlob(value []byte) {
ptr := ctx.c.newBytes(value)
ctx.c.call("sqlite3_result_blob64",
uint64(ctx.handle), uint64(ptr), uint64(len(value)),
uint64(ctx.c.freer))
}
// ResultZeroBlob sets the result of the function to a zero-filled, length n BLOB.
//
// https://sqlite.org/c3ref/result_blob.html
func (ctx Context) ResultZeroBlob(n int64) {
ctx.c.call("sqlite3_result_zeroblob64",
uint64(ctx.handle), uint64(n))
}
// ResultNull sets the result of the function to NULL.
//
// https://sqlite.org/c3ref/result_blob.html
func (ctx Context) ResultNull() {
ctx.c.call("sqlite3_result_null",
uint64(ctx.handle))
}
// ResultTime sets the result of the function to a [time.Time].
//
// https://sqlite.org/c3ref/result_blob.html
func (ctx Context) ResultTime(value time.Time, format TimeFormat) {
if format == TimeFormatDefault {
ctx.resultRFC3339Nano(value)
return
}
switch v := format.Encode(value).(type) {
case string:
ctx.ResultText(v)
case int64:
ctx.ResultInt64(v)
case float64:
ctx.ResultFloat(v)
default:
panic(util.AssertErr())
}
}
func (ctx Context) resultRFC3339Nano(value time.Time) {
const maxlen = uint64(len(time.RFC3339Nano)) + 5
ptr := ctx.c.new(maxlen)
buf := util.View(ctx.c.mod, ptr, maxlen)
buf = value.AppendFormat(buf[:0], time.RFC3339Nano)
ctx.c.call("sqlite3_result_text64",
uint64(ctx.handle), uint64(ptr), uint64(len(buf)),
uint64(ctx.c.freer), _UTF8)
}
// ResultPointer sets the result of the function to NULL, just like [Context.ResultNull],
// except that it also associates ptr with that NULL value such that it can be retrieved
// within an application-defined SQL function using [Value.Pointer].
//
// https://sqlite.org/c3ref/result_blob.html
func (ctx Context) ResultPointer(ptr any) {
valPtr := util.AddHandle(ctx.c.ctx, ptr)
ctx.c.call("sqlite3_result_pointer_go", uint64(valPtr))
}
// ResultJSON sets the result of the function to the JSON encoding of value.
//
// https://sqlite.org/c3ref/result_blob.html
func (ctx Context) ResultJSON(value any) {
data, err := json.Marshal(value)
if err != nil {
ctx.ResultError(err)
return
}
ctx.ResultRawText(data)
}
// ResultValue sets the result of the function to a copy of [Value].
//
// https://sqlite.org/c3ref/result_blob.html
func (ctx Context) ResultValue(value Value) {
if value.sqlite != ctx.c.sqlite {
ctx.ResultError(MISUSE)
return
}
ctx.c.call("sqlite3_result_value",
uint64(ctx.handle), uint64(value.handle))
}
// ResultError sets the result of the function an error.
//
// https://sqlite.org/c3ref/result_blob.html
func (ctx Context) ResultError(err error) {
if errors.Is(err, NOMEM) {
ctx.c.call("sqlite3_result_error_nomem", uint64(ctx.handle))
return
}
if errors.Is(err, TOOBIG) {
ctx.c.call("sqlite3_result_error_toobig", uint64(ctx.handle))
return
}
msg, code := errorCode(err, _OK)
if msg != "" {
defer ctx.c.arena.mark()()
ptr := ctx.c.arena.string(msg)
ctx.c.call("sqlite3_result_error",
uint64(ctx.handle), uint64(ptr), uint64(len(msg)))
}
if code != _OK {
ctx.c.call("sqlite3_result_error_code",
uint64(ctx.handle), uint64(code))
}
}

View File

@@ -12,25 +12,39 @@
//
// sql.Open("sqlite3", "file:demo.db?_txlock=immediate")
//
// Possible values are: "deferred", "immediate", "exclusive".
// A [read-only] transaction is always "deferred", regardless of "_txlock".
//
// The time encoding/decoding format can be specified using "_timefmt":
//
// sql.Open("sqlite3", "file:demo.db?_timefmt=sqlite")
//
// Possible values are: "auto" (the default), "sqlite", "rfc3339";
// "auto" encodes as RFC 3339 and decodes any [format] supported by SQLite;
// "sqlite" encodes as SQLite and decodes any [format] supported by SQLite;
// "rfc3339" encodes and decodes RFC 3339 only.
//
// [PRAGMA] statements can be specified using "_pragma":
//
// sql.Open("sqlite3", "file:demo.db?_pragma=busy_timeout(10000)&_pragma=locking_mode(normal)")
// sql.Open("sqlite3", "file:demo.db?_pragma=busy_timeout(10000)")
//
// If no PRAGMAs are specified, a busy timeout of 1 minute
// and normal locking mode are used.
// If no PRAGMAs are specified, a busy timeout of 1 minute is set.
//
// Order matters:
// busy timeout and locking mode should be the first PRAGMAs set, in that order.
//
// [URI]: https://www.sqlite.org/uri.html
// [PRAGMA]: https://www.sqlite.org/pragma.html
// [TRANSACTION]: https://www.sqlite.org/lang_transaction.html#deferred_immediate_and_exclusive_transactions
// [URI]: https://sqlite.org/uri.html
// [PRAGMA]: https://sqlite.org/pragma.html
// [format]: https://sqlite.org/lang_datefunc.html#time_values
// [TRANSACTION]: https://sqlite.org/lang_transaction.html#deferred_immediate_and_exclusive_transactions
// [read-only]: https://pkg.go.dev/database/sql#TxOptions
package driver
import (
"context"
"database/sql"
"database/sql/driver"
"errors"
"fmt"
"io"
"net/url"
@@ -41,69 +55,147 @@ import (
"github.com/ncruces/go-sqlite3/internal/util"
)
// This variable can be replaced with -ldflags:
//
// go build -ldflags="-X github.com/ncruces/go-sqlite3/driver.driverName=sqlite"
var driverName = "sqlite3"
func init() {
sql.Register("sqlite3", sqlite{})
if driverName != "" {
sql.Register(driverName, sqlite{})
}
}
// Open opens the SQLite database specified by dataSourceName as a [database/sql.DB].
//
// The init function is called by the driver on new connections.
// The conn can be used to execute queries, register functions, etc.
// Any error return closes the conn and passes the error to [database/sql].
func Open(dataSourceName string, init func(*sqlite3.Conn) error) (*sql.DB, error) {
c, err := newConnector(dataSourceName, init)
if err != nil {
return nil, err
}
return sql.OpenDB(c), nil
}
type sqlite struct{}
func (sqlite) Open(name string) (_ driver.Conn, err error) {
var c conn
c.Conn, err = sqlite3.Open(name)
func (sqlite) Open(name string) (driver.Conn, error) {
c, err := newConnector(name, nil)
if err != nil {
return nil, err
}
return c.Connect(context.Background())
}
c.txBegin = "BEGIN"
var pragmas []string
func (sqlite) OpenConnector(name string) (driver.Connector, error) {
return newConnector(name, nil)
}
func newConnector(name string, init func(*sqlite3.Conn) error) (*connector, error) {
c := connector{name: name, init: init}
var txlock, timefmt string
if strings.HasPrefix(name, "file:") {
if _, after, ok := strings.Cut(name, "?"); ok {
query, _ := url.ParseQuery(after)
switch s := query.Get("_txlock"); s {
case "":
c.txBegin = "BEGIN"
case "deferred", "immediate", "exclusive":
c.txBegin = "BEGIN " + s
default:
c.Close()
return nil, fmt.Errorf("sqlite3: invalid _txlock: %s", s)
query, err := url.ParseQuery(after)
if err != nil {
return nil, err
}
pragmas = query["_pragma"]
txlock = query.Get("_txlock")
timefmt = query.Get("_timefmt")
c.pragmas = query.Has("_pragma")
}
}
if len(pragmas) == 0 {
err := c.Conn.Exec(`
PRAGMA busy_timeout=60000;
PRAGMA locking_mode=normal;
`)
switch txlock {
case "":
c.txBegin = "BEGIN"
case "deferred", "immediate", "exclusive":
c.txBegin = "BEGIN " + txlock
default:
return nil, fmt.Errorf("sqlite3: invalid _txlock: %s", txlock)
}
switch timefmt {
case "":
c.tmRead = sqlite3.TimeFormatAuto
c.tmWrite = sqlite3.TimeFormatDefault
case "sqlite":
c.tmRead = sqlite3.TimeFormatAuto
c.tmWrite = sqlite3.TimeFormat3
case "rfc3339":
c.tmRead = sqlite3.TimeFormatDefault
c.tmWrite = sqlite3.TimeFormatDefault
default:
c.tmRead = sqlite3.TimeFormat(timefmt)
c.tmWrite = sqlite3.TimeFormat(timefmt)
}
return &c, nil
}
type connector struct {
init func(*sqlite3.Conn) error
name string
txBegin string
tmRead sqlite3.TimeFormat
tmWrite sqlite3.TimeFormat
pragmas bool
}
func (n *connector) Driver() driver.Driver {
return sqlite{}
}
func (n *connector) Connect(ctx context.Context) (_ driver.Conn, err error) {
c := &conn{
txBegin: n.txBegin,
tmRead: n.tmRead,
tmWrite: n.tmWrite,
}
c.Conn, err = sqlite3.Open(n.name)
if err != nil {
return nil, err
}
defer func() {
if err != nil {
c.Close()
return nil, err
}
c.reusable = true
} else {
s, _, err := c.Conn.Prepare(`
SELECT * FROM
PRAGMA_locking_mode,
PRAGMA_query_only;
`)
}()
old := c.Conn.SetInterrupt(ctx)
defer c.Conn.SetInterrupt(old)
if !n.pragmas {
err = c.Conn.Exec(`PRAGMA busy_timeout=60000`)
if err != nil {
c.Close()
return nil, err
}
if s.Step() {
c.reusable = s.ColumnText(0) == "normal"
c.readOnly = s.ColumnRawText(1)[0] // 0 or 1
}
if n.init != nil {
err = n.init(c.Conn)
if err != nil {
return nil, err
}
}
if n.pragmas || n.init != nil {
s, _, err := c.Conn.Prepare(`PRAGMA query_only`)
if err != nil {
return nil, err
}
if s.Step() && s.ColumnBool(0) {
c.readOnly = '1'
} else {
c.readOnly = '0'
}
err = s.Close()
if err != nil {
c.Close()
return nil, err
}
}
return &c, nil
return c, nil
}
type conn struct {
@@ -111,20 +203,21 @@ type conn struct {
txBegin string
txCommit string
txRollback string
reusable bool
tmRead sqlite3.TimeFormat
tmWrite sqlite3.TimeFormat
readOnly byte
}
var (
// Ensure these interfaces are implemented:
_ driver.ExecerContext = &conn{}
_ driver.ConnBeginTx = &conn{}
_ driver.Validator = &conn{}
_ sqlite3.DriverConn = &conn{}
_ driver.ConnPrepareContext = &conn{}
_ driver.ExecerContext = &conn{}
_ driver.ConnBeginTx = &conn{}
_ sqlite3.DriverConn = &conn{}
)
func (c *conn) IsValid() bool {
return c.reusable
func (c *conn) Raw() *sqlite3.Conn {
return c.Conn
}
func (c *conn) Begin() (driver.Tx, error) {
@@ -140,10 +233,10 @@ func (c *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, e
txBegin = `
BEGIN deferred;
PRAGMA query_only=on`
c.txCommit = `
c.txRollback = `
ROLLBACK;
PRAGMA query_only=` + string(c.readOnly)
c.txRollback = c.txCommit
c.txCommit = c.txRollback
}
switch opts.Isolation {
@@ -167,14 +260,20 @@ func (c *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, e
func (c *conn) Commit() error {
err := c.Conn.Exec(c.txCommit)
if err != nil && !c.GetAutocommit() {
if err != nil && !c.Conn.GetAutocommit() {
c.Rollback()
}
return err
}
func (c *conn) Rollback() error {
return c.Conn.Exec(c.txRollback)
err := c.Conn.Exec(c.txRollback)
if errors.Is(err, sqlite3.INTERRUPT) {
old := c.Conn.SetInterrupt(context.Background())
defer c.Conn.SetInterrupt(old)
err = c.Conn.Exec(c.txRollback)
}
return err
}
func (c *conn) Prepare(query string) (driver.Stmt, error) {
@@ -190,19 +289,10 @@ func (c *conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, e
return nil, err
}
if tail != "" {
// Check if the tail contains any SQL.
st, _, err := c.Conn.Prepare(tail)
if err != nil {
s.Close()
return nil, err
}
if st != nil {
s.Close()
st.Close()
return nil, util.TailErr
}
s.Close()
return nil, util.TailErr
}
return &stmt{s, c.Conn}, nil
return &stmt{Stmt: s, tmRead: c.tmRead, tmWrite: c.tmWrite}, nil
}
func (c *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
@@ -211,6 +301,12 @@ func (c *conn) ExecContext(ctx context.Context, query string, args []driver.Name
return nil, driver.ErrSkip
}
if savept, ok := ctx.(*saveptCtx); ok {
// Called from driver.Savepoint.
savept.Savepoint = c.Conn.Savepoint()
return resultRowsAffected(0), nil
}
old := c.Conn.SetInterrupt(ctx)
defer c.Conn.SetInterrupt(old)
@@ -222,9 +318,14 @@ func (c *conn) ExecContext(ctx context.Context, query string, args []driver.Name
return newResult(c.Conn), nil
}
func (*conn) CheckNamedValue(arg *driver.NamedValue) error {
return nil
}
type stmt struct {
Stmt *sqlite3.Stmt
Conn *sqlite3.Conn
*sqlite3.Stmt
tmWrite sqlite3.TimeFormat
tmRead sqlite3.TimeFormat
}
var (
@@ -234,10 +335,6 @@ var (
_ driver.NamedValueChecker = &stmt{}
)
func (s *stmt) Close() error {
return s.Stmt.Close()
}
func (s *stmt) NumInput() int {
n := s.Stmt.BindCount()
for i := 1; i <= n; i++ {
@@ -259,26 +356,35 @@ func (s *stmt) Query(args []driver.Value) (driver.Rows, error) {
}
func (s *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
// Use QueryContext to setup bindings.
// No need to close rows: that simply resets the statement, exec does the same.
_, err := s.QueryContext(ctx, args)
err := s.setupBindings(args)
if err != nil {
return nil, err
}
old := s.Stmt.Conn().SetInterrupt(ctx)
defer s.Stmt.Conn().SetInterrupt(old)
err = s.Stmt.Exec()
if err != nil {
return nil, err
}
return newResult(s.Conn), nil
return newResult(s.Stmt.Conn()), nil
}
func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
err := s.Stmt.ClearBindings()
err := s.setupBindings(args)
if err != nil {
return nil, err
}
return &rows{s, ctx}, nil
}
func (s *stmt) setupBindings(args []driver.NamedValue) error {
err := s.Stmt.ClearBindings()
if err != nil {
return err
}
var ids [3]int
for _, arg := range args {
@@ -310,7 +416,11 @@ func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driv
case sqlite3.ZeroBlob:
err = s.Stmt.BindZeroBlob(id, int64(a))
case time.Time:
err = s.Stmt.BindTime(id, a, sqlite3.TimeFormatDefault)
err = s.Stmt.BindTime(id, a, s.tmWrite)
case interface{ Pointer() any }:
err = s.Stmt.BindPointer(id, a.Pointer())
case interface{ JSON() any }:
err = s.Stmt.BindJSON(id, a.JSON())
case nil:
err = s.Stmt.BindNull(id)
default:
@@ -318,17 +428,19 @@ func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driv
}
}
if err != nil {
return nil, err
return err
}
}
return &rows{ctx, s.Stmt, s.Conn}, nil
return nil
}
func (s *stmt) CheckNamedValue(arg *driver.NamedValue) error {
switch arg.Value.(type) {
case bool, int, int64, float64, string, []byte,
sqlite3.ZeroBlob, time.Time, nil:
sqlite3.ZeroBlob, time.Time,
interface{ Pointer() any },
interface{ JSON() any },
nil:
return nil
default:
return driver.ErrSkip
@@ -367,12 +479,12 @@ func (r resultRowsAffected) RowsAffected() (int64, error) {
}
type rows struct {
ctx context.Context
Stmt *sqlite3.Stmt
Conn *sqlite3.Conn
*stmt
ctx context.Context
}
func (r *rows) Close() error {
r.Stmt.ClearBindings()
return r.Stmt.Reset()
}
@@ -385,9 +497,19 @@ func (r *rows) Columns() []string {
return columns
}
func (r *rows) ColumnTypeDatabaseTypeName(index int) string {
decltype := r.Stmt.ColumnDeclType(index)
if len := len(decltype); len > 0 && decltype[len-1] == ')' {
if i := strings.LastIndexByte(decltype, '('); i >= 0 {
decltype = decltype[:i]
}
}
return strings.ToUpper(strings.TrimSpace(decltype))
}
func (r *rows) Next(dest []driver.Value) error {
old := r.Conn.SetInterrupt(r.ctx)
defer r.Conn.SetInterrupt(old)
old := r.Stmt.Conn().SetInterrupt(r.ctx)
defer r.Stmt.Conn().SetInterrupt(old)
if !r.Stmt.Step() {
if err := r.Stmt.Err(); err != nil {
@@ -397,6 +519,10 @@ func (r *rows) Next(dest []driver.Value) error {
}
for i := range dest {
if t, ok := r.decodeTime(i); ok {
dest[i] = t
continue
}
switch r.Stmt.ColumnType(i) {
case sqlite3.INTEGER:
dest[i] = r.Stmt.ColumnInt64(i)
@@ -407,11 +533,7 @@ func (r *rows) Next(dest []driver.Value) error {
case sqlite3.TEXT:
dest[i] = stringOrTime(r.Stmt.ColumnRawText(i))
case sqlite3.NULL:
if buf, ok := dest[i].([]byte); ok {
dest[i] = buf[0:0]
} else {
dest[i] = nil
}
dest[i] = nil
default:
panic(util.AssertErr())
}
@@ -419,3 +541,22 @@ func (r *rows) Next(dest []driver.Value) error {
return r.Stmt.Err()
}
func (s *stmt) decodeTime(i int) (_ time.Time, _ bool) {
if s.tmRead == "" {
return
}
switch s.Stmt.ColumnType(i) {
case sqlite3.INTEGER, sqlite3.FLOAT, sqlite3.TEXT:
// maybe
default:
return
}
switch strings.ToUpper(s.Stmt.ColumnDeclType(i)) {
case "DATE", "TIME", "DATETIME", "TIMESTAMP":
// maybe
default:
return
}
return s.Stmt.ColumnTime(i, s.tmRead), s.Stmt.Err() == nil
}

View File

@@ -11,6 +11,7 @@ import (
"time"
"github.com/ncruces/go-sqlite3"
_ "github.com/ncruces/go-sqlite3/embed"
"github.com/ncruces/go-sqlite3/internal/util"
)
@@ -113,13 +114,7 @@ func Test_Open_txLock(t *testing.T) {
func Test_Open_txLock_invalid(t *testing.T) {
t.Parallel()
db, err := sql.Open("sqlite3", "file::memory:?_txlock=xclusive")
if err != nil {
t.Fatal(err)
}
defer db.Close()
_, err = db.Conn(context.TODO())
_, err := sql.Open("sqlite3", "file::memory:?_txlock=xclusive")
if err == nil {
t.Fatal("want error")
}
@@ -185,12 +180,6 @@ func Test_Prepare(t *testing.T) {
}
defer db.Close()
stmt, err := db.Prepare(`SELECT 1; -- HERE`)
if err != nil {
t.Error(err)
}
defer stmt.Close()
var serr *sqlite3.Error
_, err = db.Prepare(`SELECT`)
if err == nil {
@@ -206,18 +195,14 @@ func Test_Prepare(t *testing.T) {
t.Error("got message:", got)
}
_, err = db.Prepare(`SELECT 1; `)
if err.Error() != string(util.TailErr) {
t.Error("want tailErr")
}
_, err = db.Prepare(`SELECT 1; SELECT`)
if err == nil {
t.Error("want error")
}
if !errors.As(err, &serr) {
t.Fatalf("got %T, want sqlite3.Error", err)
}
if rc := serr.Code(); rc != sqlite3.ERROR {
t.Errorf("got %d, want sqlite3.ERROR", rc)
}
if got := err.Error(); got != `sqlite3: SQL logic error: incomplete input` {
t.Error("got message:", got)
if err.Error() != string(util.TailErr) {
t.Error("want tailErr")
}
_, err = db.Prepare(`SELECT 1; SELECT 2`)
@@ -296,6 +281,7 @@ func Test_QueryRow_blob_null(t *testing.T) {
if err != nil {
t.Fatal(err)
}
defer rows.Close()
want := [][]byte{nil, {0xca, 0xfe}, {0xba, 0xbe}, nil}
for i := 0; rows.Next(); i++ {

65
driver/json_test.go Normal file
View File

@@ -0,0 +1,65 @@
package driver_test
import (
"fmt"
"log"
"github.com/ncruces/go-sqlite3"
"github.com/ncruces/go-sqlite3/driver"
_ "github.com/ncruces/go-sqlite3/embed"
_ "github.com/ncruces/go-sqlite3/vfs/memdb"
)
func Example_json() {
db, err := driver.Open("file:/test.db?vfs=memdb", nil)
if err != nil {
log.Fatal(err)
}
defer db.Close()
_, err = db.Exec(`
CREATE TABLE IF NOT EXISTS orders (
cart_id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL,
cart TEXT
);
`)
if err != nil {
log.Fatal(err)
}
type CartItem struct {
ItemID string `json:"id"`
Name string `json:"name"`
Quantity int `json:"quantity,omitempty"`
Price int `json:"price,omitempty"`
}
type Cart struct {
Items []CartItem `json:"items"`
}
_, err = db.Exec(`INSERT INTO orders (user_id, cart) VALUES (?, ?)`, 123, sqlite3.JSON(Cart{
[]CartItem{
{ItemID: "111", Name: "T-shirt", Quantity: 1, Price: 250},
{ItemID: "222", Name: "Trousers", Quantity: 1, Price: 600},
},
}))
if err != nil {
log.Fatal(err)
}
var total string
err = db.QueryRow(`
SELECT total(json_each.value -> 'price')
FROM orders, json_each(cart -> 'items')
WHERE cart_id = last_insert_rowid()
`).Scan(&total)
if err != nil {
log.Fatal(err)
}
fmt.Println("total:", total)
// Output:
// total: 850
}

27
driver/savepoint.go Normal file
View File

@@ -0,0 +1,27 @@
package driver
import (
"database/sql"
"time"
"github.com/ncruces/go-sqlite3"
)
// Savepoint establishes a new transaction savepoint.
//
// https://sqlite.org/lang_savepoint.html
func Savepoint(tx *sql.Tx) sqlite3.Savepoint {
var ctx saveptCtx
tx.ExecContext(&ctx, "")
return ctx.Savepoint
}
type saveptCtx struct{ sqlite3.Savepoint }
func (*saveptCtx) Deadline() (deadline time.Time, ok bool) { return }
func (*saveptCtx) Done() <-chan struct{} { return nil }
func (*saveptCtx) Err() error { return nil }
func (*saveptCtx) Value(key any) any { return nil }

88
driver/savepoint_test.go Normal file
View File

@@ -0,0 +1,88 @@
package driver_test
import (
"fmt"
"log"
"github.com/ncruces/go-sqlite3/driver"
_ "github.com/ncruces/go-sqlite3/embed"
_ "github.com/ncruces/go-sqlite3/vfs/memdb"
)
func ExampleSavepoint() {
db, err := driver.Open("file:/test.db?vfs=memdb", nil)
if err != nil {
log.Fatal(err)
}
defer db.Close()
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS users (id INT, name VARCHAR(10))`)
if err != nil {
log.Fatal(err)
}
err = func() error {
tx, err := db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
stmt, err := tx.Prepare(`INSERT INTO users (id, name) VALUES (?, ?)`)
if err != nil {
return err
}
defer stmt.Close()
_, err = stmt.Exec(0, "go")
if err != nil {
return err
}
_, err = stmt.Exec(1, "zig")
if err != nil {
return err
}
savept := driver.Savepoint(tx)
_, err = stmt.Exec(2, "whatever")
if err != nil {
return err
}
err = savept.Rollback()
if err != nil {
return err
}
_, err = stmt.Exec(3, "rust")
if err != nil {
return err
}
return tx.Commit()
}()
if err != nil {
log.Fatal(err)
}
rows, err := db.Query(`SELECT id, name FROM users`)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id, name string
err = rows.Scan(&id, &name)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s %s\n", id, name)
}
// Output:
// 0 go
// 1 zig
// 3 rust
}

View File

@@ -49,16 +49,16 @@ func Fuzz_stringOrTime_1(f *testing.F) {
// This checks that any [time.Time] can be recovered as a [time.Time],
// with nanosecond accuracy, and preserving any timezone offset.
func Fuzz_stringOrTime_2(f *testing.F) {
f.Add(0, 0)
f.Add(0, 1)
f.Add(0, -1)
f.Add(0, 999_999_999)
f.Add(0, 1_000_000_000)
f.Add(7956915742, 222_222_222) // twosday
f.Add(639095955742, 222_222_222) // twosday, year 22222AD
f.Add(-763421161058, 222_222_222) // twosday, year 22222BC
f.Add(int64(0), int64(0))
f.Add(int64(0), int64(1))
f.Add(int64(0), int64(-1))
f.Add(int64(0), int64(999_999_999))
f.Add(int64(0), int64(1_000_000_000))
f.Add(int64(7956915742), int64(222_222_222)) // twosday
f.Add(int64(639095955742), int64(222_222_222)) // twosday, year 22222AD
f.Add(int64(-763421161058), int64(222_222_222)) // twosday, year 22222BC
checkTime := func(t *testing.T, date time.Time) {
checkTime := func(t testing.TB, date time.Time) {
value := stringOrTime([]byte(date.Format(time.RFC3339Nano)))
switch v := value.(type) {
@@ -80,7 +80,7 @@ func Fuzz_stringOrTime_2(f *testing.F) {
}
}
f.Fuzz(func(t *testing.T, sec, nsec int) {
f.Fuzz(func(t *testing.T, sec, nsec int64) {
// Reduce the search space.
if 1e12 < sec || sec < -1e12 {
// Dates before 29000BC and after 33000AD; I think we're safe.
@@ -91,7 +91,7 @@ func Fuzz_stringOrTime_2(f *testing.F) {
return
}
unix := time.Unix(int64(sec), int64(nsec))
unix := time.Unix(sec, nsec)
checkTime(t, unix)
checkTime(t, unix.UTC())
checkTime(t, unix.In(time.FixedZone("", -8*3600)))

View File

@@ -1,75 +0,0 @@
package sqlite3_test
import (
"context"
"database/sql"
"fmt"
"log"
"os"
"github.com/ncruces/go-sqlite3"
_ "github.com/ncruces/go-sqlite3/driver"
_ "github.com/ncruces/go-sqlite3/embed"
)
var db *sql.DB
func ExampleDriverConn() {
var err error
db, err = sql.Open("sqlite3", "demo.db")
if err != nil {
log.Fatal(err)
}
defer os.Remove("demo.db")
defer db.Close()
ctx := context.Background()
conn, err := db.Conn(ctx)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
_, err = conn.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS test (col)`)
if err != nil {
log.Fatal(err)
}
res, err := conn.ExecContext(ctx, `INSERT INTO test VALUES (?)`, sqlite3.ZeroBlob(11))
if err != nil {
log.Fatal(err)
}
id, err := res.LastInsertId()
if err != nil {
log.Fatal(err)
}
err = conn.Raw(func(driverConn any) error {
conn := driverConn.(sqlite3.DriverConn)
savept := conn.Savepoint()
defer savept.Release(&err)
blob, err := conn.OpenBlob("main", "test", "col", id, true)
if err != nil {
return err
}
defer blob.Close()
_, err = fmt.Fprint(blob, "Hello BLOB!")
return err
})
if err != nil {
log.Fatal(err)
}
var msg string
err = conn.QueryRowContext(ctx, `SELECT col FROM test`).Scan(&msg)
if err != nil {
log.Fatal(err)
}
fmt.Println(msg)
// Output:
// Hello BLOB!
}

View File

@@ -1,14 +1,15 @@
# Embeddable WASM build of SQLite
This folder includes an embeddable WASM build of SQLite 3.42.0 for use with
This folder includes an embeddable WASM build of SQLite 3.44.2 for use with
[`github.com/ncruces/go-sqlite3`](https://pkg.go.dev/github.com/ncruces/go-sqlite3).
The following optional features are compiled in:
- [math functions](https://www.sqlite.org/lang_mathfunc.html)
- [FTS3/4](https://www.sqlite.org/fts3.html)/[5](https://www.sqlite.org/fts5.html)
- [JSON](https://www.sqlite.org/json1.html)
- [R*Tree](https://www.sqlite.org/rtree.html)
- [GeoPoly](https://www.sqlite.org/geopoly.html)
- [math functions](https://sqlite.org/lang_mathfunc.html)
- [FTS3/4](https://sqlite.org/fts3.html)/[5](https://sqlite.org/fts5.html)
- [JSON](https://sqlite.org/json1.html)
- [R*Tree](https://sqlite.org/rtree.html)
- [GeoPoly](https://sqlite.org/geopoly.html)
- [soundex](https://sqlite.org/lang_corefunc.html#soundex)
- [base64](https://github.com/sqlite/sqlite/blob/master/ext/misc/base64.c)
- [decimal](https://github.com/sqlite/sqlite/blob/master/ext/misc/decimal.c)
- [regexp](https://github.com/sqlite/sqlite/blob/master/ext/misc/regexp.c)

View File

@@ -4,24 +4,27 @@ set -euo pipefail
cd -P -- "$(dirname -- "$0")"
ROOT=../
BINARYEN="$ROOT/tools/binaryen-version_113/bin"
BINARYEN="$ROOT/tools/binaryen-version_116/bin"
WASI_SDK="$ROOT/tools/wasi-sdk-20.0/bin"
"$WASI_SDK/clang" --target=wasm32-wasi -flto -g0 -O2 \
-o sqlite3.wasm "$ROOT/sqlite3/main.c" \
-I"$ROOT/sqlite3" \
-mexec-model=reactor \
-mmutable-globals \
-msimd128 -mmutable-globals \
-mbulk-memory -mreference-types \
-mnontrapping-fptoint -msign-ext \
-fno-stack-protector -fno-stack-clash-protection \
-Wl,--initial-memory=327680 \
-Wl,--stack-first \
-Wl,--import-undefined \
-D_HAVE_SQLITE_CONFIG_H \
$(awk '{print "-Wl,--export="$0}' exports.txt)
trap 'rm -f sqlite3.tmp' EXIT
"$BINARYEN/wasm-ctor-eval" -g -c _initialize sqlite3.wasm -o sqlite3.tmp
"$BINARYEN/wasm-opt" -g -O2 sqlite3.tmp -o sqlite3.wasm \
--enable-multivalue --enable-mutable-globals \
"$BINARYEN/wasm-opt" -g --strip --strip-producers -c -O3 \
sqlite3.tmp -o sqlite3.wasm \
--enable-simd --enable-mutable-globals --enable-multivalue \
--enable-bulk-memory --enable-reference-types \
--enable-nontrapping-float-to-int --enable-sign-ext

View File

@@ -1,49 +1,101 @@
free
malloc
malloc_destructor
sqlite3_errcode
sqlite3_errstr
sqlite3_errmsg
sqlite3_error_offset
sqlite3_open_v2
sqlite3_close
sqlite3_close_v2
sqlite3_prepare_v3
sqlite3_finalize
sqlite3_reset
sqlite3_step
sqlite3_exec
sqlite3_clear_bindings
sqlite3_aggregate_context
sqlite3_anycollseq_init
sqlite3_backup_finish
sqlite3_backup_init
sqlite3_backup_pagecount
sqlite3_backup_remaining
sqlite3_backup_step
sqlite3_bind_blob64
sqlite3_bind_double
sqlite3_bind_int64
sqlite3_bind_null
sqlite3_bind_parameter_count
sqlite3_bind_parameter_index
sqlite3_bind_parameter_name
sqlite3_bind_null
sqlite3_bind_int64
sqlite3_bind_double
sqlite3_bind_pointer_go
sqlite3_bind_text64
sqlite3_bind_blob64
sqlite3_bind_value
sqlite3_bind_zeroblob64
sqlite3_column_count
sqlite3_column_name
sqlite3_column_type
sqlite3_column_int64
sqlite3_column_double
sqlite3_column_text
sqlite3_blob_bytes
sqlite3_blob_close
sqlite3_blob_open
sqlite3_blob_read
sqlite3_blob_reopen
sqlite3_blob_write
sqlite3_changes64
sqlite3_clear_bindings
sqlite3_close
sqlite3_close_v2
sqlite3_column_blob
sqlite3_column_bytes
sqlite3_blob_open
sqlite3_blob_close
sqlite3_blob_bytes
sqlite3_blob_read
sqlite3_blob_write
sqlite3_blob_reopen
sqlite3_backup_init
sqlite3_backup_step
sqlite3_backup_finish
sqlite3_backup_remaining
sqlite3_backup_pagecount
sqlite3_uri_parameter
sqlite3_uri_key
sqlite3_changes64
sqlite3_column_count
sqlite3_column_decltype
sqlite3_column_double
sqlite3_column_int64
sqlite3_column_name
sqlite3_column_text
sqlite3_column_type
sqlite3_column_value
sqlite3_create_aggregate_function_go
sqlite3_create_collation_go
sqlite3_create_function_go
sqlite3_create_module_go
sqlite3_create_window_function_go
sqlite3_declare_vtab
sqlite3_errcode
sqlite3_errmsg
sqlite3_error_offset
sqlite3_errstr
sqlite3_exec
sqlite3_finalize
sqlite3_get_autocommit
sqlite3_get_auxdata
sqlite3_interrupt
sqlite3_last_insert_rowid
sqlite3_get_autocommit
sqlite3_open_v2
sqlite3_overload_function
sqlite3_prepare_v3
sqlite3_progress_handler_go
sqlite3_reset
sqlite3_result_blob64
sqlite3_result_double
sqlite3_result_error
sqlite3_result_error_code
sqlite3_result_error_nomem
sqlite3_result_error_toobig
sqlite3_result_int64
sqlite3_result_null
sqlite3_result_pointer_go
sqlite3_result_text64
sqlite3_result_value
sqlite3_result_zeroblob64
sqlite3_set_auxdata_go
sqlite3_step
sqlite3_stmt_busy
sqlite3_stmt_readonly
sqlite3_stmt_status
sqlite3_uri_key
sqlite3_uri_parameter
sqlite3_user_data
sqlite3_value_blob
sqlite3_value_bytes
sqlite3_value_double
sqlite3_value_dup
sqlite3_value_free
sqlite3_value_int64
sqlite3_value_nochange
sqlite3_value_pointer_go
sqlite3_value_text
sqlite3_value_type
sqlite3_vtab_collation
sqlite3_vtab_config_go
sqlite3_vtab_distinct
sqlite3_vtab_in
sqlite3_vtab_in_first
sqlite3_vtab_in_next
sqlite3_vtab_nochange
sqlite3_vtab_on_conflict
sqlite3_vtab_rhs_value

Binary file not shown.

View File

@@ -1,6 +1,7 @@
package sqlite3
import (
"errors"
"strconv"
"strings"
@@ -9,7 +10,7 @@ import (
// Error wraps an SQLite Error Code.
//
// https://www.sqlite.org/c3ref/errcode.html
// https://sqlite.org/c3ref/errcode.html
type Error struct {
str string
msg string
@@ -19,14 +20,14 @@ type Error struct {
// Code returns the primary error code for this error.
//
// https://www.sqlite.org/rescode.html
// https://sqlite.org/rescode.html
func (e *Error) Code() ErrorCode {
return ErrorCode(e.code)
}
// ExtendedCode returns the extended error code for this error.
//
// https://www.sqlite.org/rescode.html
// https://sqlite.org/rescode.html
func (e *Error) ExtendedCode() ExtendedErrorCode {
return ExtendedErrorCode(e.code)
}
@@ -43,8 +44,7 @@ func (e *Error) Error() string {
}
if e.msg != "" {
b.WriteByte(':')
b.WriteByte(' ')
b.WriteString(": ")
b.WriteString(e.msg)
}
@@ -68,6 +68,19 @@ func (e *Error) Is(err error) bool {
return false
}
// As converts this error to an [ErrorCode] or [ExtendedErrorCode].
func (e *Error) As(err any) bool {
switch c := err.(type) {
case *ErrorCode:
*c = e.Code()
return true
case *ExtendedErrorCode:
*c = e.ExtendedCode()
return true
}
return false
}
// Temporary returns true for [BUSY] errors.
func (e *Error) Temporary() bool {
return e.Code() == BUSY
@@ -104,6 +117,15 @@ func (e ExtendedErrorCode) Is(err error) bool {
return ok && c == ErrorCode(e)
}
// As converts this error to an [ErrorCode].
func (e ExtendedErrorCode) As(err any) bool {
c, ok := err.(*ErrorCode)
if ok {
*c = ErrorCode(e)
}
return ok
}
// Temporary returns true for [BUSY] errors.
func (e ExtendedErrorCode) Temporary() bool {
return ErrorCode(e) == BUSY
@@ -113,3 +135,28 @@ func (e ExtendedErrorCode) Temporary() bool {
func (e ExtendedErrorCode) Timeout() bool {
return e == BUSY_TIMEOUT
}
func errorCode(err error, def ErrorCode) (msg string, code uint32) {
switch code := err.(type) {
case ErrorCode:
return "", uint32(code)
case ExtendedErrorCode:
return "", uint32(code)
case *Error:
return code.msg, uint32(code.code)
case nil:
return "", _OK
}
var ecode ErrorCode
var xcode xErrorCode
switch {
case errors.As(err, &xcode):
code = uint32(xcode)
case errors.As(err, &ecode):
code = uint32(ecode)
default:
code = uint32(def)
}
return err.Error(), code
}

View File

@@ -18,22 +18,36 @@ func Test_assertErr(t *testing.T) {
func TestError(t *testing.T) {
t.Parallel()
err := Error{code: 0x8080}
if rc := err.Code(); rc != 0x80 {
t.Errorf("got %#x, want 0x80", rc)
var ecode ErrorCode
var xcode xErrorCode
err := &Error{code: 0x8080}
if !errors.As(err, &err) {
t.Fatal("want true")
}
if !errors.Is(&err, ErrorCode(0x80)) {
if ecode := err.Code(); ecode != 0x80 {
t.Errorf("got %#x, want 0x80", uint8(ecode))
}
if ok := errors.As(err, &ecode); !ok || ecode != ErrorCode(0x80) {
t.Errorf("got %#x, want 0x80", uint8(ecode))
}
if !errors.Is(err, ErrorCode(0x80)) {
t.Errorf("want true")
}
if rc := err.ExtendedCode(); rc != 0x8080 {
t.Errorf("got %#x, want 0x8080", rc)
if xcode := err.ExtendedCode(); xcode != 0x8080 {
t.Errorf("got %#x, want 0x8080", uint16(xcode))
}
if !errors.Is(&err, ExtendedErrorCode(0x8080)) {
if ok := errors.As(err, &xcode); !ok || xcode != xErrorCode(0x8080) {
t.Errorf("got %#x, want 0x8080", uint16(xcode))
}
if !errors.Is(err, xErrorCode(0x8080)) {
t.Errorf("want true")
}
if s := err.Error(); s != "sqlite3: 32896" {
t.Errorf("got %q", s)
}
if ok := errors.As(err.ExtendedCode(), &ecode); !ok || ecode != ErrorCode(0x80) {
t.Errorf("got %#x, want 0x80", uint8(ecode))
}
if !errors.Is(err.ExtendedCode(), ErrorCode(0x80)) {
t.Errorf("want true")
}
@@ -121,8 +135,8 @@ func Test_ErrorCode_Error(t *testing.T) {
// Test all error codes.
for i := 0; i == int(ErrorCode(i)); i++ {
want := "sqlite3: "
r := db.call(db.api.errstr, uint64(i))
want += util.ReadString(db.mod, uint32(r), _MAX_STRING)
r := db.call("sqlite3_errstr", uint64(i))
want += util.ReadString(db.mod, uint32(r), _MAX_NAME)
got := ErrorCode(i).Error()
if got != want {
@@ -143,8 +157,8 @@ func Test_ExtendedErrorCode_Error(t *testing.T) {
// Test all extended error codes.
for i := 0; i == int(ExtendedErrorCode(i)); i++ {
want := "sqlite3: "
r := db.call(db.api.errstr, uint64(i))
want += util.ReadString(db.mod, uint32(r), _MAX_STRING)
r := db.call("sqlite3_errstr", uint64(i))
want += util.ReadString(db.mod, uint32(r), _MAX_NAME)
got := ExtendedErrorCode(i).Error()
if got != want {

135
ext/array/array.go Normal file
View File

@@ -0,0 +1,135 @@
// Package array provides the array table-valued SQL function.
package array
import (
"fmt"
"reflect"
"github.com/ncruces/go-sqlite3"
)
// Register registers the array single-argument, table-valued SQL function.
// The argument must be an [sqlite3.Pointer] to a Go slice or array
// of ints, floats, bools, strings or blobs.
//
// https://sqlite.org/carray.html
func Register(db *sqlite3.Conn) {
sqlite3.CreateModule[array](db, "array", nil,
func(db *sqlite3.Conn, _, _, _ string, _ ...string) (array, error) {
err := db.DeclareVtab(`CREATE TABLE x(value, array HIDDEN)`)
return array{}, err
})
}
type array struct{}
func (array) BestIndex(idx *sqlite3.IndexInfo) error {
for i, cst := range idx.Constraint {
if cst.Column == 1 && cst.Op == sqlite3.INDEX_CONSTRAINT_EQ && cst.Usable {
idx.ConstraintUsage[i] = sqlite3.IndexConstraintUsage{
Omit: true,
ArgvIndex: 1,
}
idx.EstimatedCost = 1
idx.EstimatedRows = 100
return nil
}
}
return sqlite3.CONSTRAINT
}
func (array) Open() (sqlite3.VTabCursor, error) {
return &cursor{}, nil
}
type cursor struct {
array reflect.Value
rowID int
}
func (c *cursor) EOF() bool {
return c.rowID >= c.array.Len()
}
func (c *cursor) Next() error {
c.rowID++
return nil
}
func (c *cursor) RowID() (int64, error) {
return int64(c.rowID), nil
}
func (c *cursor) Column(ctx *sqlite3.Context, n int) error {
if n != 0 {
return nil
}
v := c.array.Index(c.rowID)
k := v.Kind()
if k == reflect.Interface {
if v.IsNil() {
ctx.ResultNull()
return nil
}
v = v.Elem()
k = v.Kind()
}
switch {
case v.CanInt():
ctx.ResultInt64(v.Int())
case v.CanUint():
i64 := int64(v.Uint())
if i64 < 0 {
return fmt.Errorf("array: integer element overflow:%.0w %d", sqlite3.MISMATCH, v.Uint())
}
ctx.ResultInt64(i64)
case v.CanFloat():
ctx.ResultFloat(v.Float())
case k == reflect.Bool:
ctx.ResultBool(v.Bool())
case k == reflect.String:
ctx.ResultText(v.String())
case (k == reflect.Slice || k == reflect.Array && v.CanAddr()) &&
v.Type().Elem().Kind() == reflect.Uint8:
ctx.ResultBlob(v.Bytes())
default:
return fmt.Errorf("array: unsupported element:%.0w %v", sqlite3.MISMATCH, v.Type())
}
return nil
}
func (c *cursor) Filter(idxNum int, idxStr string, arg ...sqlite3.Value) error {
array := reflect.ValueOf(arg[0].Pointer())
array, err := indexable(array)
if err != nil {
return err
}
c.array = array
c.rowID = 0
return nil
}
func indexable(v reflect.Value) (reflect.Value, error) {
if v.Kind() == reflect.Slice {
return v, nil
}
if v.Kind() == reflect.Array {
return v, nil
}
if v.Kind() == reflect.Pointer {
if v := v.Elem(); v.Kind() == reflect.Array {
return v, nil
}
}
return v, fmt.Errorf("array: unsupported argument:%.0w %v", sqlite3.MISMATCH, v.Type())
}

94
ext/array/array_test.go Normal file
View File

@@ -0,0 +1,94 @@
package array_test
import (
"fmt"
"log"
"math"
"reflect"
"testing"
"github.com/ncruces/go-sqlite3"
"github.com/ncruces/go-sqlite3/driver"
_ "github.com/ncruces/go-sqlite3/embed"
"github.com/ncruces/go-sqlite3/ext/array"
)
func Example() {
db, err := driver.Open(":memory:", func(c *sqlite3.Conn) error {
array.Register(c)
return nil
})
if err != nil {
log.Fatal(err)
}
defer db.Close()
rows, err := db.Query(`
SELECT name
FROM pragma_function_list
WHERE name like 'geopoly%' AND narg IN array(?)`,
sqlite3.Pointer([]int{2, 3, 4}))
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var name string
err := rows.Scan(&name)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", name)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
// Unordered output:
// geopoly_regular
// geopoly_overlap
// geopoly_contains_point
// geopoly_within
}
func Test_cursor_Column(t *testing.T) {
t.Parallel()
db, err := driver.Open(":memory:", func(c *sqlite3.Conn) error {
array.Register(c)
return nil
})
if err != nil {
t.Fatal(err)
}
defer db.Close()
rows, err := db.Query(`
SELECT rowid, value FROM array(?)`,
sqlite3.Pointer(&[...]any{nil, true, 1, uint(2), math.Pi, "text", []byte{1, 2, 3}}))
if err != nil {
t.Fatal(err)
}
defer rows.Close()
want := []string{"nil", "int64", "int64", "int64", "float64", "string", "[]uint8"}
for rows.Next() {
var id, val any
err := rows.Scan(&id, &val)
if err != nil {
t.Fatal(err)
}
if want := want[0]; val == nil {
if want != "nil" {
t.Errorf("got nil, want %s", want)
}
} else if got := reflect.TypeOf(val).String(); got != want {
t.Errorf("got %s, want %s", got, want)
}
want = want[1:]
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
}

70
ext/blob/blob.go Normal file
View File

@@ -0,0 +1,70 @@
// Package blob provides an alternative interface to incremental BLOB I/O.
package blob
import (
"errors"
"github.com/ncruces/go-sqlite3"
"github.com/ncruces/go-sqlite3/internal/util"
)
// Register registers the blob_open SQL function:
//
// blob_open(schema, table, column, rowid, flags, callback, args...)
//
// The callback must be an [sqlite3.Pointer] to an [OpenCallback].
// Any optional args will be passed to the callback,
// along with the [sqlite3.Blob] handle.
//
// https://sqlite.org/c3ref/blob.html
func Register(db *sqlite3.Conn) {
db.CreateFunction("blob_open", -1,
sqlite3.DETERMINISTIC|sqlite3.DIRECTONLY, openBlob)
}
func openBlob(ctx sqlite3.Context, arg ...sqlite3.Value) {
if len(arg) < 6 {
ctx.ResultError(util.ErrorString("blob_open: wrong number of arguments"))
return
}
row := arg[3].Int64()
var err error
blob, ok := ctx.GetAuxData(0).(*sqlite3.Blob)
if ok {
err = blob.Reopen(row)
if errors.Is(err, sqlite3.MISUSE) {
// Blob was closed (db, table, column or write changed).
ok = false
}
}
if !ok {
db := arg[0].Text()
table := arg[1].Text()
column := arg[2].Text()
write := arg[4].Bool()
blob, err = ctx.Conn().OpenBlob(db, table, column, row, write)
}
if err != nil {
ctx.ResultError(err)
return
}
fn := arg[5].Pointer().(OpenCallback)
err = fn(blob, arg[6:]...)
if err != nil {
ctx.ResultError(err)
return
}
// This ensures the blob is closed if db, table, column or write change.
ctx.SetAuxData(0, blob) // db
ctx.SetAuxData(1, blob) // table
ctx.SetAuxData(2, blob) // column
ctx.SetAuxData(4, blob) // write
}
// OpenCallback is the type for the blob_open callback.
type OpenCallback func(*sqlite3.Blob, ...sqlite3.Value) error

128
ext/blob/blob_test.go Normal file
View File

@@ -0,0 +1,128 @@
package blob_test
import (
"io"
"log"
"os"
"reflect"
"testing"
"github.com/ncruces/go-sqlite3"
"github.com/ncruces/go-sqlite3/driver"
_ "github.com/ncruces/go-sqlite3/embed"
"github.com/ncruces/go-sqlite3/ext/array"
"github.com/ncruces/go-sqlite3/ext/blob"
_ "github.com/ncruces/go-sqlite3/vfs/memdb"
)
func Example() {
// Open the database, registering the extension.
db, err := driver.Open("file:/test.db?vfs=memdb", func(conn *sqlite3.Conn) error {
blob.Register(conn)
return nil
})
if err != nil {
log.Fatal(err)
}
defer db.Close()
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS test (col)`)
if err != nil {
log.Fatal(err)
}
const message = "Hello BLOB!"
// Create the BLOB.
_, err = db.Exec(`INSERT INTO test VALUES (?)`, sqlite3.ZeroBlob(len(message)))
if err != nil {
log.Fatal(err)
}
// Write the BLOB.
_, err = db.Exec(`SELECT blob_open('main', 'test', 'col', last_insert_rowid(), true, ?)`,
sqlite3.Pointer[blob.OpenCallback](func(blob *sqlite3.Blob, _ ...sqlite3.Value) error {
_, err = io.WriteString(blob, message)
return err
}))
if err != nil {
log.Fatal(err)
}
// Read the BLOB.
_, err = db.Exec(`SELECT blob_open('main', 'test', 'col', rowid, false, ?) FROM test`,
sqlite3.Pointer[blob.OpenCallback](func(blob *sqlite3.Blob, _ ...sqlite3.Value) error {
_, err = io.Copy(os.Stdout, blob)
return err
}))
if err != nil {
log.Fatal(err)
}
// Output:
// Hello BLOB!
}
func TestRegister(t *testing.T) {
t.Parallel()
db, err := sqlite3.Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
blob.Register(db)
array.Register(db)
err = db.Exec(`SELECT blob_open()`)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
err = db.Exec(`
CREATE TABLE IF NOT EXISTS test1 (col);
CREATE TABLE IF NOT EXISTS test2 (col);
INSERT INTO test1 VALUES (x'cafe');
INSERT INTO test2 VALUES (x'babe');
`)
if err != nil {
t.Fatal(err)
}
stmt, _, err := db.Prepare(`SELECT blob_open('main', value, 'col', 1, false, ?) FROM array(?)`)
if err != nil {
t.Fatal(err)
}
defer stmt.Close()
var got []string
err = stmt.BindPointer(1, blob.OpenCallback(func(b *sqlite3.Blob, _ ...sqlite3.Value) error {
d, err := io.ReadAll(b)
if err != nil {
return err
}
got = append(got, string(d))
return nil
}))
if err != nil {
t.Fatal(err)
}
err = stmt.BindPointer(2, []string{"test1", "test2"})
if err != nil {
t.Fatal(err)
}
err = stmt.Exec()
if err != nil {
t.Fatal(err)
}
want := []string{"\xca\xfe", "\xba\xbe"}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
}

211
ext/csv/csv.go Normal file
View File

@@ -0,0 +1,211 @@
// Package csv provides a CSV virtual table.
//
// The CSV virtual table reads RFC 4180 formatted comma-separated values,
// and returns that content as if it were rows and columns of an SQL table.
//
// https://sqlite.org/csv.html
package csv
import (
"encoding/csv"
"fmt"
"io"
"math"
"os"
"strings"
"github.com/ncruces/go-sqlite3"
)
// Register registers the CSV virtual table.
// If a filename is specified, `os.Open` is used to read it from disk.
func Register(db *sqlite3.Conn) {
RegisterOpen(db, func(name string) (io.ReaderAt, error) {
return os.Open(name)
})
}
// RegisterOpen registers the CSV virtual table.
// If a filename is specified, open is used to open the file.
func RegisterOpen(db *sqlite3.Conn, open func(name string) (io.ReaderAt, error)) {
declare := func(db *sqlite3.Conn, _, _, _ string, arg ...string) (_ *table, err error) {
var (
filename string
data string
schema string
header bool
columns int = -1
comma rune = ','
done = map[string]struct{}{}
)
for _, arg := range arg {
key, val := getParam(arg)
if _, ok := done[key]; ok {
return nil, fmt.Errorf("csv: more than one %q parameter", key)
}
switch key {
case "filename":
filename = unquoteParam(val)
case "data":
data = unquoteParam(val)
case "schema":
schema = unquoteParam(val)
case "header":
header, err = boolParam(key, val)
case "columns":
columns, err = uintParam(key, val)
case "comma":
comma, err = runeParam(key, val)
default:
return nil, fmt.Errorf("csv: unknown %q parameter", key)
}
if err != nil {
return nil, err
}
done[key] = struct{}{}
}
if (filename == "") == (data == "") {
return nil, fmt.Errorf(`csv: must specify either "filename" or "data" but not both`)
}
var r io.ReaderAt
if filename != "" {
r, err = open(filename)
} else {
r = strings.NewReader(data)
}
if err != nil {
return nil, err
}
table := &table{
r: r,
comma: comma,
header: header,
bom: -1,
}
defer func() {
if err != nil {
table.Close()
}
}()
if schema == "" {
var row []string
if header || columns < 0 {
row, err = table.newReader().Read()
if err != nil {
return nil, err
}
}
schema = getSchema(header, columns, row)
}
err = db.DeclareVtab(schema)
if err != nil {
return nil, err
}
err = db.VtabConfig(sqlite3.VTAB_DIRECTONLY)
if err != nil {
return nil, err
}
return table, nil
}
sqlite3.CreateModule(db, "csv", declare, declare)
}
type table struct {
r io.ReaderAt
comma rune
header bool
bom int8
}
func (t *table) Close() error {
if c, ok := t.r.(io.Closer); ok {
err := c.Close()
t.r = nil
return err
}
return nil
}
func (t *table) BestIndex(idx *sqlite3.IndexInfo) error {
idx.EstimatedCost = 1e6
return nil
}
func (t *table) Open() (sqlite3.VTabCursor, error) {
return &cursor{table: t}, nil
}
func (t *table) Rename(new string) error {
return nil
}
func (t *table) Integrity(schema, table string, flags int) (err error) {
if flags&1 == 0 {
_, err = t.newReader().ReadAll()
}
return err
}
func (t *table) newReader() *csv.Reader {
if t.bom < 0 {
var bom [3]byte
t.r.ReadAt(bom[:], 0)
if string(bom[:]) == "\xEF\xBB\xBF" {
t.bom = 3
} else {
t.bom = 0
}
}
csv := csv.NewReader(io.NewSectionReader(t.r, int64(t.bom), math.MaxInt64))
csv.ReuseRecord = true
csv.Comma = t.comma
return csv
}
type cursor struct {
table *table
csv *csv.Reader
row []string
rowID int64
}
func (c *cursor) Filter(idxNum int, idxStr string, arg ...sqlite3.Value) error {
c.csv = c.table.newReader()
if c.table.header {
c.Next() // skip header
}
c.rowID = 0
return c.Next()
}
func (c *cursor) Next() (err error) {
c.rowID++
c.row, err = c.csv.Read()
if err != io.EOF {
return err
}
return nil
}
func (c *cursor) EOF() bool {
return c.row == nil
}
func (c *cursor) RowID() (int64, error) {
return c.rowID, nil
}
func (c *cursor) Column(ctx *sqlite3.Context, col int) error {
if col < len(c.row) {
ctx.ResultText(c.row[col])
}
return nil
}

155
ext/csv/csv_test.go Normal file
View File

@@ -0,0 +1,155 @@
package csv_test
import (
"fmt"
"log"
"testing"
"github.com/ncruces/go-sqlite3"
_ "github.com/ncruces/go-sqlite3/embed"
"github.com/ncruces/go-sqlite3/ext/csv"
)
func Example() {
db, err := sqlite3.Open(":memory:")
if err != nil {
log.Fatal(err)
}
defer db.Close()
csv.Register(db)
err = db.Exec(`
CREATE VIRTUAL TABLE IF NOT EXISTS eurofxref USING csv(
filename = 'testdata/eurofxref.csv',
header = YES,
columns = 42,
)`)
if err != nil {
log.Fatal(err)
}
stmt, _, err := db.Prepare(`SELECT USD FROM eurofxref WHERE Date = '2022-02-22'`)
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
if stmt.Step() {
fmt.Printf("On Twosday, 1€ = $%g", stmt.ColumnFloat(0))
}
if err := stmt.Reset(); err != nil {
log.Fatal(err)
}
err = db.Exec(`DROP TABLE eurofxref`)
if err != nil {
log.Fatal(err)
}
// Output:
// On Twosday, 1€ = $1.1342
}
func TestRegister(t *testing.T) {
t.Parallel()
db, err := sqlite3.Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
csv.Register(db)
const data = "\xEF\xBB\xBF" + `
"Rob" "Pike" rob
"Ken" Thompson ken
Robert "Griesemer" "gri"`
err = db.Exec(`
CREATE VIRTUAL TABLE temp.users USING csv(
data = ` + sqlite3.Quote(data) + `,
schema = 'CREATE TABLE x(first_name, last_name, username)',
comma = '\t'
)`)
if err != nil {
t.Fatal(err)
}
stmt, _, err := db.Prepare(`SELECT * FROM temp.users WHERE rowid = 1 ORDER BY username`)
if err != nil {
t.Fatal(err)
}
defer stmt.Close()
if !stmt.Step() {
t.Fatal("no rows")
}
if got := stmt.ColumnText(1); got != "Pike" {
t.Errorf("got %q want Pike", got)
}
if stmt.Step() {
t.Fatal("more rows")
}
err = db.Exec(`ALTER TABLE temp.users RENAME TO csv`)
if err != nil {
t.Fatal(err)
}
err = db.Exec(`PRAGMA integrity_check`)
if err != nil {
t.Fatal(err)
}
err = db.Exec(`DROP TABLE temp.csv`)
if err != nil {
log.Fatal(err)
}
}
func TestRegister_errors(t *testing.T) {
t.Parallel()
db, err := sqlite3.Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
csv.Register(db)
err = db.Exec(`CREATE VIRTUAL TABLE temp.users USING csv()`)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
err = db.Exec(`CREATE VIRTUAL TABLE temp.users USING csv(data='abc', data='abc')`)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
err = db.Exec(`CREATE VIRTUAL TABLE temp.users USING csv(data='abc', xpto='abc')`)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
err = db.Exec(`CREATE VIRTUAL TABLE temp.users USING csv(data='abc', comma='"')`)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
err = db.Exec(`CREATE VIRTUAL TABLE temp.users USING csv(data='abc', header=tru)`)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
}

65
ext/csv/params.go Normal file
View File

@@ -0,0 +1,65 @@
package csv
import (
"fmt"
"strconv"
"strings"
)
func getParam(arg string) (key, val string) {
key, val, _ = strings.Cut(arg, "=")
key = strings.TrimSpace(key)
val = strings.TrimSpace(val)
return
}
func uintParam(key, val string) (int, error) {
i, err := strconv.ParseUint(val, 10, 15)
if err != nil {
return 0, fmt.Errorf("csv: invalid %q parameter: %s", key, val)
}
return int(i), nil
}
func boolParam(key, val string) (bool, error) {
if val == "" || val == "1" ||
strings.EqualFold(val, "true") ||
strings.EqualFold(val, "yes") ||
strings.EqualFold(val, "on") {
return true, nil
}
if val == "0" ||
strings.EqualFold(val, "false") ||
strings.EqualFold(val, "no") ||
strings.EqualFold(val, "off") {
return false, nil
}
return false, fmt.Errorf("csv: invalid %q parameter: %s", key, val)
}
func runeParam(key, val string) (rune, error) {
r, _, tail, err := strconv.UnquoteChar(unquoteParam(val), 0)
if tail != "" || err != nil {
return 0, fmt.Errorf("csv: invalid %q parameter: %s", key, val)
}
return r, nil
}
func unquoteParam(val string) string {
if len(val) < 2 {
return val
}
if val[0] != val[len(val)-1] {
return val
}
var old, new string
switch val[0] {
default:
return val
case '"':
old, new = `""`, `"`
case '\'':
old, new = `''`, `'`
}
return strings.ReplaceAll(val[1:len(val)-1], old, new)
}

104
ext/csv/params_test.go Normal file
View File

@@ -0,0 +1,104 @@
package csv
import "testing"
func Test_uintParam(t *testing.T) {
t.Parallel()
tests := []struct {
arg string
key string
val int
err bool
}{
{"columns 1", "columns 1", 0, true},
{"columns = 1", "columns", 1, false},
{"columns\t= 2", "columns", 2, false},
{" columns = 3", "columns", 3, false},
{" columns = -1", "columns", 0, true},
{" columns = 32768", "columns", 0, true},
}
for _, tt := range tests {
t.Run(tt.arg, func(t *testing.T) {
key, val := getParam(tt.arg)
if key != tt.key {
t.Errorf("getParam() %v, want err %v", key, tt.key)
}
got, err := uintParam(key, val)
if (err != nil) != tt.err {
t.Fatalf("uintParam() error = %v, want err %v", err, tt.err)
}
if got != tt.val {
t.Errorf("uintParam() = %v, want %v", got, tt.val)
}
})
}
}
func Test_boolParam(t *testing.T) {
tests := []struct {
arg string
key string
val bool
err bool
}{
{"header", "header", true, false},
{"header\t= 1", "header", true, false},
{" header = 0", "header", false, false},
{" header = TrUe", "header", true, false},
{" header = FaLsE", "header", false, false},
{" header = Yes", "header", true, false},
{" header = nO", "header", false, false},
{" header = On", "header", true, false},
{" header = Off", "header", false, false},
{" header = T", "header", false, true},
{" header = f", "header", false, true},
}
for _, tt := range tests {
t.Run(tt.arg, func(t *testing.T) {
key, val := getParam(tt.arg)
if key != tt.key {
t.Errorf("getParam() %v, want err %v", key, tt.key)
}
got, err := boolParam(key, val)
if (err != nil) != tt.err {
t.Fatalf("boolParam() error = %v, want err %v", err, tt.err)
}
if got != tt.val {
t.Errorf("boolParam() = %v, want %v", got, tt.val)
}
})
}
}
func Test_runeParam(t *testing.T) {
tests := []struct {
arg string
key string
val rune
err bool
}{
{"comma", "comma", 0, true},
{"comma\t= ,", "comma", ',', false},
{" comma = ;", "comma", ';', false},
{" comma = ;;", "comma", 0, true},
{` comma = '\t`, "comma", 0, true},
{` comma = '\t'`, "comma", '\t', false},
{` comma = "\t"`, "comma", '\t', false},
}
for _, tt := range tests {
t.Run(tt.arg, func(t *testing.T) {
key, val := getParam(tt.arg)
if key != tt.key {
t.Errorf("getParam() %v, want err %v", key, tt.key)
}
got, err := runeParam(key, val)
if (err != nil) != tt.err {
t.Fatalf("runeParam() error = %v, want err %v", err, tt.err)
}
if got != tt.val {
t.Errorf("runeParam() = %v, want %v", got, tt.val)
}
})
}
}

39
ext/csv/schema.go Normal file
View File

@@ -0,0 +1,39 @@
package csv
import (
"strconv"
"strings"
"github.com/ncruces/go-sqlite3"
)
func getSchema(header bool, columns int, row []string) string {
var sep string
var str strings.Builder
str.WriteString("CREATE TABLE x(")
if 0 <= columns && columns < len(row) {
row = row[:columns]
}
for i, f := range row {
str.WriteString(sep)
if header && f != "" {
str.WriteString(sqlite3.QuoteIdentifier(f))
} else {
str.WriteString("c")
str.WriteString(strconv.Itoa(i + 1))
}
str.WriteString(" TEXT")
sep = ","
}
for i := len(row); i < columns; i++ {
str.WriteString(sep)
str.WriteString("c")
str.WriteString(strconv.Itoa(i + 1))
str.WriteString(" TEXT")
sep = ","
}
str.WriteByte(')')
return str.String()
}

28
ext/csv/schema_test.go Normal file
View File

@@ -0,0 +1,28 @@
package csv
import "testing"
func Test_getSchema(t *testing.T) {
t.Parallel()
tests := []struct {
header bool
columns int
row []string
want string
}{
{true, 2, nil, `CREATE TABLE x(c1 TEXT,c2 TEXT)`},
{false, 2, nil, `CREATE TABLE x(c1 TEXT,c2 TEXT)`},
{false, -1, []string{"abc", ""}, `CREATE TABLE x(c1 TEXT,c2 TEXT)`},
{true, 3, []string{"abc", ""}, `CREATE TABLE x("abc" TEXT,c2 TEXT,c3 TEXT)`},
{true, -1, []string{"abc", "def"}, `CREATE TABLE x("abc" TEXT,"def" TEXT)`},
{true, 1, []string{"abc", "def"}, `CREATE TABLE x("abc" TEXT)`},
}
for _, tt := range tests {
t.Run(tt.want, func(t *testing.T) {
if got := getSchema(tt.header, tt.columns, tt.row); got != tt.want {
t.Errorf("getSchema() = %v, want %v", got, tt.want)
}
})
}
}

258
ext/csv/testdata/eurofxref.csv vendored Normal file
View File

@@ -0,0 +1,258 @@
Date,USD,JPY,BGN,CYP,CZK,DKK,EEK,GBP,HUF,LTL,LVL,MTL,PLN,ROL,RON,SEK,SIT,SKK,CHF,ISK,NOK,HRK,RUB,TRL,TRY,AUD,BRL,CAD,CNY,HKD,IDR,ILS,INR,KRW,MXN,MYR,NZD,PHP,SGD,THB,ZAR,
2022-12-30,1.0666,140.66,1.9558,N/A,24.116,7.4365,N/A,0.88693,400.87,N/A,N/A,N/A,4.6808,N/A,4.9495,11.1218,N/A,N/A,0.9847,151.5,10.5138,7.5365,N/A,N/A,19.9649,1.5693,5.6386,1.444,7.3582,8.3163,16519.82,3.7554,88.171,1344.09,20.856,4.6984,1.6798,59.32,1.43,36.835,18.0986,
2022-12-29,1.0649,142.24,1.9558,N/A,24.191,7.4365,N/A,0.88549,399.6,N/A,N/A,N/A,4.6855,N/A,4.9493,11.158,N/A,N/A,0.984,152.5,10.55,7.5365,N/A,N/A,19.934,1.5859,5.5351,1.4475,7.4151,8.2994,16680.38,3.7575,88.2295,1350.18,20.651,4.7106,1.6887,59.367,1.436,36.877,18.1967,
2022-12-28,1.064,142.21,1.9558,N/A,24.252,7.4365,N/A,0.88058,403.3,N/A,N/A,N/A,4.7008,N/A,4.946,11.1038,N/A,N/A,0.9863,151.9,10.4495,7.5365,N/A,N/A,19.9144,1.566,5.6109,1.4361,7.4224,8.2931,16765.93,3.7526,88.0943,1348.59,20.6856,4.7055,1.6772,59.613,1.4323,36.953,18.289,
2022-12-27,1.0624,141.68,1.9558,N/A,24.26,7.4366,N/A,0.88333,401.65,N/A,N/A,N/A,4.6683,N/A,4.927,11.1285,N/A,N/A,0.9885,152.3,10.4895,7.5375,N/A,N/A,19.8799,1.577,5.6035,1.4384,7.3994,8.2874,16620.58,3.7278,88.0808,1349.85,20.5515,4.699,1.6916,59.356,1.43,36.775,18.3181,
2022-12-23,1.0622,140.86,1.9558,N/A,24.247,7.4364,N/A,0.8803,400.68,N/A,N/A,N/A,4.6423,N/A,4.9056,11.1045,N/A,N/A,0.9867,152.3,10.4448,7.537,N/A,N/A,19.843,1.5857,5.4834,1.4433,7.4198,8.2878,16569.18,3.704,87.958,1359.5,20.7115,4.7002,1.6887,58.623,1.4337,36.842,18.1048,
2022-12-22,1.0633,140.42,1.9558,N/A,24.215,7.4367,N/A,0.88243,402.13,N/A,N/A,N/A,4.6443,N/A,4.8993,11.05,N/A,N/A,0.9852,153.3,10.4123,7.538,N/A,N/A,19.8553,1.5804,5.5386,1.4484,7.4229,8.2883,16525.91,3.6942,88.0365,1361.75,20.8485,4.7051,1.6918,58.705,1.4356,36.849,18.2238,
2022-12-21,1.0636,140.29,1.9558,N/A,24.218,7.438,N/A,0.87651,402.93,N/A,N/A,N/A,4.6665,N/A,4.8937,11.0623,N/A,N/A,0.9836,152.1,10.4309,7.5419,N/A,N/A,19.8541,1.5859,5.4913,1.4475,7.4219,8.2902,16573.77,3.6989,88.109,1367.63,20.9919,4.7197,1.685,58.556,1.4366,36.907,18.3529,
2022-12-20,1.0599,140.58,1.9558,N/A,24.181,7.4388,N/A,0.8753,403.88,N/A,N/A,N/A,4.6757,N/A,4.9125,11.0615,N/A,N/A,0.9854,151.5,10.5098,7.5471,N/A,N/A,19.7744,1.5972,5.6234,1.4451,7.39,8.2488,16537.09,3.6759,87.6649,1363.73,20.9355,4.6991,1.6816,58.549,1.4347,36.853,18.4239,
2022-12-19,1.0598,144.65,1.9558,N/A,24.233,7.4382,N/A,0.87118,403.18,N/A,N/A,N/A,4.6853,N/A,4.9107,11.0063,N/A,N/A,0.9884,151.9,10.5025,7.5395,N/A,N/A,19.7676,1.5794,5.6327,1.4472,7.3901,8.2428,16506.72,3.6551,87.5321,1377.17,20.9743,4.6912,1.6632,58.649,1.4378,36.923,18.3074,
2022-12-16,1.0619,145.53,1.9558,N/A,24.262,7.4379,N/A,0.87233,407.1,N/A,N/A,N/A,4.6925,N/A,4.9213,11.0153,N/A,N/A,0.9879,150.1,10.4833,7.5385,N/A,N/A,19.8039,1.5866,5.6233,1.4506,7.4037,8.2632,16575.47,3.6689,87.824,1389.7,21.0634,4.6984,1.6687,58.967,1.4413,37.145,18.6708,
2022-12-15,1.0621,145.07,1.9558,N/A,24.27,7.4387,N/A,0.86194,406.4,N/A,N/A,N/A,4.689,N/A,4.922,10.898,N/A,N/A,0.9862,150.9,10.4013,7.5395,N/A,N/A,19.806,1.5695,5.6247,1.4443,7.4007,8.2551,16591.4,3.6388,87.9355,1393.97,20.9431,4.6918,1.6628,59.297,1.4406,37.12,18.3599,
2022-12-14,1.0649,143.68,1.9558,N/A,24.276,7.4392,N/A,0.86118,406.63,N/A,N/A,N/A,4.681,N/A,4.9248,10.8638,N/A,N/A,0.9865,150.9,10.362,7.538,N/A,N/A,19.8579,1.551,5.6842,1.4441,7.4009,8.2751,16599.51,3.6327,87.8435,1379.99,20.8635,4.6765,1.6508,59.326,1.4349,36.851,18.2563,
2022-12-13,1.0545,144.85,1.9558,N/A,24.287,7.4391,N/A,0.85753,409.65,N/A,N/A,N/A,4.6938,N/A,4.9298,10.8965,N/A,N/A,0.9869,151.1,10.4679,7.5495,N/A,N/A,19.6649,1.5553,5.5784,1.4341,7.3637,8.2033,16521.81,3.6266,87.2965,1378.75,20.9435,4.6704,1.6464,58.852,1.4288,36.707,18.6855,
2022-12-12,1.0562,144.86,1.9558,N/A,24.307,7.4379,N/A,0.86006,416.78,N/A,N/A,N/A,4.6923,N/A,4.9318,10.9075,N/A,N/A,0.9855,150.7,10.5548,7.554,N/A,N/A,19.6913,1.5625,5.556,1.4428,7.367,8.2103,16524.63,3.6232,87.253,1377.93,20.9047,4.6652,1.6523,58.788,1.4284,36.708,18.4697,
2022-12-09,1.0559,143.3,1.9558,N/A,24.293,7.4379,N/A,0.8595,417.53,N/A,N/A,N/A,4.6869,N/A,4.9224,10.9188,N/A,N/A,0.9856,149.5,10.5345,7.555,N/A,N/A,19.6872,1.5553,5.5457,1.438,7.3475,8.2169,16453.46,3.6128,86.9535,1373.94,20.849,4.6512,1.6482,58.47,1.426,36.656,18.2358,
2022-12-08,1.0519,143.75,1.9558,N/A,24.324,7.4382,N/A,0.86258,417.66,N/A,N/A,N/A,4.6853,N/A,4.9131,10.906,N/A,N/A,0.9889,149.5,10.488,7.5553,N/A,N/A,19.6114,1.559,5.488,1.4307,7.3324,8.1889,16423.92,3.6206,86.6755,1387.06,20.6989,4.6257,1.6547,58.233,1.4256,36.559,18.0225,
2022-12-07,1.0529,144.44,1.9558,N/A,24.322,7.4382,N/A,0.86408,410.63,N/A,N/A,N/A,4.7003,N/A,4.918,10.919,N/A,N/A,0.9893,148.7,10.5255,7.5525,N/A,N/A,19.6256,1.5728,5.5023,1.4387,7.3476,8.1997,16465.17,3.626,86.692,1390.87,20.7534,4.6301,1.6573,58.432,1.4286,36.904,18.1353,
2022-12-06,1.0516,143.33,1.9558,N/A,24.316,7.438,N/A,0.8617,415.08,N/A,N/A,N/A,4.6975,N/A,4.913,10.889,N/A,N/A,0.9872,148.9,10.4408,7.5563,N/A,N/A,19.601,1.5625,5.5113,1.4326,7.3494,8.1813,16441.49,3.5831,86.6485,1386.39,20.6884,4.6223,1.6583,58.782,1.4263,36.827,18.2068,
2022-12-05,1.0587,143.07,1.9558,N/A,24.351,7.4369,N/A,0.86085,412.13,N/A,N/A,N/A,4.695,N/A,4.9215,10.8931,N/A,N/A,0.9893,148.9,10.3366,7.551,N/A,N/A,19.7326,1.5542,5.5491,1.4198,7.3573,8.2236,16332.36,3.5856,86.5249,1370.87,20.7295,4.6255,1.6498,59.245,1.4271,36.732,18.2038,
2022-12-02,1.0538,141.32,1.9558,N/A,24.377,7.4373,N/A,0.85855,410,N/A,N/A,N/A,4.684,N/A,4.9298,10.902,N/A,N/A,0.9834,148.7,10.2615,7.5503,N/A,N/A,19.6392,1.5457,5.4657,1.416,7.3971,8.2035,16179.78,3.5769,85.6435,1366.67,20.187,4.6241,1.6453,58.734,1.4227,36.614,18.2749,
2022-12-01,1.0454,142.48,1.9558,N/A,24.361,7.4373,N/A,0.85715,413.5,N/A,N/A,N/A,4.6998,N/A,4.9303,10.8984,N/A,N/A,0.9868,148.7,10.2495,7.55,N/A,N/A,19.4778,1.5377,5.4508,1.4059,7.3965,8.1371,16160.84,3.5642,84.933,1363.81,20.1472,4.605,1.6446,58.793,1.4195,36.526,18.5393,
2022-11-30,1.0376,144.28,1.9558,N/A,24.338,7.4366,N/A,0.86488,408.4,N/A,N/A,N/A,4.6635,N/A,4.9245,10.9345,N/A,N/A,0.9854,147.1,10.2648,7.549,N/A,N/A,19.3333,1.5425,5.5063,1.4021,7.3437,8.0944,16271.81,3.5691,84.4215,1365.14,20.0111,4.6147,1.6634,58.697,1.418,36.588,17.5768,
2022-11-29,1.0366,143.36,1.9558,N/A,24.334,7.4367,N/A,0.86218,406.5,N/A,N/A,N/A,4.673,N/A,4.9193,10.901,N/A,N/A,0.9862,147.1,10.3313,7.55,N/A,N/A,19.3181,1.5414,5.5126,1.4005,7.4289,8.0965,16301.58,3.5581,84.6548,1375.7,19.8075,4.6735,1.6639,58.64,1.4237,36.706,17.6027,
2022-11-28,1.0463,144.9,1.9558,N/A,24.348,7.4367,N/A,0.86606,408.87,N/A,N/A,N/A,4.6938,N/A,4.9246,10.8973,N/A,N/A,0.9872,146.7,10.364,7.5488,N/A,N/A,19.4844,1.5632,5.6354,1.4062,7.5326,8.1782,16440.45,3.6002,85.437,1396.56,20.22,4.6874,1.6827,59.21,1.4375,37.285,17.9376,
2022-11-25,1.0375,144.62,1.9558,N/A,24.367,7.4365,N/A,0.85885,411.33,N/A,N/A,N/A,4.6875,N/A,4.9255,10.8183,N/A,N/A,0.9836,146.5,10.2985,7.5473,N/A,N/A,19.3333,1.5404,5.5476,1.3864,7.4425,8.1084,16282.44,3.5551,84.7145,1383.2,20.1069,4.648,1.6651,58.795,1.4277,37.153,17.7677,
2022-11-24,1.0413,143.9,1.9558,N/A,24.392,7.4369,N/A,0.85933,413.33,N/A,N/A,N/A,4.6958,N/A,4.9205,10.8573,N/A,N/A,0.9818,146.5,10.3435,7.547,N/A,N/A,19.3969,1.5414,5.5504,1.3894,7.4442,8.1324,16295.35,3.5607,85.0295,1382.28,20.1501,4.6806,1.6598,58.992,1.4319,37.258,17.7246,
2022-11-23,1.0325,145.75,1.9558,N/A,24.356,7.437,N/A,0.86369,405.75,N/A,N/A,N/A,4.7033,N/A,4.937,10.8933,N/A,N/A,0.9795,146.7,10.3659,7.5435,N/A,N/A,19.2316,1.5522,5.565,1.3856,7.3982,8.0708,16189.81,3.5681,84.466,1397.42,20.001,4.7237,1.6718,58.914,1.4295,37.423,17.7103,
2022-11-22,1.0274,145.2,1.9558,N/A,24.351,7.4377,N/A,0.86358,408.23,N/A,N/A,N/A,4.7125,N/A,4.9269,10.9653,N/A,N/A,0.9791,145.7,10.4445,7.5438,N/A,N/A,19.1221,1.5473,5.4578,1.3765,7.3344,8.0313,16106.79,3.5615,83.8768,1392.68,20.0951,4.7055,1.6707,58.942,1.4167,37.11,17.7568,
2022-11-21,1.0246,145.33,1.9558,N/A,24.356,7.4377,N/A,0.86793,409.43,N/A,N/A,N/A,4.7075,N/A,4.9413,10.9873,N/A,N/A,0.9817,147.9,10.4898,7.5425,N/A,N/A,19.0822,1.5471,5.4401,1.377,7.3419,7.9989,16116.76,3.5515,83.7375,1395,19.9357,4.6927,1.6766,58.822,1.4162,37.121,17.7858,
2022-11-18,1.0366,145.12,1.9558,N/A,24.351,7.4385,N/A,0.87063,407.41,N/A,N/A,N/A,4.7033,N/A,4.9413,10.9805,N/A,N/A,0.9881,148.9,10.486,7.5415,N/A,N/A,19.3009,1.5433,5.547,1.3841,7.379,8.1092,16224.36,3.591,84.6875,1389.02,20.162,4.7202,1.6757,59.41,1.4229,37.069,17.908,
2022-11-17,1.0319,144.8,1.9558,N/A,24.399,7.4383,N/A,0.87475,415.6,N/A,N/A,N/A,4.7153,N/A,4.9254,10.9871,N/A,N/A,0.9818,148.9,10.498,7.541,N/A,N/A,19.2124,1.5526,5.6535,1.382,7.3859,8.077,16224.01,3.5796,84.394,1394.06,20.062,4.7122,1.6986,59.293,1.4221,37.123,18.0961,
2022-11-16,1.0412,145.29,1.9558,N/A,24.355,7.4386,N/A,0.87483,408.18,N/A,N/A,N/A,4.7065,N/A,4.9206,10.8754,N/A,N/A,0.9795,148.9,10.3675,7.5443,N/A,N/A,19.3783,1.54,5.5438,1.3801,7.372,8.1444,16248.37,3.5684,84.5905,1378.1,20.1227,4.7323,1.6897,59.678,1.425,37.103,18.0195,
2022-11-15,1.0404,144.84,1.9558,N/A,24.326,7.4388,N/A,0.87455,405.45,N/A,N/A,N/A,4.7073,N/A,4.9116,10.8081,N/A,N/A,0.979,149.9,10.357,7.5459,N/A,N/A,19.3608,1.5415,5.548,1.3816,7.3299,8.143,16164.78,3.5694,84.1304,1365.61,20.0795,4.7208,1.6897,59.532,1.4238,36.939,17.8822,
2022-11-14,1.0319,144.86,1.9558,N/A,24.289,7.4382,N/A,0.87513,407.28,N/A,N/A,N/A,4.6898,N/A,4.9043,10.7713,N/A,N/A,0.9751,150.3,10.3143,7.5465,N/A,N/A,19.1923,1.5427,5.4605,1.3706,7.2906,8.0852,16052.12,3.541,83.7779,1369.32,20.0985,4.7429,1.6957,59.04,1.4177,36.978,17.8393,
2022-11-11,1.0308,143.89,1.9558,N/A,24.278,7.4384,N/A,0.87538,402.08,N/A,N/A,N/A,4.6765,N/A,4.894,10.7241,N/A,N/A,0.9844,148.7,10.2635,7.5445,N/A,N/A,19.0987,1.5459,5.5147,1.3698,7.3267,8.0758,15979.45,3.5255,83.2253,1359.2,20.0239,4.77,1.702,59.106,1.4199,37.088,17.7944,
2022-11-10,0.9954,145.47,1.9558,N/A,24.361,7.4381,N/A,0.87298,400.95,N/A,N/A,N/A,4.706,N/A,4.8913,10.8743,N/A,N/A,0.9834,147.5,10.3615,7.5427,N/A,N/A,18.51,1.5525,5.286,1.3467,7.2184,7.8128,15615.6,3.5453,81.3058,1373.96,19.4562,4.6789,1.6984,57.793,1.3963,36.7,17.6882,
2022-11-09,1.0039,146.82,1.9558,N/A,24.337,7.4382,N/A,0.87774,403.53,N/A,N/A,N/A,4.701,N/A,4.9045,10.845,N/A,N/A,0.988,146.7,10.322,7.5425,N/A,N/A,18.6728,1.5538,5.1947,1.3501,7.2813,7.8801,15717.07,3.5621,81.6575,1369.73,19.6554,4.7098,1.7033,58.236,1.4061,36.999,17.877,
2022-11-08,0.9996,146.25,1.9558,N/A,24.326,7.4378,N/A,0.87378,400.75,N/A,N/A,N/A,4.6918,N/A,4.8978,10.8373,N/A,N/A,0.9911,146.3,10.2795,7.539,N/A,N/A,18.5991,1.5435,5.203,1.3489,7.2495,7.8468,15652.76,3.5436,81.518,1377.94,19.4495,4.7346,1.686,58.187,1.4022,37.22,17.8397,
2022-11-07,0.9993,146.18,1.9558,N/A,24.301,7.4393,N/A,0.87135,401.03,N/A,N/A,N/A,4.6865,N/A,4.8855,10.832,N/A,N/A,0.9874,145.9,10.2555,7.5375,N/A,N/A,18.5875,1.5428,5.07,1.3464,7.2189,7.8444,15648.95,3.5402,81.8407,1391.25,19.4395,4.7362,1.6834,58.361,1.4022,37.284,17.7583,
2022-11-04,0.9872,145.19,1.9558,N/A,24.422,7.4419,N/A,0.87478,401.15,N/A,N/A,N/A,4.6825,N/A,4.8893,10.8538,N/A,N/A,0.9863,145.5,10.2019,7.5353,N/A,N/A,18.3845,1.5311,4.9682,1.3351,7.0894,7.7493,15491.81,3.5065,81.02,1397.7,19.2611,4.6872,1.6769,57.672,1.3891,36.906,17.7983,
2022-11-03,0.9753,144.58,1.9558,N/A,24.539,7.4433,N/A,0.87228,407.87,N/A,N/A,N/A,4.709,N/A,4.9013,10.932,N/A,N/A,0.9889,144.9,10.3543,7.5375,N/A,N/A,18.1602,1.5517,5.0262,1.3452,7.1367,7.656,15400.2,3.4847,80.8845,1391.75,19.2363,4.6271,1.6957,57.463,1.3878,37.091,18.0173,
2022-11-02,0.9908,145.75,1.9558,N/A,24.506,7.4431,N/A,0.861,407,N/A,N/A,N/A,4.7035,N/A,4.912,10.9065,N/A,N/A,0.9861,143.7,10.2388,7.5335,N/A,N/A,18.4488,1.5426,5.0964,1.347,7.2156,7.7774,15492.57,3.4987,81.992,1402.01,19.4921,4.6944,1.6844,57.841,1.3983,37.314,17.9608,
2022-11-01,0.9947,146.35,1.9558,N/A,24.484,7.4438,N/A,0.86058,406.9,N/A,N/A,N/A,4.7053,N/A,4.9138,10.874,N/A,N/A,0.9878,143.3,10.1835,7.5342,N/A,N/A,18.5216,1.5409,5.1337,1.3469,7.2165,7.8079,15534.6,3.4922,82.084,1404.63,19.5984,4.7119,1.6876,57.786,1.4017,37.45,17.9802,
2022-10-31,0.9914,147.4,1.9558,N/A,24.488,7.4444,N/A,0.86115,409.65,N/A,N/A,N/A,4.7085,N/A,4.9143,10.901,N/A,N/A,0.9925,143.3,10.3028,7.531,N/A,N/A,18.4562,1.5529,5.2694,1.3553,7.238,7.7822,15489.55,3.4933,82.1035,1416.12,19.7122,4.6873,1.7099,57.8,1.4038,37.748,18.1736,
2022-10-28,0.9951,146.79,1.9558,N/A,24.465,7.4423,N/A,0.8612,411.7,N/A,N/A,N/A,4.7275,N/A,4.9189,10.9403,N/A,N/A,0.992,143.3,10.2695,7.532,N/A,N/A,18.5219,1.5511,5.327,1.3542,7.2159,7.8107,15481.88,3.5215,82.0565,1417.7,19.7718,4.6994,1.7151,57.739,1.4055,37.724,18.053,
2022-10-27,1.0037,147.37,1.9558,N/A,24.53,7.4387,N/A,0.86745,412.15,N/A,N/A,N/A,4.7585,N/A,4.8893,10.9583,N/A,N/A,0.9949,143.1,10.342,7.533,N/A,N/A,18.681,1.561,5.3889,1.3672,7.2552,7.8782,15629.06,3.5376,82.656,1428.57,20.015,4.7324,1.7316,58.441,1.4154,37.975,18.1521,
2022-10-26,1.0023,147.32,1.9558,N/A,24.535,7.4381,N/A,0.86603,408.09,N/A,N/A,N/A,4.7548,N/A,4.8806,10.953,N/A,N/A,0.9917,143.5,10.3408,7.532,N/A,N/A,18.6461,1.5466,5.2944,1.3568,7.1948,7.8678,15589.27,3.5145,82.206,1422.11,19.8501,4.7262,1.7249,58.493,1.4104,37.862,18.0212,
2022-10-25,0.9861,146.84,1.9558,N/A,24.472,7.4387,N/A,0.87143,413.7,N/A,N/A,N/A,4.777,N/A,4.9036,10.9728,N/A,N/A,0.9888,142.9,10.391,7.5315,N/A,N/A,18.3508,1.5599,5.2254,1.3537,7.2072,7.7407,15407.12,3.506,81.653,1417.5,19.6353,4.6697,1.7321,57.988,1.405,37.758,18.2211,
2022-10-24,0.9851,146.76,1.9558,N/A,24.482,7.4385,N/A,0.8707,411.88,N/A,N/A,N/A,4.7908,N/A,4.9128,11.0795,N/A,N/A,0.9856,142.5,10.392,7.5337,N/A,N/A,18.3298,1.5631,5.1461,1.3502,7.1544,7.7329,15362.63,3.4997,81.5451,1418.4,19.6514,4.6674,1.7343,58.021,1.4008,37.6,18.0625,
2022-10-21,0.973,147.59,1.9558,N/A,24.511,7.4382,N/A,0.87728,412.88,N/A,N/A,N/A,4.7885,N/A,4.9125,11.0868,N/A,N/A,0.9855,141.1,10.4315,7.5325,N/A,N/A,18.0988,1.5646,5.1117,1.3465,7.0504,7.6376,15199.12,3.4803,80.739,1404.32,19.5521,4.6101,1.7347,57.287,1.3917,37.349,18.0021,
2022-10-20,0.9811,146.99,1.9558,N/A,24.525,7.4389,N/A,0.87258,411.2,N/A,N/A,N/A,4.7728,N/A,4.9203,10.982,N/A,N/A,0.9836,141.1,10.402,7.5353,N/A,N/A,18.2257,1.5554,5.1387,1.3461,7.0858,7.7008,15250.05,3.4754,81.1755,1400.3,19.7005,4.6396,1.7206,57.742,1.3959,37.36,17.9106,
2022-10-19,0.9778,146.34,1.9558,N/A,24.563,7.439,N/A,0.86993,413.78,N/A,N/A,N/A,4.7878,N/A,4.9248,10.9448,N/A,N/A,0.981,141.1,10.3823,7.5325,N/A,N/A,18.1793,1.5568,5.1755,1.3479,7.0672,7.6757,15185.1,3.4628,81.1955,1398.35,19.6845,4.6152,1.7264,57.741,1.3931,37.469,17.8339,
2022-10-18,0.9835,146.65,1.9558,N/A,24.593,7.4393,N/A,0.86928,413.08,N/A,N/A,N/A,4.804,N/A,4.9359,10.906,N/A,N/A,0.9792,141.5,10.3528,7.5298,N/A,N/A,18.2813,1.5557,5.1795,1.3495,7.0805,7.72,15214.98,3.464,80.9195,1400.92,19.664,4.6382,1.7251,57.897,1.3963,37.422,17.7904,
2022-10-17,0.9739,145,1.9558,N/A,24.562,7.4379,N/A,0.8625,418.3,N/A,N/A,N/A,4.8143,N/A,4.937,10.9893,N/A,N/A,0.9762,140.9,10.342,7.5265,N/A,N/A,18.1043,1.5599,5.1497,1.3452,7.013,7.6448,15061.8,3.4486,80.128,1399.41,19.5,4.5934,1.7404,57.433,1.3896,37.169,17.6769,
2022-10-14,0.9717,143.63,1.9558,N/A,24.587,7.4378,N/A,0.86823,418.24,N/A,N/A,N/A,4.8328,N/A,4.9335,11.0035,N/A,N/A,0.9757,140.5,10.3323,7.5266,N/A,N/A,18.0614,1.5493,5.1177,1.3426,6.9952,7.6278,15031.5,3.444,79.9695,1398.5,19.5032,4.5689,1.7302,57.375,1.3852,37.109,17.6932,
2022-10-13,0.9739,142.94,1.9558,N/A,24.569,7.4385,N/A,0.86513,430.65,N/A,N/A,N/A,4.8303,N/A,4.9355,11.0098,N/A,N/A,0.9725,140.5,10.3525,7.531,N/A,N/A,18.1041,1.5495,5.1214,1.3443,6.9945,7.644,14952.86,3.4731,79.9981,1392.71,19.4442,4.5691,1.7314,57.352,1.3949,36.843,17.8173,
2022-10-12,0.9706,142.34,1.9558,N/A,24.561,7.4399,N/A,0.8784,429.65,N/A,N/A,N/A,4.8495,N/A,4.94,11.02,N/A,N/A,0.9664,140.1,10.4145,7.529,N/A,N/A,18.0427,1.5525,5.1378,1.3395,6.9603,7.6192,14907.04,3.4623,79.8955,1384.66,19.4522,4.5448,1.7372,57.148,1.3941,36.902,17.6876,
2022-10-11,0.9723,141.54,1.9558,N/A,24.535,7.439,N/A,0.87703,428.73,N/A,N/A,N/A,4.869,N/A,4.9394,11.0015,N/A,N/A,0.9675,140.7,10.4235,7.5293,N/A,N/A,18.0686,1.545,5.0456,1.3402,6.9669,7.6325,14930.83,3.4776,79.9555,1392.84,19.4115,4.5436,1.7323,57.243,1.3967,37.03,17.6153,
2022-10-10,0.9697,141.16,1.9558,N/A,24.521,7.4384,N/A,0.8773,428.2,N/A,N/A,N/A,4.8655,N/A,4.94,10.9502,N/A,N/A,0.968,139.9,10.3378,7.528,N/A,N/A,18.0131,1.536,5.0328,1.3312,6.9344,7.612,14872.51,3.4463,79.9678,1384.26,19.3588,4.5091,1.7369,57.197,1.3939,36.81,17.5866,
2022-10-07,0.9797,141.92,1.9558,N/A,24.517,7.4381,N/A,0.87383,423.85,N/A,N/A,N/A,4.8595,N/A,4.9415,10.8555,N/A,N/A,0.97,140.7,10.4498,7.527,N/A,N/A,18.209,1.5266,5.1075,1.3437,6.9715,7.6906,14933.14,3.4477,80.546,1381.42,19.643,4.5556,1.7328,57.747,1.3996,36.602,17.6222,
2022-10-06,0.986,142.68,1.9558,N/A,24.479,7.439,N/A,0.87583,422.59,N/A,N/A,N/A,4.8505,N/A,4.9364,10.8728,N/A,N/A,0.9709,139.9,10.4278,7.5288,N/A,N/A,18.3191,1.5263,5.1185,1.3475,7.0164,7.74,15021.24,3.4846,81.0615,1388.39,19.817,4.5726,1.728,57.949,1.4057,36.827,17.5769,
2022-10-05,0.9915,143.18,1.9558,N/A,24.524,7.4388,N/A,0.8734,423.6,N/A,N/A,N/A,4.791,N/A,4.9385,10.8376,N/A,N/A,0.9756,141.3,10.4858,7.5255,N/A,N/A,18.4201,1.538,5.1575,1.3493,7.0555,7.7831,15061.81,3.503,80.909,1406.71,19.8625,4.5911,1.7419,58.212,1.4124,37.102,17.6228,
2022-10-04,0.9891,143.3,1.9558,N/A,24.544,7.4374,N/A,0.87273,417.68,N/A,N/A,N/A,4.8193,N/A,4.9418,10.8166,N/A,N/A,0.9767,141.9,10.4915,7.523,N/A,N/A,18.3374,1.5318,5.0589,1.3503,7.0384,7.7644,15080.18,3.4885,80.6995,1412.2,19.777,4.5939,1.7368,58.104,1.4148,37.16,17.5437,
2022-10-03,0.9764,141.49,1.9558,N/A,24.527,7.4366,N/A,0.8707,424.86,N/A,N/A,N/A,4.832,N/A,4.9479,10.8743,N/A,N/A,0.9658,141.7,10.5655,7.5275,N/A,N/A,18.124,1.5128,5.178,1.3412,6.9481,7.6647,14969.79,3.498,79.898,1408.25,19.604,4.5383,1.7263,57.599,1.4015,37.181,17.5871,
2022-09-30,0.9748,141.01,1.9558,N/A,24.549,7.4365,N/A,0.883,422.18,N/A,N/A,N/A,4.8483,N/A,4.949,10.8993,N/A,N/A,0.9561,140.9,10.5838,7.524,N/A,N/A,18.0841,1.5076,5.2584,1.3401,6.9368,7.6521,14863.26,3.4759,79.425,1400.69,19.6393,4.5201,1.7177,57.276,1.4001,36.823,17.5353,
2022-09-29,0.9706,140.46,1.9558,N/A,24.687,7.4365,N/A,0.89485,421.93,N/A,N/A,N/A,4.857,N/A,4.9481,10.958,N/A,N/A,0.9538,140.1,10.4518,7.528,N/A,N/A,18,1.4982,5.2521,1.3294,6.9223,7.6192,14735.97,3.4422,79.314,1388.34,19.5779,4.4992,1.704,56.86,1.3961,36.946,17.4466,
2022-09-28,0.9565,138.39,1.9558,N/A,24.65,7.4368,N/A,0.90268,411.72,N/A,N/A,N/A,4.8043,N/A,4.9485,10.9194,N/A,N/A,0.9437,139.7,10.4576,7.5313,N/A,N/A,17.7311,1.4924,5.1728,1.3157,6.9199,7.5084,14622.96,3.3931,78.2655,1378.84,19.5294,4.4281,1.6998,56.528,1.3846,36.687,17.2916,
2022-09-27,0.9644,139.28,1.9558,N/A,24.661,7.4366,N/A,0.89275,406.65,N/A,N/A,N/A,4.764,N/A,4.9444,10.8533,N/A,N/A,0.9503,139.3,10.3473,7.528,N/A,N/A,17.824,1.4859,5.1235,1.3196,6.9156,7.5704,14604.52,3.3714,78.574,1370.06,19.5832,4.4466,1.6921,56.933,1.3838,36.565,17.2361,
2022-09-26,0.9646,139.07,1.9558,N/A,24.64,7.4365,N/A,0.89404,408.83,N/A,N/A,N/A,4.7608,N/A,4.9418,10.9275,N/A,N/A,0.9555,138.9,10.3585,7.5278,N/A,N/A,17.8001,1.4858,5.1504,1.3195,6.9075,7.572,14620.74,3.4069,78.704,1379.4,19.6066,4.4401,1.6886,56.908,1.3842,36.496,17.4247,
2022-09-23,0.9754,139.43,1.9558,N/A,24.658,7.4365,N/A,0.88201,406.3,N/A,N/A,N/A,4.7543,N/A,4.9433,10.9328,N/A,N/A,0.9565,139.9,10.2335,7.5228,N/A,N/A,17.9515,1.4828,5.0456,1.3177,6.9442,7.6567,14697.3,3.4152,79.0705,1381.97,19.5708,4.4659,1.6846,57.217,1.3897,36.636,17.3853,
2022-09-22,0.9884,139.18,1.9558,N/A,24.657,7.4365,N/A,0.87256,405.25,N/A,N/A,N/A,4.7592,N/A,4.9411,10.8724,N/A,N/A,0.9684,139.9,10.235,7.5235,N/A,N/A,18.1559,1.484,5.0677,1.3278,6.9804,7.7583,14824.28,3.4216,79.897,1384.79,19.6129,4.514,1.6832,57.721,1.3998,36.803,17.3514,
2022-09-21,0.9906,142.66,1.9558,N/A,24.637,7.4364,N/A,0.87335,405.1,N/A,N/A,N/A,4.7505,N/A,4.9443,10.9214,N/A,N/A,0.9549,140.3,10.2858,7.5205,N/A,N/A,18.149,1.4851,5.0924,1.3262,6.9821,7.7761,14866.28,3.4298,79.1555,1381.38,19.7847,4.5097,1.6844,57.285,1.4006,36.786,17.4879,
2022-09-20,0.9986,143.34,1.9558,N/A,24.556,7.4368,N/A,0.87395,398.58,N/A,N/A,N/A,4.7208,N/A,4.934,10.8338,N/A,N/A,0.9644,140.9,10.273,7.5198,N/A,N/A,18.2833,1.4893,5.2139,1.3268,7.003,7.8382,14997.82,3.4406,79.6095,1390.71,19.9667,4.5516,1.6908,57.497,1.4074,36.968,17.7261,
2022-09-19,0.999,143.42,1.9558,N/A,24.494,7.4373,N/A,0.87785,400.85,N/A,N/A,N/A,4.7058,N/A,4.93,10.7993,N/A,N/A,0.9658,139.9,10.2826,7.5215,N/A,N/A,18.2738,1.495,5.2886,1.3294,7.0066,7.8416,14975.43,3.446,79.653,1391.82,20.113,4.5455,1.6807,57.347,1.4082,36.983,17.7267,
2022-09-16,0.9954,142.53,1.9558,N/A,24.497,7.4366,N/A,0.874,403.98,N/A,N/A,N/A,4.7143,N/A,4.9238,10.7541,N/A,N/A,0.9579,138.3,10.1985,7.5235,N/A,N/A,18.1923,1.4894,5.2279,1.3226,6.9787,7.8133,14904.67,3.4267,79.3605,1383.58,20.0028,4.5141,1.6717,57.111,1.4025,36.8,17.6004,
2022-09-15,0.9992,143.43,1.9558,N/A,24.518,7.4366,N/A,0.86934,407.15,N/A,N/A,N/A,4.7273,N/A,4.9238,10.69,N/A,N/A,0.9572,138.7,10.1203,7.5258,N/A,N/A,18.2477,1.4853,5.1837,1.3172,6.9852,7.8423,14925.35,3.4384,79.7119,1397.18,20.0021,4.5314,1.6689,57.258,1.4062,36.816,17.5283,
2022-09-14,0.999,143.08,1.9558,N/A,24.527,7.4366,N/A,0.86498,402.9,N/A,N/A,N/A,4.7163,N/A,4.9297,10.675,N/A,N/A,0.9612,139.7,10.1125,7.5195,N/A,N/A,18.2397,1.4873,5.1827,1.3177,6.955,7.8405,14903.93,3.4339,79.422,1391.97,20.028,4.5225,1.6675,57.054,1.4039,36.608,17.4342,
2022-09-13,1.0175,144.5,1.9558,N/A,24.551,7.4366,N/A,0.86793,396.83,N/A,N/A,N/A,4.705,N/A,4.921,10.6108,N/A,N/A,0.9669,140.1,9.9988,7.5255,N/A,N/A,18.564,1.4736,5.1764,1.32,7.0467,7.9855,15099.17,3.4125,80.5453,1397.3,20.1615,4.5869,1.6555,57.665,1.4186,36.859,17.3112,
2022-09-12,1.0155,144.49,1.9558,N/A,24.546,7.4365,N/A,0.86778,395.73,N/A,N/A,N/A,4.6965,N/A,4.9135,10.6368,N/A,N/A,0.9667,140.9,9.9718,7.5195,N/A,N/A,18.5232,1.4749,5.1933,1.3194,7.0348,7.9709,15083.83,3.4346,80.692,1397.58,20.1025,4.5733,1.6499,57.701,1.4168,36.873,17.322,
2022-09-09,1.0049,143.3,1.9558,N/A,24.536,7.4365,N/A,0.8686,396.3,N/A,N/A,N/A,4.721,N/A,4.9019,10.6643,N/A,N/A,0.9657,140.9,9.9836,7.5245,N/A,N/A,18.3282,1.4704,5.2087,1.307,6.9543,7.8871,14905.33,3.4416,79.9685,1384.64,19.991,4.52,1.6463,57.098,1.4063,36.508,17.3753,
2022-09-08,1.0009,143.65,1.9558,N/A,24.543,7.4365,N/A,0.86656,395.48,N/A,N/A,N/A,4.7155,N/A,4.8756,10.7075,N/A,N/A,0.9739,140.3,10.0615,7.515,N/A,N/A,18.2546,1.4824,5.2042,1.3134,6.9564,7.8568,14891.86,3.429,79.7375,1381.7,20.013,4.5051,1.6491,57.031,1.4054,36.418,17.3797,
2022-09-07,0.9885,143.2,1.9558,N/A,24.631,7.4365,N/A,0.8651,401.83,N/A,N/A,N/A,4.729,N/A,4.8585,10.6888,N/A,N/A,0.975,141.3,9.9483,7.5143,N/A,N/A,18.0262,1.4748,5.1881,1.3037,6.8968,7.7596,14779.47,3.4053,79.028,1374.44,19.9225,4.4497,1.6459,56.532,1.3931,36.322,17.2582,
2022-09-06,0.9928,140.91,1.9558,N/A,24.55,7.4365,N/A,0.85743,402.65,N/A,N/A,N/A,4.7068,N/A,4.8424,10.6825,N/A,N/A,0.9745,141.9,9.8945,7.5133,N/A,N/A,18.0938,1.4651,5.13,1.3029,6.9091,7.7932,14783.94,3.39,79.2305,1366.65,19.8545,4.4676,1.6313,56.655,1.3947,36.242,17.0805,
2022-09-05,0.992,139.47,1.9558,N/A,24.622,7.4364,N/A,0.86358,403.9,N/A,N/A,N/A,4.736,N/A,4.8198,10.729,N/A,N/A,0.9747,142.7,9.9188,7.5173,N/A,N/A,18.0792,1.4616,5.1407,1.3043,6.8768,7.7867,14782.83,3.3826,79.2332,1359.98,19.8192,4.4563,1.6289,56.477,1.3932,36.263,17.088,
2022-09-02,0.9993,140.36,1.9558,N/A,24.481,7.437,N/A,0.86478,398.38,N/A,N/A,N/A,4.7063,N/A,4.8335,10.7498,N/A,N/A,0.9839,141.5,10.0035,7.5225,N/A,N/A,18.2072,1.4671,5.2153,1.3131,6.9031,7.8439,14895.92,3.396,79.8096,1360.84,20.1024,4.4809,1.6394,56.854,1.4013,36.624,17.2791,
2022-09-01,1.0004,139.34,1.9558,N/A,24.488,7.4372,N/A,0.86473,399.58,N/A,N/A,N/A,4.7128,N/A,4.8447,10.7415,N/A,N/A,0.9802,141.7,10.013,7.521,N/A,N/A,18.2149,1.4651,5.2239,1.3169,6.9017,7.8511,14878,3.3644,79.6195,1353.69,20.1954,4.4828,1.6389,56.609,1.4002,36.71,17.1524,
2022-08-31,1,138.72,1.9558,N/A,24.55,7.4371,N/A,0.86035,402.8,N/A,N/A,N/A,4.7283,N/A,4.8595,10.6788,N/A,N/A,0.9796,141.7,9.9388,7.5148,N/A,N/A,18.1849,1.4591,5.1482,1.3111,6.8947,7.8488,14849.93,3.3399,79.5465,1342.79,20.2044,4.4755,1.6322,56.153,1.3969,36.45,17.0667,
2022-08-30,1.0034,138.71,1.9558,N/A,24.577,7.4376,N/A,0.85645,406.38,N/A,N/A,N/A,4.7323,N/A,4.8657,10.65,N/A,N/A,0.9741,142.1,9.7553,7.5103,N/A,N/A,18.239,1.4472,5.0286,1.3047,6.9233,7.8751,14875,3.3168,79.8025,1350.92,20.0077,4.4907,1.6245,56.393,1.3997,36.494,16.8567,
2022-08-29,0.9986,138.49,1.9558,N/A,24.592,7.4379,N/A,0.8542,409.9,N/A,N/A,N/A,4.745,N/A,4.8699,10.628,N/A,N/A,0.967,141.1,9.7675,7.5119,N/A,N/A,18.1605,1.4529,5.0663,1.3026,6.9044,7.8368,14871.09,3.3146,79.8295,1347.47,19.9876,4.4837,1.6305,56.187,1.395,36.399,16.8891,
2022-08-26,1.0007,137.02,1.9558,N/A,24.635,7.4379,N/A,0.8459,410.48,N/A,N/A,N/A,4.7485,N/A,4.8729,10.5703,N/A,N/A,0.9642,140.3,9.667,7.5135,N/A,N/A,18.1923,1.4333,5.1069,1.2944,6.8671,7.8521,14825.57,3.2537,79.9025,1333.46,19.924,4.4706,1.6112,56.109,1.3906,36.035,16.7995,
2022-08-25,0.997,136.07,1.9558,N/A,24.648,7.4374,N/A,0.84293,408.93,N/A,N/A,N/A,4.7578,N/A,4.8758,10.5525,N/A,N/A,0.9616,140.3,9.64,7.514,N/A,N/A,18.112,1.4306,5.0879,1.2881,6.8317,7.8234,14753.15,3.2791,79.6555,1331.98,19.8132,4.4586,1.6006,55.842,1.3857,35.732,16.7903,
2022-08-24,0.9934,135.74,1.9558,N/A,24.629,7.4381,N/A,0.84283,410.93,N/A,N/A,N/A,4.7668,N/A,4.88,10.586,N/A,N/A,0.9576,139.5,9.636,7.5125,N/A,N/A,18.0362,1.4389,5.0606,1.2908,6.822,7.795,14757.6,3.2599,79.3006,1332.84,19.7781,4.4559,1.6065,55.7,1.3857,35.906,16.8976,
2022-08-23,0.9927,136.34,1.9558,N/A,24.658,7.4374,N/A,0.84343,410.55,N/A,N/A,N/A,4.7788,N/A,4.8839,10.6063,N/A,N/A,0.9602,140.1,9.7438,7.5128,N/A,N/A,17.983,1.4437,5.0984,1.2928,6.7952,7.79,14743.28,3.2598,79.2805,1332.1,19.9152,4.4557,1.6071,55.661,1.386,35.856,16.9568,
2022-08-22,1.0001,137.08,1.9558,N/A,24.651,7.437,N/A,0.84658,408,N/A,N/A,N/A,4.764,N/A,4.8853,10.65,N/A,N/A,0.958,140.9,9.7719,7.5113,N/A,N/A,18.1268,1.4478,5.1752,1.2989,6.8457,7.8468,14895.47,3.2778,79.8615,1344.21,20.1583,4.4854,1.6125,56.218,1.3958,36.099,17.0766,
2022-08-19,1.0054,137.67,1.9558,N/A,24.625,7.4373,N/A,0.84938,407.35,N/A,N/A,N/A,4.751,N/A,4.8811,10.6095,N/A,N/A,0.9616,140.5,9.8418,7.5155,N/A,N/A,18.2028,1.4584,5.2334,1.3062,6.8531,7.8877,14951.91,3.2879,80.2988,1343.39,20.3273,4.5007,1.6203,56.325,1.3979,35.988,17.1007,
2022-08-18,1.0178,137.17,1.9558,N/A,24.611,7.4389,N/A,0.84391,405.13,N/A,N/A,N/A,4.724,N/A,4.8808,10.5903,N/A,N/A,0.9683,140.5,9.8283,7.5215,N/A,N/A,18.4095,1.4617,5.2326,1.3118,6.906,7.9844,15092.62,3.2993,81.042,1344.81,20.313,4.5536,1.6145,56.776,1.4053,36.254,17.0004,
2022-08-17,1.0164,137.36,1.9558,N/A,24.566,7.4377,N/A,0.84208,404.28,N/A,N/A,N/A,4.7078,N/A,4.8825,10.5617,N/A,N/A,0.9686,140.3,9.8428,7.5071,N/A,N/A,18.2568,1.4655,5.2838,1.3117,6.8917,7.9705,15015.81,3.311,80.7555,1337.02,20.3825,4.5413,1.6165,56.772,1.4051,36.052,16.9125,
2022-08-16,1.0131,136.11,1.9558,N/A,24.54,7.4368,N/A,0.84218,406.2,N/A,N/A,N/A,4.7043,N/A,4.882,10.5365,N/A,N/A,0.9625,140.3,9.8428,7.51,N/A,N/A,18.1994,1.4463,5.1835,1.3076,6.8767,7.9449,14968.68,3.3087,80.3745,1329.66,20.1595,4.5245,1.6012,56.602,1.398,35.93,16.6556,
2022-08-15,1.0195,135.61,1.9558,N/A,24.46,7.4373,N/A,0.84375,398.6,N/A,N/A,N/A,4.6858,N/A,4.8849,10.498,N/A,N/A,0.9631,140.3,9.871,7.5028,N/A,N/A,18.3143,1.4508,5.2268,1.3167,6.905,7.9899,15042.36,3.3294,81.061,1336.35,20.3914,4.5465,1.6002,57.122,1.4036,36.218,16.7375,
2022-08-12,1.0285,137.47,1.9558,N/A,24.38,7.4395,N/A,0.84715,392.3,N/A,N/A,N/A,4.6773,N/A,4.8915,10.4515,N/A,N/A,0.9689,140.3,9.813,7.5138,N/A,N/A,18.4733,1.4496,5.3007,1.3148,6.9352,8.06,15104.2,3.345,81.9935,1342.59,20.4925,4.5709,1.5985,57.246,1.4106,36.393,16.7318,
2022-08-11,1.0338,136.57,1.9558,N/A,24.346,7.4395,N/A,0.84575,394.18,N/A,N/A,N/A,4.6828,N/A,4.9055,10.36,N/A,N/A,0.9712,139.7,9.804,7.515,N/A,N/A,18.5674,1.4532,5.2447,1.3202,6.9668,8.1118,15215.93,3.3505,82.2845,1344.62,20.6398,4.5952,1.6045,57.225,1.4151,36.343,16.7083,
2022-08-10,1.0252,138.16,1.9558,N/A,24.397,7.4397,N/A,0.84608,397.65,N/A,N/A,N/A,4.7063,N/A,4.9138,10.3773,N/A,N/A,0.9713,139.7,9.9118,7.5158,N/A,N/A,18.4099,1.4682,5.251,1.3207,6.9222,8.046,15218.87,3.3773,81.468,1344.16,20.713,4.5693,1.6211,57.061,1.4107,36.42,16.8788,
2022-08-09,1.0234,138.26,1.9558,N/A,24.532,7.4407,N/A,0.8452,397.35,N/A,N/A,N/A,4.7085,N/A,4.9038,10.3875,N/A,N/A,0.9763,140.1,9.9365,7.514,N/A,N/A,18.3342,1.4687,5.2478,1.3163,6.9106,8.0334,15197.09,3.3865,81.406,1336.74,20.7145,4.5592,1.6304,56.939,1.411,36.264,17.05,
2022-08-08,1.0199,137.62,1.9558,N/A,24.515,7.4405,N/A,0.84165,394.27,N/A,N/A,N/A,4.7043,N/A,4.9163,10.365,N/A,N/A,0.9763,140.1,9.9405,7.5123,N/A,N/A,18.3175,1.4607,5.238,1.3134,6.8931,8.0061,15147.65,3.3895,81.166,1329.93,20.681,4.5477,1.6202,56.554,1.4058,36.38,16.9694,
2022-08-05,1.0233,136.22,1.9558,N/A,24.581,7.4415,N/A,0.84268,393.78,N/A,N/A,N/A,4.7085,N/A,4.9251,10.3573,N/A,N/A,0.9776,138.9,9.982,7.5148,N/A,N/A,18.3853,1.4713,5.3348,1.3185,6.9068,8.0328,15236.2,3.4033,81.0469,1324.53,20.8367,4.5598,1.6248,56.524,1.4077,36.373,17.0342,
2022-08-04,1.0181,135.81,1.9558,N/A,24.659,7.4425,N/A,0.84231,395.98,N/A,N/A,N/A,4.7233,N/A,4.9261,10.374,N/A,N/A,0.9765,138.7,9.9065,7.515,N/A,N/A,18.2922,1.4607,5.3614,1.307,6.8769,7.9919,15200.94,3.4101,80.7715,1333.7,20.756,4.5387,1.6172,56.633,1.4037,36.606,17.0352,
2022-08-03,1.0194,136.18,1.9558,N/A,24.65,7.4427,N/A,0.83629,395.03,N/A,N/A,N/A,4.691,N/A,4.9245,10.3913,N/A,N/A,0.9773,139.3,9.8743,7.5178,N/A,N/A,18.3112,1.4681,5.3547,1.3085,6.883,8.0022,15184.35,3.4362,80.6895,1336.03,21.0788,4.5435,1.6266,56.855,1.4069,36.963,17.1283,
2022-08-02,1.0224,133.9,1.9558,N/A,24.644,7.4432,N/A,0.83665,396.82,N/A,N/A,N/A,4.7063,N/A,4.9298,10.3995,N/A,N/A,0.9744,139.3,9.9305,7.5195,N/A,N/A,18.3564,1.4745,5.3175,1.315,6.9117,8.0257,15204.85,3.4486,80.3243,1339.16,20.952,4.5531,1.6254,56.834,1.4103,36.914,16.982,
2022-08-01,1.0233,135.38,1.9558,N/A,24.628,7.4457,N/A,0.837,401.35,N/A,N/A,N/A,4.734,N/A,4.9283,10.3668,N/A,N/A,0.9717,138.7,9.8638,7.521,N/A,N/A,18.3475,1.4535,5.2723,1.3076,6.9105,8.0329,15203.21,3.4546,80.9335,1333.3,20.7635,4.5568,1.616,56.734,1.4087,36.977,16.8613,
2022-07-29,1.0198,136.42,1.9558,N/A,24.61,7.4438,N/A,0.8399,404.8,N/A,N/A,N/A,4.7375,N/A,4.9343,10.3875,N/A,N/A,0.9744,138.3,9.8773,7.518,N/A,N/A,18.2472,1.4646,5.2739,1.31,6.8705,8.0054,15155.56,3.4714,80.882,1329.4,20.6745,4.5386,1.6283,56.375,1.4088,36.978,16.8627,
2022-07-28,1.0122,137.26,1.9558,N/A,24.609,7.4442,N/A,0.83586,407.3,N/A,N/A,N/A,4.7908,N/A,4.9342,10.449,N/A,N/A,0.9745,138.7,9.8983,7.52,N/A,N/A,18.1417,1.4535,5.33,1.2986,6.8325,7.9456,15107.59,3.4701,80.6535,1320.45,20.676,4.5071,1.6172,56.592,1.4009,37.097,17.0011,
2022-07-27,1.0152,138.89,1.9558,N/A,24.575,7.4446,N/A,0.84138,404.67,N/A,N/A,N/A,4.7978,N/A,4.9334,10.4545,N/A,N/A,0.9768,139.1,9.9558,7.514,N/A,N/A,18.1859,1.462,5.4039,1.3049,6.8534,7.9692,15213.07,3.4855,81.135,1333.99,20.753,4.5263,1.6306,56.455,1.4088,37.4,17.1347,
2022-07-26,1.0124,138.35,1.9558,N/A,24.607,7.4449,N/A,0.84558,400.99,N/A,N/A,N/A,4.742,N/A,4.9324,10.4445,N/A,N/A,0.9765,139.1,10.0105,7.5145,N/A,N/A,18.0705,1.4605,5.4437,1.3035,6.8451,7.9466,15185.27,3.4891,80.805,1326.65,20.7845,4.5113,1.6235,56.16,1.4066,37.18,17.087,
2022-07-25,1.0236,139.84,1.9558,N/A,24.535,7.4449,N/A,0.84813,396.5,N/A,N/A,N/A,4.708,N/A,4.9339,10.3973,N/A,N/A,0.9869,139.5,10.0704,7.5195,N/A,N/A,18.2653,1.4707,5.5976,1.3168,6.9094,8.0345,15303.87,3.5201,81.6675,1341.25,20.9376,4.5586,1.6325,57.209,1.4176,37.525,17.1502,
2022-07-22,1.019,139.51,1.9558,N/A,24.514,7.4443,N/A,0.85141,398.3,N/A,N/A,N/A,4.7508,N/A,4.9321,10.4328,N/A,N/A,0.9832,139.5,10.1498,7.5234,N/A,N/A,18.094,1.4677,5.5821,1.3105,6.8852,7.9985,15275.69,3.5083,81.384,1335.66,20.9595,4.5366,1.6265,57.24,1.4151,37.392,17.2009,
2022-07-21,1.0199,141.46,1.9558,N/A,24.496,7.4446,N/A,0.85545,400.13,N/A,N/A,N/A,4.761,N/A,4.9391,10.426,N/A,N/A,0.9924,139.7,10.175,7.52,N/A,N/A,18.0327,1.4848,5.5777,1.3178,6.904,8.0056,15342.25,3.5203,81.451,1337.47,20.941,4.5457,1.6479,57.512,1.4218,37.66,17.5195,
2022-07-20,1.0199,140.92,1.9558,N/A,24.493,7.4452,N/A,0.85178,399.5,N/A,N/A,N/A,4.782,N/A,4.9396,10.4606,N/A,N/A,0.9896,139.5,10.1323,7.5143,N/A,N/A,17.9444,1.4767,5.5427,1.3132,6.8892,8.0062,15275.82,3.5147,81.599,1337.61,20.8967,4.5406,1.6308,57.398,1.4204,37.405,17.3924,
2022-07-19,1.0245,141.01,1.9558,N/A,24.555,7.4449,N/A,0.85303,397.45,N/A,N/A,N/A,4.7598,N/A,4.9395,10.4964,N/A,N/A,0.9918,138.9,10.176,7.5093,N/A,N/A,18.018,1.4869,5.5454,1.3264,6.9064,8.0423,15344.49,3.5295,81.898,1340.33,20.8552,4.559,1.6456,57.583,1.4269,37.492,17.457,
2022-07-18,1.0131,140.16,1.9558,N/A,24.508,7.4435,N/A,0.84708,402.05,N/A,N/A,N/A,4.776,N/A,4.9389,10.5265,N/A,N/A,0.9911,138.9,10.2553,7.513,N/A,N/A,17.7225,1.4839,5.4505,1.3151,6.8266,7.9528,15157.63,3.5004,81.034,1333.33,20.7095,4.5113,1.6432,57.056,1.4153,37.13,17.383,
2022-07-15,1.0059,139.49,1.9558,N/A,24.561,7.443,N/A,0.84988,403.73,N/A,N/A,N/A,4.7953,N/A,4.9407,10.5943,N/A,N/A,0.9849,138.9,10.2763,7.516,N/A,N/A,17.5451,1.4886,5.4434,1.3147,6.7943,7.8963,15081.58,3.5044,80.316,1333.79,20.9209,4.4752,1.6377,56.678,1.4113,36.866,17.2875,
2022-07-14,1.0005,139.04,1.9558,N/A,24.417,7.4425,N/A,0.8456,408.78,N/A,N/A,N/A,4.8146,N/A,4.942,10.6019,N/A,N/A,0.9841,138.89,10.2536,7.5122,N/A,N/A,17.494,1.4893,5.4586,1.3162,6.7618,7.8539,15119.56,3.4915,80.0752,1322.29,20.9585,4.4462,1.6437,56.565,1.4065,36.632,17.202,
2022-07-13,1.0067,138.02,1.9558,N/A,24.397,7.4416,N/A,0.84371,409.35,N/A,N/A,N/A,4.824,N/A,4.9414,10.602,N/A,N/A,0.9829,138.3,10.2428,7.5155,N/A,N/A,17.5629,1.4802,5.4533,1.3073,6.7722,7.9025,15117.08,3.4864,80.1285,1311.4,20.9029,4.4667,1.635,56.669,1.4134,36.377,17.0527,
2022-07-12,1.0042,137.31,1.9558,N/A,24.582,7.4408,N/A,0.84823,409.98,N/A,N/A,N/A,4.819,N/A,4.9413,10.629,N/A,N/A,0.9883,139.1,10.2754,7.517,N/A,N/A,17.4392,1.49,5.4009,1.3094,6.7518,7.8828,15054.05,3.4987,79.8965,1315.1,20.8883,4.4556,1.6395,56.648,1.4127,36.392,17.1509,
2022-07-11,1.0098,138.77,1.9558,N/A,24.592,7.4414,N/A,0.8454,408.22,N/A,N/A,N/A,4.7968,N/A,4.943,10.6943,N/A,N/A,0.9908,139.3,10.299,7.518,N/A,N/A,17.5447,1.491,5.3673,1.314,6.7793,7.9265,15131.92,3.5108,80.2435,1320.36,20.7845,4.4704,1.6466,56.574,1.4178,36.585,17.1634,
2022-07-08,1.0163,138.05,1.9558,N/A,24.614,7.4424,N/A,0.84585,402.45,N/A,N/A,N/A,4.763,N/A,4.9431,10.6665,N/A,N/A,0.9913,139.5,10.263,7.519,N/A,N/A,17.6026,1.4871,5.4345,1.3201,6.8095,7.9769,15210.73,3.5325,80.528,1321.61,20.8477,4.4992,1.6464,56.882,1.4228,36.602,17.1922,
2022-07-07,1.018,138.11,1.9558,N/A,24.779,7.4405,N/A,0.85105,410.04,N/A,N/A,N/A,4.7721,N/A,4.9448,10.723,N/A,N/A,0.9906,139.3,10.291,7.5193,N/A,N/A,17.5551,1.4883,5.4983,1.3227,6.823,7.9893,15265.27,3.5548,80.6,1324.66,20.9675,4.5077,1.6461,56.939,1.4255,36.74,17.0372,
2022-07-06,1.0177,137.71,1.9558,N/A,24.778,7.4403,N/A,0.85676,411.8,N/A,N/A,N/A,4.771,N/A,4.944,10.745,N/A,N/A,0.9896,138.5,10.2803,7.5198,N/A,N/A,17.5505,1.4961,5.5116,1.3274,6.8289,7.9864,15287.49,3.5884,80.5321,1331.69,21.0194,4.5028,1.6505,56.779,1.4305,36.78,17.0246,
2022-07-05,1.029,139.77,1.9558,N/A,24.751,7.4396,N/A,0.85845,407.38,N/A,N/A,N/A,4.7448,N/A,4.9438,10.8031,N/A,N/A,0.9932,139.1,10.285,7.5246,N/A,N/A,17.5049,1.518,5.5141,1.3364,6.9029,8.0748,15487.93,3.6343,81.673,1348.97,21.0171,4.5477,1.6772,57.009,1.4455,36.879,16.9143,
2022-07-04,1.0455,141.51,1.9558,N/A,24.745,7.4391,N/A,0.8596,401.52,N/A,N/A,N/A,4.71,N/A,4.944,10.7658,N/A,N/A,1.0037,139.3,10.2958,7.5301,N/A,N/A,17.5994,1.5205,5.5663,1.3435,6.9977,8.2033,15684.13,3.6655,82.5067,1353.4,21.1972,4.6138,1.6748,57.487,1.4587,37.298,17.0275,
2022-07-01,1.0425,141.05,1.9558,N/A,24.753,7.4391,N/A,0.86648,401.11,N/A,N/A,N/A,4.7168,N/A,4.9457,10.7783,N/A,N/A,1.0027,138.7,10.3651,7.531,N/A,N/A,17.4608,1.5382,5.5117,1.3492,6.987,8.1801,15621.64,3.6717,82.3747,1352.58,21.115,4.5943,1.6929,57.452,1.4565,37.186,17.1323,
2022-06-30,1.0387,141.54,1.9558,N/A,24.739,7.4392,N/A,0.8582,397.04,N/A,N/A,N/A,4.6904,N/A,4.9464,10.73,N/A,N/A,0.996,138.9,10.3485,7.5307,N/A,N/A,17.322,1.5099,5.4229,1.3425,6.9624,8.1493,15552,3.6392,82.113,1351.6,20.9641,4.5781,1.6705,57.15,1.4483,36.754,17.0143,
2022-06-29,1.0517,143.53,1.9558,N/A,24.739,7.4392,N/A,0.86461,394.28,N/A,N/A,N/A,4.6869,N/A,4.9419,10.6848,N/A,N/A,1.0005,139.9,10.3065,7.5285,N/A,N/A,17.4998,1.5256,5.5163,1.3513,7.0382,8.2532,15612.61,3.6344,83.037,1364.02,21.1375,4.6272,1.6871,57.773,1.4607,36.925,16.9295,
2022-06-28,1.0561,143.67,1.9558,N/A,24.726,7.4394,N/A,0.8635,398.55,N/A,N/A,N/A,4.6905,N/A,4.9443,10.6543,N/A,N/A,1.0101,139.5,10.337,7.532,N/A,N/A,17.5891,1.521,5.5308,1.3565,7.0775,8.288,15669.91,3.6267,83.408,1361.75,21.088,4.6432,1.6822,57.85,1.4645,37.154,16.9072,
2022-06-27,1.0572,143.25,1.9558,N/A,24.724,7.4408,N/A,0.862,402.62,N/A,N/A,N/A,4.699,N/A,4.944,10.6713,N/A,N/A,1.0143,139.7,10.408,7.5333,N/A,N/A,17.4794,1.5278,5.5446,1.3639,7.0737,8.2946,15635.36,3.6009,82.9325,1357.68,21.041,4.6559,1.6801,57.9,1.4641,37.361,16.7967,
2022-06-24,1.0524,142.19,1.9558,N/A,24.731,7.4398,N/A,0.85773,401.34,N/A,N/A,N/A,4.7023,N/A,4.9463,10.694,N/A,N/A,1.0072,139.7,10.4345,7.5295,N/A,N/A,18.2856,1.5248,5.4851,1.3657,7.0478,8.2609,15633.96,3.621,82.3985,1364.09,20.9901,4.6327,1.6731,57.83,1.462,37.36,16.7137,
2022-06-23,1.0493,142.11,1.9558,N/A,24.75,7.4388,N/A,0.85818,399.6,N/A,N/A,N/A,4.7085,N/A,4.9468,10.705,N/A,N/A,1.013,139.9,10.475,7.5286,N/A,N/A,18.2199,1.5212,5.4515,1.36,7.0367,8.236,15594.75,3.6192,82.1489,1367.21,21.0924,4.623,1.6713,57.44,1.4589,37.261,16.817,
2022-06-22,1.0521,143.11,1.9558,N/A,24.712,7.4387,N/A,0.85885,396,N/A,N/A,N/A,4.6905,N/A,4.9467,10.6688,N/A,N/A,1.0153,138.7,10.5045,7.5228,N/A,N/A,18.255,1.5254,5.4349,1.366,7.0604,8.2589,15618.98,3.6432,82.4075,1369.29,21.1491,4.6345,1.6835,57.174,1.4615,37.281,16.7985,
2022-06-21,1.055,143.75,1.9558,N/A,24.69,7.4393,N/A,0.8601,396.48,N/A,N/A,N/A,4.6435,N/A,4.9462,10.646,N/A,N/A,1.0214,138.7,10.3283,7.5205,N/A,N/A,18.3049,1.5177,5.442,1.366,7.068,8.2817,15639.62,3.6505,82.423,1365.09,21.2485,4.6399,1.6675,57.304,1.4612,37.294,16.7881,
2022-06-20,1.0517,141.94,1.9558,N/A,24.728,7.4387,N/A,0.85748,397.85,N/A,N/A,N/A,4.652,N/A,4.9453,10.6375,N/A,N/A,1.0162,137.3,10.4085,7.5175,N/A,N/A,18.2239,1.5061,5.4117,1.3662,7.0346,8.2558,15589.89,3.639,81.994,1357.54,21.3016,4.6291,1.6549,56.872,1.4589,37.157,16.8603,
2022-06-17,1.0486,141.21,1.9558,N/A,24.742,7.4384,N/A,0.855,400.53,N/A,N/A,N/A,4.7003,N/A,4.9469,10.6748,N/A,N/A,1.0105,137.7,10.4525,7.5155,N/A,N/A,18.1495,1.5039,5.3824,1.3631,7.0308,8.2314,15537.05,3.6112,81.871,1356.27,21.4474,4.6159,1.6601,56.371,1.4547,36.974,16.7133,
2022-06-16,1.04,138.24,1.9558,N/A,24.742,7.4386,N/A,0.8555,398.1,N/A,N/A,N/A,4.7138,N/A,4.9443,10.6942,N/A,N/A,1.0142,137.5,10.4588,7.5245,N/A,N/A,18.0126,1.4939,5.2559,1.3446,6.9844,8.1638,15427.31,3.5934,81.1945,1346.88,21.4115,4.5786,1.6608,55.7,1.4451,36.566,16.6052,
2022-06-15,1.0431,140.49,1.9558,N/A,24.703,7.4392,N/A,0.86328,397.96,N/A,N/A,N/A,4.669,N/A,4.9427,10.6278,N/A,N/A,1.0435,137.5,10.3868,7.5245,N/A,N/A,18.0465,1.5051,5.3164,1.3498,7.0013,8.1883,15361.97,3.6007,81.5142,1346.86,21.4763,4.6037,1.6706,55.627,1.4519,36.529,16.7111,
2022-06-14,1.0452,140.62,1.9558,N/A,24.749,7.4403,N/A,0.86578,398.68,N/A,N/A,N/A,4.6563,N/A,4.9443,10.622,N/A,N/A,1.0394,138.3,10.3945,7.5238,N/A,N/A,18.06,1.5174,5.3329,1.3522,7.0417,8.2048,15400.02,3.6208,81.559,1346.72,21.4832,4.6224,1.6755,55.669,1.4541,36.566,16.7959,
2022-06-13,1.0455,140.51,1.9558,N/A,24.724,7.4397,N/A,0.8585,399.3,N/A,N/A,N/A,4.6373,N/A,4.9459,10.616,N/A,N/A,1.0375,138.7,10.3222,7.5215,N/A,N/A,18.0495,1.4998,5.2785,1.3435,7.0434,8.2071,15376.17,3.5994,81.606,1349.93,21.2102,4.6195,1.6635,55.72,1.4538,36.425,16.807,
2022-06-10,1.0578,141.69,1.9558,N/A,24.705,7.4389,N/A,0.85048,398.48,N/A,N/A,N/A,4.6053,N/A,4.9442,10.5255,N/A,N/A,1.0404,137.7,10.1495,7.5225,N/A,N/A,18.0116,1.4845,5.1718,1.3484,7.0868,8.3031,15393.27,3.5626,82.3355,1344.25,20.8285,4.6564,1.6482,56.101,1.462,36.774,16.5209,
2022-06-09,1.0743,143.93,1.9558,N/A,24.689,7.4391,N/A,0.85653,396.45,N/A,N/A,N/A,4.5925,N/A,4.9453,10.5045,N/A,N/A,1.0495,138.7,10.1818,7.5223,N/A,N/A,18.5104,1.4985,5.2506,1.3506,7.1722,8.4317,15646.25,3.5859,83.526,1348.99,21.0248,4.7199,1.6673,56.872,1.4779,37.079,16.4132,
2022-06-08,1.0739,143.92,1.9558,N/A,24.622,7.4386,N/A,0.85575,391.25,N/A,N/A,N/A,4.5698,N/A,4.945,10.4938,N/A,N/A,1.0486,138.9,10.1395,7.5215,N/A,N/A,18.453,1.4917,5.2447,1.3467,7.1785,8.4275,15577.86,3.5848,83.414,1349.34,21.0458,4.7187,1.6644,56.799,1.4769,37.076,16.4626,
2022-06-07,1.0662,141.66,1.9558,N/A,24.739,7.4395,N/A,0.85365,389.33,N/A,N/A,N/A,4.5813,N/A,4.9426,10.5039,N/A,N/A,1.0423,138.9,10.1843,7.5244,N/A,N/A,17.8702,1.4884,5.1256,1.3437,7.1146,8.3656,15412.37,3.5661,82.873,1340.75,20.8435,4.6865,1.6582,56.421,1.4685,36.768,16.4059,
2022-06-06,1.0726,140.16,1.9558,N/A,24.715,7.439,N/A,0.85415,388.05,N/A,N/A,N/A,4.5808,N/A,4.9424,10.452,N/A,N/A,1.032,138.3,10.0853,7.5222,N/A,N/A,17.796,1.4842,5.0986,1.3463,7.1223,8.4154,15464.73,3.5697,83.245,1341.13,20.9078,4.7076,1.6428,56.67,1.4732,36.774,16.4142,
2022-06-03,1.073,139.59,1.9558,N/A,24.708,7.4388,N/A,0.8542,394.78,N/A,N/A,N/A,4.5955,N/A,4.9428,10.4589,N/A,N/A,1.0296,137.9,10.103,7.522,N/A,N/A,17.738,1.4805,5.1643,1.3484,7.1465,8.4167,15498.1,3.5751,83.273,1337.4,20.985,4.7094,1.6409,56.738,1.4741,36.777,16.6153,
2022-06-02,1.0692,138.72,1.9558,N/A,24.702,7.4391,N/A,0.85195,394.9,N/A,N/A,N/A,4.5787,N/A,4.9398,10.4705,N/A,N/A,1.0264,136.9,10.0845,7.5325,N/A,N/A,17.6175,1.4829,5.1335,1.352,7.135,8.3896,15481.86,3.5705,82.922,1334.06,20.9831,4.6949,1.6413,56.467,1.4701,36.754,16.6143,
2022-06-01,1.0712,138.68,1.9558,N/A,24.748,7.4393,N/A,0.85158,395.03,N/A,N/A,N/A,4.5913,N/A,4.9428,10.4758,N/A,N/A,1.0305,137.1,10.0438,7.5345,N/A,N/A,17.6223,1.4861,5.0646,1.3536,7.1586,8.4057,15574.33,3.5682,83.051,1331.44,21.0678,4.6951,1.6442,56.182,1.47,36.801,16.609,
2022-05-31,1.0713,137.36,1.9558,N/A,24.714,7.4394,N/A,0.85138,396.2,N/A,N/A,N/A,4.5805,N/A,4.9408,10.5053,N/A,N/A,1.0281,136.3,10.0983,7.541,N/A,N/A,17.5817,1.4933,5.0965,1.3573,7.1402,8.4063,15580.15,3.5746,83.231,1329.32,20.987,4.6907,1.6459,56.323,1.4687,36.751,16.745,
2022-05-30,1.0764,137.25,1.9558,N/A,24.712,7.4391,N/A,0.8515,392.18,N/A,N/A,N/A,4.5855,N/A,4.9441,10.518,N/A,N/A,1.0327,136.9,10.1256,7.5305,N/A,N/A,17.6416,1.4982,5.0629,1.3647,7.1735,8.449,15682.41,3.5722,83.475,1331.66,20.8994,4.6998,1.6439,56.322,1.4719,36.7,16.648,
2022-05-27,1.0722,136.05,1.9558,N/A,24.7,7.4392,N/A,0.84875,392.83,N/A,N/A,N/A,4.5858,N/A,4.9427,10.5293,N/A,N/A,1.0258,137.9,10.179,7.5379,N/A,N/A,17.582,1.4995,5.0959,1.3661,7.1831,8.4165,15583.97,3.597,83.1915,1343.63,21.136,4.6952,1.6426,56.02,1.4679,36.589,16.746,
2022-05-26,1.0697,135.95,1.9558,N/A,24.676,7.4409,N/A,0.85073,391.72,N/A,N/A,N/A,4.6083,N/A,4.9423,10.5983,N/A,N/A,1.0283,138.1,10.2715,7.5355,N/A,N/A,17.5588,1.511,5.1741,1.3715,7.2024,8.397,15628.91,3.5935,83.0065,1352.69,21.1935,4.7045,1.6541,55.975,1.4709,36.589,16.9312,
2022-05-25,1.0656,135.34,1.9558,N/A,24.648,7.4405,N/A,0.85295,388.25,N/A,N/A,N/A,4.621,N/A,4.9416,10.5419,N/A,N/A,1.0269,138.3,10.2704,7.5355,N/A,N/A,17.3954,1.5126,5.1736,1.372,7.1334,8.3647,15587.59,3.585,82.6666,1354.61,21.2213,4.6833,1.6539,55.787,1.4676,36.55,16.7628,
2022-05-24,1.072,136.49,1.9558,N/A,24.663,7.4411,N/A,0.8575,383.33,N/A,N/A,N/A,4.6015,N/A,4.9446,10.5013,N/A,N/A,1.0334,139.3,10.289,7.5285,N/A,N/A,17.2572,1.5152,5.1793,1.3714,7.1449,8.4143,15711.88,3.5848,83.185,1353.65,21.2456,4.7076,1.6656,56.152,1.4722,36.609,16.7814,
2022-05-23,1.0659,136.05,1.9558,N/A,24.594,7.4413,N/A,0.84783,381.65,N/A,N/A,N/A,4.621,N/A,4.947,10.4918,N/A,N/A,1.031,139.1,10.252,7.5275,N/A,N/A,16.8672,1.4982,5.1623,1.3626,7.085,8.3664,15609,3.5745,82.6795,1344.19,21.1273,4.6782,1.6463,55.686,1.4639,36.41,16.7437,
2022-05-20,1.0577,135.34,1.9558,N/A,24.67,7.4424,N/A,0.8482,382.93,N/A,N/A,N/A,4.6365,N/A,4.9477,10.4915,N/A,N/A,1.028,138.5,10.262,7.5335,N/A,N/A,16.8201,1.498,5.1989,1.3526,7.0638,8.2999,15501.99,3.533,82.1617,1340.58,21.0314,4.6422,1.6518,55.181,1.4588,36.284,16.7131,
2022-05-19,1.0525,134.46,1.9558,N/A,24.7,7.4423,N/A,0.84728,385.83,N/A,N/A,N/A,4.6423,N/A,4.9474,10.5098,N/A,N/A,1.0265,139.5,10.3102,7.5395,N/A,N/A,16.8037,1.5036,5.2094,1.349,7.1028,8.2594,15416.76,3.5623,81.7115,1343.21,21.0043,4.6363,1.6551,55.14,1.4576,36.343,16.8315,
2022-05-18,1.0523,135.76,1.9558,N/A,24.647,7.4419,N/A,0.8467,382.88,N/A,N/A,N/A,4.6443,N/A,4.9473,10.4675,N/A,N/A,1.0486,138.9,10.2125,7.535,N/A,N/A,16.7811,1.498,5.1974,1.3488,7.0972,8.2591,15446,3.526,81.6455,1332.76,20.9204,4.6254,1.6548,55.077,1.4598,36.399,16.7313,
2022-05-17,1.0541,136.32,1.9558,N/A,24.712,7.4414,N/A,0.844,386.3,N/A,N/A,N/A,4.6488,N/A,4.9478,10.4393,N/A,N/A,1.0457,138.7,10.178,7.5245,N/A,N/A,16.6027,1.4993,5.2621,1.3517,7.0899,8.2744,15433.23,3.5387,81.6515,1333.66,21.0273,4.6211,1.6561,55.137,1.4589,36.361,16.844,
2022-05-16,1.0422,135.01,1.9558,N/A,24.71,7.4418,N/A,0.85045,385.85,N/A,N/A,N/A,4.6675,N/A,4.9469,10.4978,N/A,N/A,1.0479,138.3,10.2188,7.5225,N/A,N/A,16.3121,1.5057,5.2819,1.3473,7.0786,8.1812,15294.29,3.5474,81.081,1337.9,20.9324,4.5836,1.6601,54.705,1.4531,36.274,16.9195,
2022-05-13,1.0385,133.91,1.9558,N/A,24.74,7.4412,N/A,0.85115,385,N/A,N/A,N/A,4.6883,N/A,4.9455,10.4905,N/A,N/A,1.0385,140.1,10.2043,7.52,N/A,N/A,16.0687,1.5067,5.3204,1.3505,7.0513,8.1522,15193.55,3.5586,80.4315,1330.83,20.988,4.5673,1.6633,54.449,1.45,36.109,16.7789,
2022-05-12,1.0408,133.85,1.9558,N/A,24.925,7.4413,N/A,0.85293,382.2,N/A,N/A,N/A,4.668,N/A,4.947,10.5648,N/A,N/A,1.0377,139.7,10.2898,7.5235,N/A,N/A,16.0132,1.5163,5.4161,1.3569,7.0691,8.1702,15255.73,3.5981,80.667,1341.98,21.2531,4.5725,1.6692,54.589,1.4529,36.15,16.8806,
2022-05-11,1.0553,137.07,1.9558,N/A,25.365,7.4393,N/A,0.85393,379.13,N/A,N/A,N/A,4.6575,N/A,4.947,10.526,N/A,N/A,1.0446,139.3,10.1793,7.5365,N/A,N/A,16.1851,1.5055,5.3859,1.3685,7.0893,8.2839,15308.87,3.6148,81.4935,1343.99,21.387,4.6185,1.6645,54.992,1.4622,36.492,16.9275,
2022-05-10,1.0554,137.38,1.9558,N/A,25.014,7.4386,N/A,0.85595,380.15,N/A,N/A,N/A,4.6763,N/A,4.9458,10.6075,N/A,N/A,1.0479,139.5,10.2315,7.5385,N/A,N/A,16.0883,1.5162,5.4232,1.3707,7.0967,8.2847,15349.06,3.6587,81.5425,1346.56,21.4716,4.6248,1.6707,55.289,1.4667,36.448,17.005,
2022-05-09,1.0559,138.1,1.9558,N/A,25.055,7.4385,N/A,0.85235,383.23,N/A,N/A,N/A,4.6985,N/A,4.9467,10.5818,N/A,N/A,1.0462,139.5,10.0583,7.5335,N/A,N/A,15.8941,1.5048,5.4321,1.3656,7.0886,8.2887,15367.67,3.6239,81.7415,1345.48,21.4341,4.6285,1.6584,55.67,1.4676,36.497,17.1332,
2022-05-06,1.057,137.9,1.9558,N/A,24.665,7.44,N/A,0.85625,381.47,N/A,N/A,N/A,4.7028,N/A,4.949,10.4686,N/A,N/A,1.0419,138.3,9.9808,7.5336,N/A,N/A,15.8078,1.4888,5.3183,1.356,7.0506,8.2969,15312.44,3.5965,81.298,1343.9,21.3555,4.6191,1.644,55.467,1.4642,36.303,16.9614,
2022-05-05,1.0568,137.18,1.9558,N/A,24.606,7.4405,N/A,0.8519,378.65,N/A,N/A,N/A,4.6673,N/A,4.9485,10.3748,N/A,N/A,1.0355,138,9.8463,7.5398,N/A,N/A,15.7051,1.4669,5.2192,1.3483,6.9944,8.2948,15250.92,3.5916,80.6185,1330.89,21.2069,4.5955,1.6273,55.364,1.4561,36.026,16.5862,
2022-05-04,1.0531,136.84,1.9558,N/A,24.644,7.4409,N/A,0.84194,377.55,N/A,N/A,N/A,4.6875,N/A,4.947,10.3968,N/A,N/A,1.0324,137.2,9.9042,7.5499,N/A,N/A,15.5769,1.478,5.24,1.3498,6.9594,8.2655,15201.44,3.5487,80.4035,1331.45,21.2947,4.5847,1.6333,55.26,1.4559,36.137,16.6489,
2022-05-03,1.0556,137.06,1.9558,N/A,24.662,7.4403,N/A,0.8413,382.15,N/A,N/A,N/A,4.6925,N/A,4.9475,10.3978,N/A,N/A,1.0272,137.6,9.909,7.5555,N/A,N/A,15.6941,1.4825,5.3143,1.357,6.9759,8.2838,15288.47,3.5597,80.842,1335.64,21.5025,4.5956,1.6366,55.455,1.4605,36.387,16.8303,
2022-05-02,1.0524,136.63,1.9558,N/A,24.671,7.4391,N/A,0.8381,378.51,N/A,N/A,N/A,4.685,N/A,4.9478,10.4035,N/A,N/A,1.0253,137.2,9.9248,7.561,N/A,N/A,15.6697,1.4913,5.248,1.356,6.9548,8.2581,15293.41,3.5277,80.497,1333.71,21.4758,4.5816,1.6362,55.229,1.4585,36.208,16.7383,
2022-04-29,1.054,137.01,1.9558,N/A,24.605,7.4415,N/A,0.83908,378.71,N/A,N/A,N/A,4.678,N/A,4.9479,10.2958,N/A,N/A,1.0229,137.8,9.7525,7.5667,N/A,N/A,15.6385,1.4699,5.1608,1.3426,6.9441,8.2703,15301.52,3.4993,80.638,1326.71,21.4181,4.5886,1.6119,55.2,1.4545,36.026,16.6473,
2022-04-28,1.0485,137.13,1.9558,N/A,24.526,7.4421,N/A,0.8435,377.06,N/A,N/A,N/A,4.6891,N/A,4.9479,10.3594,N/A,N/A,1.0216,137.8,9.899,7.5703,N/A,N/A,15.5362,1.4814,5.2465,1.3498,6.9381,8.2267,15222.05,3.5096,80.367,1337.82,21.4531,4.5741,1.6221,54.845,1.4556,36.152,16.7472,
2022-04-27,1.0583,135.57,1.9558,N/A,24.55,7.441,N/A,0.84215,379.74,N/A,N/A,N/A,4.7043,N/A,4.948,10.4035,N/A,N/A,1.0229,138.2,9.7838,7.565,N/A,N/A,15.6857,1.4828,5.3045,1.3572,6.9377,8.3045,15259.86,3.5178,81.0705,1341.98,21.6259,4.6142,1.6118,55.195,1.4602,36.331,16.8406,
2022-04-26,1.0674,136.15,1.9558,N/A,24.423,7.4393,N/A,0.84135,374.46,N/A,N/A,N/A,4.6466,N/A,4.9458,10.3935,N/A,N/A,1.0229,138.4,9.7943,7.5625,N/A,N/A,15.7944,1.4828,5.249,1.3613,6.9837,8.3735,15365.76,3.5147,81.7265,1340.02,21.6538,4.6485,1.6102,55.681,1.4666,36.596,16.7787,
2022-04-25,1.0746,137.73,1.9558,N/A,24.418,7.4391,N/A,0.8433,374.08,N/A,N/A,N/A,4.6398,N/A,4.9455,10.3476,N/A,N/A,1.0267,139.2,9.7018,7.562,N/A,N/A,15.864,1.4972,5.1953,1.3709,7.0398,8.4325,15533.84,3.5306,82.321,1344.49,21.8989,4.6815,1.624,56.259,1.4757,36.542,16.8549,
2022-04-22,1.0817,138.83,1.9558,N/A,24.32,7.4402,N/A,0.83925,370.35,N/A,N/A,N/A,4.6336,N/A,4.9455,10.278,N/A,N/A,1.0336,139.8,9.6255,7.5625,N/A,N/A,15.9446,1.4816,5.0926,1.3714,7.0332,8.4859,15603.47,3.5288,82.6943,1344.04,22.0034,4.6784,1.6193,56.721,1.4784,36.724,16.8652,
2022-04-21,1.0887,139.61,1.9558,N/A,24.38,7.4403,N/A,0.83523,370.6,N/A,N/A,N/A,4.63,N/A,4.945,10.2553,N/A,N/A,1.0335,139,9.5788,7.5635,N/A,N/A,15.9983,1.4653,5.0324,1.36,7.0228,8.5406,15624.02,3.5153,82.965,1348.33,21.8836,4.6716,1.6053,57.081,1.482,36.891,16.5996,
2022-04-20,1.083,138.53,1.9558,N/A,24.409,7.4405,N/A,0.82965,371.36,N/A,N/A,N/A,4.6338,N/A,4.9436,10.23,N/A,N/A,1.0254,139.2,9.5443,7.561,N/A,N/A,15.8892,1.4581,5.0481,1.3579,6.9448,8.494,15537.05,3.4908,82.6348,1337.89,21.6392,4.6415,1.595,56.747,1.4779,36.567,16.3019,
2022-04-19,1.0803,138.4,1.9558,N/A,24.424,7.4391,N/A,0.82955,374.12,N/A,N/A,N/A,4.6553,N/A,4.9411,10.3408,N/A,N/A,1.0208,139.8,9.5228,7.562,N/A,N/A,15.8416,1.4663,5.0261,1.3631,6.9008,8.4698,15498.35,3.5038,82.6038,1339.46,21.4725,4.5961,1.6016,56.683,1.4763,36.466,16.0401,
2022-04-14,1.0878,136.32,1.9558,N/A,24.42,7.4389,N/A,0.82908,376.57,N/A,N/A,N/A,4.6478,N/A,4.9459,10.3008,N/A,N/A,1.0189,140.4,9.5313,7.5587,N/A,N/A,15.9046,1.4612,5.1226,1.3663,6.932,8.5298,15621.3,3.4896,82.814,1334.71,21.5941,4.603,1.5957,56.759,1.4732,36.615,15.9331,
2022-04-13,1.0826,136.26,1.9558,N/A,24.45,7.4377,N/A,0.8328,378.45,N/A,N/A,N/A,4.6453,N/A,4.9415,10.3323,N/A,N/A,1.0116,140.2,9.5693,7.5538,N/A,N/A,15.7992,1.4603,5.0449,1.37,6.8939,8.4867,15549.1,3.4782,82.478,1328.47,21.417,4.5799,1.5991,56.446,1.4769,36.305,15.682,
2022-04-12,1.0861,136.29,1.9558,N/A,24.45,7.4379,N/A,0.83455,377.78,N/A,N/A,N/A,4.6552,N/A,4.9417,10.332,N/A,N/A,1.0131,139.6,9.5395,7.5513,N/A,N/A,15.9548,1.4599,5.0944,1.3724,6.9199,8.5112,15609.66,3.4972,82.7285,1335.49,21.5616,4.5972,1.5874,56.574,1.4803,36.531,15.849,
2022-04-11,1.09,137.01,1.9558,N/A,24.429,7.4375,N/A,0.83693,378.27,N/A,N/A,N/A,4.6456,N/A,4.9397,10.3128,N/A,N/A,1.018,140,9.5478,7.5519,N/A,N/A,16.0485,1.4654,5.155,1.3738,6.9405,8.544,15658.28,3.501,82.7085,1345.23,21.8653,4.6112,1.5938,56.753,1.4874,36.613,15.9127,
2022-04-08,1.0861,134.87,1.9558,N/A,24.479,7.4372,N/A,0.83355,375.66,N/A,N/A,N/A,4.6437,N/A,4.9425,10.2768,N/A,N/A,1.0155,139.6,9.508,7.549,N/A,N/A,16.0237,1.4552,5.1583,1.3675,6.9115,8.5134,15601.96,3.501,82.389,1333.12,21.8729,4.585,1.5849,55.99,1.4801,36.488,15.9968,
2022-04-07,1.0916,135.32,1.9558,N/A,24.512,7.4378,N/A,0.8345,379.26,N/A,N/A,N/A,4.637,N/A,4.9419,10.313,N/A,N/A,1.0185,141,9.5595,7.5562,N/A,N/A,16.0929,1.4578,5.146,1.3704,6.9448,8.5554,15692.35,3.5259,82.951,1330.92,21.9806,4.6046,1.5816,56.114,1.4848,36.541,16.052,
2022-04-06,1.0923,135.3,1.9558,N/A,24.441,7.4378,N/A,0.83473,377.77,N/A,N/A,N/A,4.6328,N/A,4.9433,10.2855,N/A,N/A,1.0187,141.4,9.5523,7.547,N/A,N/A,16.0998,1.4431,5.0996,1.3647,6.9498,8.5617,15683.36,3.5199,82.8343,1330.44,21.8759,4.604,1.5718,56.167,1.4844,36.701,15.9934,
2022-04-05,1.0969,134.76,1.9558,N/A,24.338,7.4378,N/A,0.8349,370.93,N/A,N/A,N/A,4.6265,N/A,4.9438,10.2593,N/A,N/A,1.0141,141.6,9.5398,7.5399,N/A,N/A,16.15,1.4374,5.0384,1.3647,6.9783,8.5917,15732.77,3.5152,82.635,1330.81,21.7474,4.6185,1.5657,56.194,1.4867,36.697,15.9529,
2022-04-04,1.1005,135.08,1.9558,N/A,24.32,7.4385,N/A,0.8389,369.15,N/A,N/A,N/A,4.6375,N/A,4.9432,10.3849,N/A,N/A,1.0203,141.8,9.5489,7.5455,N/A,N/A,16.183,1.4651,5.1162,1.3749,7.0026,8.6226,15783.89,3.5312,83.118,1338.41,21.82,4.643,1.586,56.521,1.4938,36.894,16.0957,
2022-04-01,1.1052,135.35,1.9558,N/A,24.376,7.4388,N/A,0.84145,368.12,N/A,N/A,N/A,4.6401,N/A,4.9452,10.332,N/A,N/A,1.0217,142,9.6628,7.5675,N/A,N/A,16.2411,1.4696,5.2188,1.3805,7.0311,8.6596,15887.5,3.5315,83.9847,1345.61,21.9087,4.6534,1.5911,57.084,1.4985,36.941,16.1685,
2022-03-31,1.1101,135.17,1.9558,N/A,24.375,7.4379,N/A,0.84595,369.77,N/A,N/A,N/A,4.6531,N/A,4.9463,10.337,N/A,N/A,1.0267,142,9.711,7.574,N/A,N/A,16.2823,1.4829,5.3009,1.3896,7.0403,8.6918,15947,3.5243,84.134,1347.37,22.0903,4.6677,1.6014,57.514,1.5028,36.911,16.1727,
2022-03-30,1.1126,135.47,1.9558,N/A,24.45,7.4391,N/A,0.84563,368.13,N/A,N/A,N/A,4.6679,N/A,4.9477,10.3498,N/A,N/A,1.0309,142.2,9.6398,7.572,N/A,N/A,16.3296,1.4809,5.2808,1.3891,7.0666,8.7081,15957.24,3.5399,84.38,1346.97,22.1557,4.6779,1.5947,57.906,1.5064,37.144,16.1288,
2022-03-29,1.1085,136.66,1.9558,N/A,24.464,7.4388,N/A,0.8444,369.8,N/A,N/A,N/A,4.6594,N/A,4.9478,10.329,N/A,N/A,1.0362,142.2,9.5995,7.5815,N/A,N/A,16.3275,1.4795,5.2434,1.387,7.055,8.6767,15896.31,3.5505,83.9685,1345.62,22.1561,4.6707,1.6054,57.602,1.5051,37.29,16.1804,
2022-03-28,1.0966,135.93,1.9558,N/A,24.65,7.4393,N/A,0.83643,374.13,N/A,N/A,N/A,4.718,N/A,4.9483,10.4225,N/A,N/A,1.0257,142.8,9.5123,7.5735,N/A,N/A,16.275,1.459,5.2133,1.3702,6.9862,8.5861,15737.77,3.5313,83.4825,1342.49,21.9841,4.6238,1.5838,57.08,1.4921,37.027,15.9925,
2022-03-25,1.1002,134.07,1.9558,N/A,24.645,7.4404,N/A,0.8338,373.81,N/A,N/A,N/A,4.7307,N/A,4.9487,10.3505,N/A,N/A,1.0207,142.2,9.5205,7.5754,N/A,N/A,16.3304,1.4624,5.2634,1.3781,7.0007,8.6117,15777.69,3.5351,83.8235,1343.32,21.9908,4.6324,1.5787,57.322,1.4919,36.906,16.0386,
2022-03-24,1.0978,133.71,1.9558,N/A,24.72,7.4397,N/A,0.83288,374.44,N/A,N/A,N/A,4.7421,N/A,4.9489,10.3555,N/A,N/A,1.0225,141.2,9.4923,7.5745,N/A,N/A,16.2917,1.4668,5.3057,1.3806,6.9933,8.5897,15778.31,3.5461,83.879,1342.53,22.177,4.6396,1.5812,57.426,1.4912,36.837,16.1478,
2022-03-23,1.0985,132.65,1.9558,N/A,24.605,7.4381,N/A,0.8328,372.25,N/A,N/A,N/A,4.7052,N/A,4.9463,10.4005,N/A,N/A,1.0269,141.4,9.6425,7.571,N/A,N/A,16.3108,1.4728,5.3903,1.384,7.0003,8.5948,15792.11,3.5407,83.9675,1337.76,22.1978,4.6401,1.5822,57.565,1.4919,36.965,16.2501,
2022-03-22,1.1024,132.96,1.9558,N/A,24.679,7.4402,N/A,0.83228,371.23,N/A,N/A,N/A,4.6851,N/A,4.9463,10.3822,N/A,N/A,1.0275,142.7,9.6233,7.575,N/A,N/A,16.3432,1.4802,5.4105,1.3867,7.0137,8.6285,15808.01,3.5521,83.9145,1343.81,22.3667,4.6483,1.586,57.749,1.4957,36.881,16.343,
2022-03-21,1.1038,131.57,1.9558,N/A,24.683,7.4411,N/A,0.83775,374.48,N/A,N/A,N/A,4.696,N/A,4.947,10.4088,N/A,N/A,1.0278,142.7,9.6575,7.5733,N/A,N/A,16.3773,1.4897,5.502,1.3898,7.0152,8.6387,15826.61,3.5637,84.1835,1342.62,22.48,4.6415,1.5997,57.817,1.496,37.038,16.4543,
2022-03-18,1.1008,131.4,1.9558,N/A,24.837,7.4423,N/A,0.83925,375.33,N/A,N/A,N/A,4.7135,N/A,4.9483,10.4303,N/A,N/A,1.0314,142.9,9.694,7.5685,N/A,N/A,16.3054,1.4945,5.5784,1.3911,7.0031,8.6101,15782.11,3.5761,83.7825,1337.31,22.5905,4.6157,1.6026,57.622,1.4952,36.745,16.5347,
2022-03-17,1.1051,131.27,1.9558,N/A,24.777,7.4439,N/A,0.84315,372.05,N/A,N/A,N/A,4.6889,N/A,4.9465,10.4503,N/A,N/A,1.0385,142.1,9.78,7.573,N/A,N/A,16.3123,1.5055,5.6339,1.3998,7.0176,8.6391,15835.97,3.5777,83.8435,1340.02,22.788,4.6364,1.613,57.69,1.498,36.767,16.5286,
2022-03-16,1.0994,130.05,1.9558,N/A,24.687,7.4412,N/A,0.83988,371.18,N/A,N/A,N/A,4.6765,N/A,4.9473,10.4205,N/A,N/A,1.0336,143.5,9.7988,7.5725,N/A,N/A,16.1783,1.5165,5.6523,1.3967,6.9817,8.5996,15690.36,3.5872,83.7805,1353.77,22.854,4.6147,1.6168,57.433,1.4966,36.681,16.5574,
2022-03-15,1.0991,129.67,1.9558,N/A,24.867,7.441,N/A,0.84053,371.41,N/A,N/A,N/A,4.7355,N/A,4.9482,10.526,N/A,N/A,1.0322,144.9,9.849,7.575,N/A,N/A,16.0968,1.5234,5.6385,1.4099,7.0117,8.6026,15710.44,3.6088,83.9555,1366.05,22.9352,4.6239,1.6216,57.536,1.4993,36.842,16.6249,
2022-03-14,1.096,129.3,1.9558,N/A,24.89,7.4405,N/A,0.83915,373.88,N/A,N/A,N/A,4.7218,N/A,4.949,10.5368,N/A,N/A,1.0249,145.1,9.8588,7.5745,N/A,N/A,16.2,1.5137,5.5286,1.3978,6.9738,8.5815,15678.53,3.586,83.931,1357.77,22.8311,4.6087,1.613,57.398,1.4947,36.59,16.5029,
2022-03-11,1.099,128.46,1.9558,N/A,25.213,7.4402,N/A,0.8397,380.92,N/A,N/A,N/A,4.782,N/A,4.949,10.646,N/A,N/A,1.023,144.9,9.8033,7.5713,N/A,N/A,16.2554,1.5017,5.5077,1.4024,6.9633,8.6007,15696.64,3.5683,83.9875,1354.04,22.9524,4.6098,1.6053,57.461,1.4949,36.542,16.4896,
2022-03-10,1.1084,128.54,1.9558,N/A,25.316,7.4401,N/A,0.84175,381.63,N/A,N/A,N/A,4.8239,N/A,4.9491,10.7073,N/A,N/A,1.027,145.5,9.919,7.5665,N/A,N/A,16.574,1.5109,5.5958,1.4189,7.0063,8.6688,15824.95,3.6219,84.607,1360.48,23.3153,4.6414,1.6185,57.825,1.5058,36.71,16.7264,
2022-03-09,1.0993,127.31,1.9558,N/A,25.364,7.444,N/A,0.8357,379.66,N/A,N/A,N/A,4.8196,N/A,4.9485,10.734,N/A,N/A,1.0198,145.3,9.798,7.5625,N/A,N/A,16.1323,1.4991,5.5201,1.4108,6.9454,8.5974,15710.06,3.5978,84.2025,1357.08,23.2145,4.6028,1.6055,57.259,1.4966,36.326,16.656,
2022-03-08,1.0892,126.03,1.9558,N/A,25.642,7.4441,N/A,0.83185,388.28,N/A,N/A,N/A,4.9103,N/A,4.9494,10.8803,N/A,N/A,1.0111,145.9,9.7925,7.5715,N/A,N/A,15.8183,1.4971,5.5346,1.3978,6.8805,8.5183,15639.76,3.6022,83.924,1344.71,23.2866,4.5556,1.5958,56.9,1.4856,36.156,16.7051,
2022-03-07,1.0895,125.55,1.9558,N/A,25.584,7.4406,N/A,0.82625,393.25,N/A,N/A,N/A,4.9525,N/A,4.9494,10.8573,N/A,N/A,1.0069,145.8,9.8325,7.56,N/A,N/A,15.6577,1.4751,5.5065,1.3864,6.8846,8.5154,15685.76,3.5653,83.8125,1338.45,23.0249,4.5426,1.5861,56.832,1.4831,35.866,16.6951,
2022-03-04,1.0929,126.17,1.9558,N/A,25.737,7.4394,N/A,0.82388,386.54,N/A,N/A,N/A,4.853,N/A,4.9495,10.7935,N/A,N/A,1.0056,144.2,9.8358,7.5584,N/A,N/A,15.5681,1.4872,5.5313,1.3937,6.9065,8.5411,15725.3,3.5603,83.4354,1332.23,22.7543,4.5661,1.6005,56.814,1.4872,35.776,16.8044,
2022-03-03,1.1076,128.18,1.9558,N/A,25.634,7.4399,N/A,0.82773,378.64,N/A,N/A,N/A,4.7691,N/A,4.9496,10.7688,N/A,N/A,1.0192,143.4,9.8418,7.57,N/A,N/A,15.6897,1.5139,5.6041,1.3992,6.9996,8.6547,15934.42,3.5872,84.174,1334.2,22.8945,4.637,1.6329,57.293,1.5042,36.063,16.8798,
2022-03-02,1.1106,128.08,1.9558,N/A,25.866,7.4387,N/A,0.83316,382.31,N/A,N/A,N/A,4.8021,N/A,4.9493,10.788,N/A,N/A,1.0216,143,9.8826,7.574,N/A,N/A,15.628,1.5272,5.7313,1.4088,7.0153,8.6785,15980.03,3.5954,84.1765,1338.99,22.999,4.6595,1.6404,57.206,1.5059,36.339,17.1904,
2022-03-01,1.1162,128.15,1.9558,N/A,25.465,7.4377,N/A,0.8329,379.6,N/A,N/A,N/A,4.7947,N/A,4.949,10.6893,N/A,N/A,1.0247,142,9.8598,7.567,117.201,N/A,15.5509,1.5365,5.7598,1.4158,7.0462,8.7234,16033.36,3.6152,84.5015,1342.6,22.8558,4.6802,1.6484,57.295,1.515,36.505,17.2145,
2022-02-28,1.1199,129.31,1.9558,N/A,24.997,7.4404,N/A,0.8355,369.72,N/A,N/A,N/A,4.6835,N/A,4.9484,10.6055,N/A,N/A,1.0336,141.8,9.9465,7.5655,115.4842,N/A,15.4532,1.5508,5.7828,1.4264,7.067,8.7514,16100.72,3.63,84.554,1347.62,22.9011,4.7019,1.6628,57.432,1.5201,36.593,17.2863,
2022-02-25,1.1216,129.64,1.9558,N/A,24.66,7.4418,N/A,0.8374,365.28,N/A,N/A,N/A,4.6369,N/A,4.9479,10.5848,N/A,N/A,1.0398,140.8,9.9756,7.5535,92.5673,N/A,15.4799,1.5541,5.738,1.4325,7.0828,8.7578,16088.71,3.6389,84.347,1346.44,22.9145,4.7107,1.6651,57.549,1.5176,36.441,17.0315,
2022-02-24,1.1163,128.28,1.9558,N/A,25.09,7.4405,N/A,0.83463,368.63,N/A,N/A,N/A,4.6554,N/A,4.9501,10.7338,N/A,N/A,1.032,142,10.0878,7.552,95.7175,N/A,16.0525,1.5593,5.6874,1.4316,7.0601,8.7178,16074,3.6618,84.296,1347.7,22.9355,4.6896,1.6692,57.45,1.5125,36.514,17.1634,
2022-02-23,1.1344,130.58,1.9558,N/A,24.473,7.4388,N/A,0.83463,357.25,N/A,N/A,N/A,4.5481,N/A,4.9468,10.5658,N/A,N/A,1.0431,141.2,10.0335,7.5362,90.8791,N/A,15.6871,1.5592,5.6808,1.4394,7.1669,8.8529,16270.12,3.6515,84.6135,1350.23,22.9079,4.748,1.6679,57.98,1.5253,36.601,17.0508,
2022-02-22,1.1342,130.54,1.9558,N/A,24.496,7.4392,N/A,0.83685,355.89,N/A,N/A,N/A,4.5447,N/A,4.9464,10.5996,N/A,N/A,1.0422,141.2,10.1018,7.537,89.8055,N/A,15.6959,1.5739,5.7677,1.4441,7.1771,8.8495,16293.92,3.6584,84.758,1353.34,23.033,4.7472,1.6848,58.208,1.5268,36.748,17.1768,
2022-02-21,1.1338,130.2,1.9558,N/A,24.345,7.4397,N/A,0.83298,357.54,N/A,N/A,N/A,4.5351,N/A,4.9448,10.6535,N/A,N/A,1.0387,141.4,10.1738,7.536,89.0866,N/A,15.4689,1.5751,5.8045,1.4454,7.1831,8.8443,16276.34,3.6433,84.677,1353.02,22.9951,4.7387,1.687,58.3,1.5265,36.588,17.1895,
2022-02-18,1.1354,130.59,1.9558,N/A,24.337,7.4382,N/A,0.83425,356.37,N/A,N/A,N/A,4.5201,N/A,4.9453,10.5796,N/A,N/A,1.0452,140.8,10.1465,7.5355,86.2815,N/A,15.4678,1.5754,5.8435,1.4424,7.184,8.8566,16304.49,3.6276,84.6525,1356.45,23.027,4.7528,1.6896,58.403,1.5255,36.435,17.0858,
2022-02-17,1.137,130.84,1.9558,N/A,24.383,7.4398,N/A,0.83493,356.08,N/A,N/A,N/A,4.5065,N/A,4.9432,10.593,N/A,N/A,1.0466,141.6,10.1225,7.533,86.388,N/A,15.4945,1.5786,5.8495,1.4439,7.206,8.8692,16291.53,3.6231,85.2935,1360.7,23.0367,4.7612,1.695,58.314,1.5278,36.537,16.9893,
2022-02-16,1.1372,131.56,1.9558,N/A,24.365,7.441,N/A,0.8394,355.65,N/A,N/A,N/A,4.4961,N/A,4.9436,10.5363,N/A,N/A,1.0516,141.4,10.1095,7.5295,85.3679,N/A,15.481,1.5859,5.8765,1.4416,7.2101,8.8712,16232.55,3.6256,85.3885,1361.31,23.1718,4.7595,1.7108,58.346,1.5291,36.771,17.214,
2022-02-15,1.1345,131.18,1.9558,N/A,24.419,7.4422,N/A,0.83765,355.33,N/A,N/A,N/A,4.5036,N/A,4.941,10.5739,N/A,N/A,1.0483,141.2,10.0893,7.529,85.5025,N/A,15.4716,1.5888,5.8977,1.4433,7.1969,8.8527,16187.89,3.6596,85.443,1357.5,23.1113,4.7493,1.7143,58.144,1.5265,36.724,17.1767,
2022-02-14,1.1316,130.6,1.9558,N/A,24.527,7.4411,N/A,0.8372,357.06,N/A,N/A,N/A,4.54,N/A,4.9457,10.6158,N/A,N/A,1.0472,142.6,10.0693,7.5293,86.348,N/A,15.351,1.5902,5.8965,1.4431,7.1937,8.8283,16190.53,3.6835,85.4715,1354.5,23.1331,4.742,1.7112,58.114,1.5247,36.8,17.131,
2022-02-11,1.1417,132.24,1.9558,N/A,24.405,7.44,N/A,0.83958,353.38,N/A,N/A,N/A,4.5204,N/A,4.9458,10.553,N/A,N/A,1.0557,141.8,10.0732,7.5312,85.855,N/A,15.4066,1.5927,5.9263,1.4498,7.2564,8.9054,16339.46,3.6958,85.8535,1363.68,23.3183,4.7832,1.7085,58.482,1.5339,37.282,17.2736,
2022-02-10,1.1439,132.42,1.9558,N/A,24.35,7.4404,N/A,0.84248,354.02,N/A,N/A,N/A,4.4921,N/A,4.9451,10.5275,N/A,N/A,1.0571,141.8,10.0693,7.5275,85.0187,N/A,15.4838,1.5894,5.9668,1.4498,7.2722,8.9142,16390.21,3.6796,85.9373,1367.52,23.3584,4.7855,1.7076,58.583,1.5345,37.331,17.3078,
2022-02-09,1.1435,132.04,1.9558,N/A,24.288,7.4437,N/A,0.84255,352.94,N/A,N/A,N/A,4.5135,N/A,4.9449,10.4075,N/A,N/A,1.0555,142.2,10.0585,7.5285,85.5289,N/A,15.551,1.5933,6.0198,1.4514,7.2759,8.9106,16390.99,3.6817,85.5765,1365.72,23.4719,4.7853,1.7107,58.603,1.5349,37.404,17.5281,
2022-02-08,1.1408,131.68,1.9558,N/A,24.259,7.4437,N/A,0.84363,353.09,N/A,N/A,N/A,4.5312,N/A,4.945,10.4433,N/A,N/A,1.0545,142.4,10.0758,7.5215,85.7797,N/A,15.5558,1.6025,6.0209,1.4505,7.2636,8.8923,16418.4,3.6753,85.2545,1367.88,23.5601,4.774,1.7196,58.715,1.5349,37.606,17.638,
2022-02-07,1.1447,131.59,1.9558,N/A,24.222,7.4443,N/A,0.84685,353.48,N/A,N/A,N/A,4.5432,N/A,4.9461,10.4483,N/A,N/A,1.0571,143.4,10.0658,7.52,86.5824,N/A,15.5235,1.6097,6.0541,1.4546,7.2807,8.9202,16478.97,3.6547,85.5345,1371.76,23.575,4.7909,1.7278,58.978,1.5389,37.735,17.7,
2022-02-04,1.1464,131.72,1.9558,N/A,24.36,7.4432,N/A,0.84593,352.92,N/A,N/A,N/A,4.5474,N/A,4.9466,10.4465,N/A,N/A,1.0567,142.8,10.0483,7.5275,87.3095,N/A,15.5072,1.6165,6.083,1.4583,7.2923,8.9286,16493.16,3.6741,85.6445,1374.04,23.5856,4.7914,1.7287,58.754,1.5419,37.797,17.5875,
2022-02-03,1.1286,129.63,1.9558,N/A,24.135,7.4388,N/A,0.83208,353.94,N/A,N/A,N/A,4.5315,N/A,4.9461,10.387,N/A,N/A,1.0407,142.4,9.9545,7.5295,86.1788,N/A,15.3047,1.5849,5.9843,1.4334,7.1795,8.7966,16243.28,3.5949,84.518,1358.42,23.2359,4.7215,1.7001,57.608,1.5212,37.424,17.2864,
2022-02-02,1.1323,129.37,1.9558,N/A,24.298,7.4383,N/A,0.83395,354.45,N/A,N/A,N/A,4.5449,N/A,4.9463,10.385,N/A,N/A,1.0399,143.2,9.9228,7.526,85.815,N/A,15.3011,1.5828,5.9677,1.433,7.2026,8.8245,16243.98,3.5777,84.613,1359.23,23.2134,4.7392,1.701,57.785,1.5254,37.575,17.3459,
2022-02-01,1.126,129.12,1.9558,N/A,24.335,7.4407,N/A,0.83498,356.38,N/A,N/A,N/A,4.5804,N/A,4.9465,10.4438,N/A,N/A,1.0374,143.8,9.9638,7.5275,86.3238,N/A,15.0644,1.5868,5.9572,1.4299,7.1625,8.7779,16126.29,3.566,84.197,1353.61,23.1296,4.7129,1.7032,57.516,1.5199,37.378,17.1633,
2022-01-31,1.1156,128.79,1.9558,N/A,24.372,7.4419,N/A,0.83153,357.19,N/A,N/A,N/A,4.5892,N/A,4.9475,10.489,N/A,N/A,1.0404,143.2,10.0085,7.5293,86.7251,N/A,14.931,1.582,6.003,1.4233,7.0963,8.6994,16036.76,3.564,83.3655,1349.08,23.1856,4.6693,1.6983,56.985,1.511,37.144,17.3734,
2022-01-28,1.1138,128.68,1.9558,N/A,24.443,7.4432,N/A,0.83178,358.42,N/A,N/A,N/A,4.5755,N/A,4.9463,10.552,N/A,N/A,1.0378,144,10.026,7.529,86.6113,N/A,15.1424,1.5971,6.0147,1.4239,7.0857,8.681,16047.76,3.5697,83.6015,1349.47,23.1854,4.6668,1.7031,57.028,1.5109,37.229,17.3844,
2022-01-27,1.116,128.74,1.9558,N/A,24.427,7.4428,N/A,0.83368,358.09,N/A,N/A,N/A,4.5592,N/A,4.9466,10.445,N/A,N/A,1.0391,145.2,9.9903,7.5328,87.139,N/A,15.1946,1.5771,6.0159,1.4161,7.1061,8.6951,16052.42,3.5695,83.7893,1344.5,23.143,4.6844,1.6872,57.295,1.5089,37.124,17.1112,
2022-01-26,1.1277,128.86,1.9558,N/A,24.531,7.442,N/A,0.83458,359.67,N/A,N/A,N/A,4.5864,N/A,4.9451,10.4493,N/A,N/A,1.0386,145.6,10.0115,7.529,89.265,N/A,15.2877,1.5727,6.1084,1.4173,7.1293,8.7791,16185.31,3.5834,84.4288,1350.03,23.1845,4.7268,1.6865,57.728,1.5162,37.169,17.0858,
2022-01-25,1.1268,128.49,1.9558,N/A,24.5,7.4437,N/A,0.83713,359.44,N/A,N/A,N/A,4.5751,N/A,4.9448,10.502,N/A,N/A,1.0364,146,10.1385,7.5295,88.7384,N/A,15.2723,1.5814,6.2049,1.4247,7.1325,8.7725,16169.54,3.5898,84.277,1350.71,23.2909,4.7213,1.6911,57.753,1.5157,37.28,17.2669,
2022-01-24,1.1304,128.62,1.9558,N/A,24.528,7.4431,N/A,0.83803,359.84,N/A,N/A,N/A,4.5572,N/A,4.9453,10.5038,N/A,N/A,1.0308,145.6,10.1638,7.529,88.649,N/A,15.1621,1.5866,6.1901,1.4269,7.1533,8.8003,16213.69,3.5846,84.3495,1352.41,23.2566,4.7352,1.6901,58.045,1.5216,37.382,17.2509,
2022-01-21,1.1348,129.14,1.9558,N/A,24.347,7.4431,N/A,0.83633,358.19,N/A,N/A,N/A,4.5318,N/A,4.9453,10.414,N/A,N/A,1.0353,145.6,10.0523,7.528,86.838,N/A,15.223,1.5774,6.2063,1.4211,7.1946,8.837,16244.2,3.5668,84.419,1351.89,23.2229,4.7508,1.6884,58.171,1.526,37.358,17.1546,
2022-01-20,1.1338,129.53,1.9558,N/A,24.263,7.4424,N/A,0.83265,355.81,N/A,N/A,N/A,4.5228,N/A,4.9453,10.3708,N/A,N/A,1.0382,145.4,9.9578,7.525,86.8952,N/A,15.2094,1.5662,6.1621,1.4158,7.1936,8.8274,16267.5,3.5564,84.362,1349.16,23.1684,4.7489,1.6731,58.285,1.5261,37.319,17.2531,
2022-01-19,1.1345,129.86,1.9558,N/A,24.313,7.4419,N/A,0.83168,355.88,N/A,N/A,N/A,4.5229,N/A,4.9449,10.3428,N/A,N/A,1.0383,145.2,9.9368,7.5238,86.48,N/A,15.4207,1.5709,6.2657,1.4144,7.2003,8.8392,16283.78,3.5529,84.4135,1347.1,23.0922,4.757,1.6684,58.429,1.5293,37.467,17.3889,
2022-01-18,1.1367,130.39,1.9558,N/A,24.426,7.4425,N/A,0.83673,357,N/A,N/A,N/A,4.526,N/A,4.9449,10.3185,N/A,N/A,1.0414,146,9.9638,7.5225,86.7325,N/A,15.4447,1.5833,6.2797,1.4228,7.2212,8.8576,16318.64,3.5557,84.813,1355.33,23.1443,4.7554,1.6798,58.553,1.5349,37.635,17.5398,
2022-01-17,1.1403,130.64,1.9558,N/A,24.467,7.4417,N/A,0.83573,356.09,N/A,N/A,N/A,4.5256,N/A,4.9443,10.305,N/A,N/A,1.0429,146.8,9.9623,7.5275,87.3907,N/A,15.2757,1.5811,6.2808,1.4287,7.2402,8.8844,16337.73,3.5479,84.7295,1359.89,23.1901,4.7704,1.6765,58.496,1.5374,37.761,17.601,
2022-01-14,1.1447,130.17,1.9558,N/A,24.493,7.4414,N/A,0.83508,356.1,N/A,N/A,N/A,4.5414,N/A,4.9429,10.2684,N/A,N/A,1.0429,147,9.9863,7.5205,88.0011,N/A,15.5256,1.5803,6.3361,1.433,7.2728,8.9119,16388.85,3.5565,84.9445,1361.27,23.2684,4.7831,1.6745,58.727,1.5418,38.033,17.6043,
2022-01-13,1.1463,130.98,1.9558,N/A,24.458,7.4409,N/A,0.83545,355.24,N/A,N/A,N/A,4.5361,N/A,4.944,10.238,N/A,N/A,1.0453,147,9.9333,7.5202,86.603,N/A,15.5744,1.5709,6.3518,1.4304,7.2913,8.9289,16379.02,3.5638,84.717,1359.24,23.3894,4.7875,1.6676,58.572,1.5427,38.08,17.6381,
2022-01-12,1.137,131.19,1.9558,N/A,24.423,7.4414,N/A,0.83338,355.98,N/A,N/A,N/A,4.5359,N/A,4.9453,10.264,N/A,N/A,1.0486,147,9.927,7.524,84.7559,N/A,15.5922,1.5762,6.3458,1.4261,7.2379,8.863,16295.93,3.5406,84.0285,1353.27,23.1852,4.7595,1.6775,58.08,1.5358,37.936,17.5645,
2022-01-11,1.1336,130.95,1.9558,N/A,24.412,7.4404,N/A,0.83475,357.45,N/A,N/A,N/A,4.5438,N/A,4.945,10.3075,N/A,N/A,1.0502,147,10.0165,7.5236,84.8663,N/A,15.696,1.5804,6.389,1.4329,7.2255,8.8384,16221.39,3.549,83.7481,1352.85,23.0888,4.7515,1.6772,57.979,1.5342,37.862,17.7094,
2022-01-10,1.1318,130.45,1.9558,N/A,24.357,7.4381,N/A,0.83398,358.4,N/A,N/A,N/A,4.5334,N/A,4.9449,10.3038,N/A,N/A,1.0446,146.2,10.0253,7.5278,84.9825,N/A,15.7183,1.5774,6.3969,1.4327,7.2128,8.8233,16181.9,3.5303,83.8,1355.68,23.0597,4.7536,1.6753,58.141,1.5344,38.074,17.6999,
2022-01-07,1.1298,130.9,1.9558,N/A,24.439,7.438,N/A,0.8343,358.68,N/A,N/A,N/A,4.5496,N/A,4.9451,10.2839,N/A,N/A,1.0422,146,10.0288,7.5214,85.298,N/A,15.7206,1.5804,6.4343,1.4374,7.206,8.8133,16188.43,3.5135,83.978,1359.96,23.1109,4.7553,1.6748,58.046,1.5356,38.074,17.6701,
2022-01-06,1.1315,131.05,1.9558,N/A,24.528,7.4393,N/A,0.83593,359.84,N/A,N/A,N/A,4.5614,N/A,4.9435,10.3265,N/A,N/A,1.0395,146.8,10.035,7.5197,86.5088,N/A,15.5504,1.5778,6.442,1.4451,7.2187,8.8272,16291.88,3.5247,84.2475,1362.06,23.2549,4.767,1.6752,57.943,1.5388,37.962,17.7932,
2022-01-05,1.1319,131.03,1.9558,N/A,24.581,7.4384,N/A,0.83546,362.15,N/A,N/A,N/A,4.5666,N/A,4.946,10.2545,N/A,N/A,1.0364,146.8,9.9672,7.519,85.7275,N/A,15.2446,1.56,6.4146,1.4399,7.2087,8.8227,16263.02,3.4989,84.161,1354.61,23.1422,4.7466,1.6597,57.713,1.534,37.607,17.9369,
2022-01-04,1.1279,131.17,1.9558,N/A,24.745,7.4378,N/A,0.83618,365.12,N/A,N/A,N/A,4.5667,N/A,4.9481,10.2808,N/A,N/A,1.0355,147.8,10.0138,7.5185,84.9202,N/A,15.1384,1.5682,6.4174,1.4382,7.1924,8.7919,16199.73,3.4909,84.2055,1352.91,23.1808,4.7214,1.6668,57.988,1.531,37.582,18.108,
2022-01-03,1.1355,130.56,1.9558,N/A,24.818,7.4382,N/A,0.84135,367.71,N/A,N/A,N/A,4.5895,N/A,4.9483,10.2958,N/A,N/A,1.0372,147.6,10.0013,7.519,84.5313,N/A,15.0777,1.5691,6.3539,1.442,7.2174,8.8541,16202.02,3.5139,84.3949,1354.4,23.2259,4.7379,1.6651,58.051,1.5333,37.665,17.9661,
1 Date USD JPY BGN CYP CZK DKK EEK GBP HUF LTL LVL MTL PLN ROL RON SEK SIT SKK CHF ISK NOK HRK RUB TRL TRY AUD BRL CAD CNY HKD IDR ILS INR KRW MXN MYR NZD PHP SGD THB ZAR
2 2022-12-30 1.0666 140.66 1.9558 N/A 24.116 7.4365 N/A 0.88693 400.87 N/A N/A N/A 4.6808 N/A 4.9495 11.1218 N/A N/A 0.9847 151.5 10.5138 7.5365 N/A N/A 19.9649 1.5693 5.6386 1.444 7.3582 8.3163 16519.82 3.7554 88.171 1344.09 20.856 4.6984 1.6798 59.32 1.43 36.835 18.0986
3 2022-12-29 1.0649 142.24 1.9558 N/A 24.191 7.4365 N/A 0.88549 399.6 N/A N/A N/A 4.6855 N/A 4.9493 11.158 N/A N/A 0.984 152.5 10.55 7.5365 N/A N/A 19.934 1.5859 5.5351 1.4475 7.4151 8.2994 16680.38 3.7575 88.2295 1350.18 20.651 4.7106 1.6887 59.367 1.436 36.877 18.1967
4 2022-12-28 1.064 142.21 1.9558 N/A 24.252 7.4365 N/A 0.88058 403.3 N/A N/A N/A 4.7008 N/A 4.946 11.1038 N/A N/A 0.9863 151.9 10.4495 7.5365 N/A N/A 19.9144 1.566 5.6109 1.4361 7.4224 8.2931 16765.93 3.7526 88.0943 1348.59 20.6856 4.7055 1.6772 59.613 1.4323 36.953 18.289
5 2022-12-27 1.0624 141.68 1.9558 N/A 24.26 7.4366 N/A 0.88333 401.65 N/A N/A N/A 4.6683 N/A 4.927 11.1285 N/A N/A 0.9885 152.3 10.4895 7.5375 N/A N/A 19.8799 1.577 5.6035 1.4384 7.3994 8.2874 16620.58 3.7278 88.0808 1349.85 20.5515 4.699 1.6916 59.356 1.43 36.775 18.3181
6 2022-12-23 1.0622 140.86 1.9558 N/A 24.247 7.4364 N/A 0.8803 400.68 N/A N/A N/A 4.6423 N/A 4.9056 11.1045 N/A N/A 0.9867 152.3 10.4448 7.537 N/A N/A 19.843 1.5857 5.4834 1.4433 7.4198 8.2878 16569.18 3.704 87.958 1359.5 20.7115 4.7002 1.6887 58.623 1.4337 36.842 18.1048
7 2022-12-22 1.0633 140.42 1.9558 N/A 24.215 7.4367 N/A 0.88243 402.13 N/A N/A N/A 4.6443 N/A 4.8993 11.05 N/A N/A 0.9852 153.3 10.4123 7.538 N/A N/A 19.8553 1.5804 5.5386 1.4484 7.4229 8.2883 16525.91 3.6942 88.0365 1361.75 20.8485 4.7051 1.6918 58.705 1.4356 36.849 18.2238
8 2022-12-21 1.0636 140.29 1.9558 N/A 24.218 7.438 N/A 0.87651 402.93 N/A N/A N/A 4.6665 N/A 4.8937 11.0623 N/A N/A 0.9836 152.1 10.4309 7.5419 N/A N/A 19.8541 1.5859 5.4913 1.4475 7.4219 8.2902 16573.77 3.6989 88.109 1367.63 20.9919 4.7197 1.685 58.556 1.4366 36.907 18.3529
9 2022-12-20 1.0599 140.58 1.9558 N/A 24.181 7.4388 N/A 0.8753 403.88 N/A N/A N/A 4.6757 N/A 4.9125 11.0615 N/A N/A 0.9854 151.5 10.5098 7.5471 N/A N/A 19.7744 1.5972 5.6234 1.4451 7.39 8.2488 16537.09 3.6759 87.6649 1363.73 20.9355 4.6991 1.6816 58.549 1.4347 36.853 18.4239
10 2022-12-19 1.0598 144.65 1.9558 N/A 24.233 7.4382 N/A 0.87118 403.18 N/A N/A N/A 4.6853 N/A 4.9107 11.0063 N/A N/A 0.9884 151.9 10.5025 7.5395 N/A N/A 19.7676 1.5794 5.6327 1.4472 7.3901 8.2428 16506.72 3.6551 87.5321 1377.17 20.9743 4.6912 1.6632 58.649 1.4378 36.923 18.3074
11 2022-12-16 1.0619 145.53 1.9558 N/A 24.262 7.4379 N/A 0.87233 407.1 N/A N/A N/A 4.6925 N/A 4.9213 11.0153 N/A N/A 0.9879 150.1 10.4833 7.5385 N/A N/A 19.8039 1.5866 5.6233 1.4506 7.4037 8.2632 16575.47 3.6689 87.824 1389.7 21.0634 4.6984 1.6687 58.967 1.4413 37.145 18.6708
12 2022-12-15 1.0621 145.07 1.9558 N/A 24.27 7.4387 N/A 0.86194 406.4 N/A N/A N/A 4.689 N/A 4.922 10.898 N/A N/A 0.9862 150.9 10.4013 7.5395 N/A N/A 19.806 1.5695 5.6247 1.4443 7.4007 8.2551 16591.4 3.6388 87.9355 1393.97 20.9431 4.6918 1.6628 59.297 1.4406 37.12 18.3599
13 2022-12-14 1.0649 143.68 1.9558 N/A 24.276 7.4392 N/A 0.86118 406.63 N/A N/A N/A 4.681 N/A 4.9248 10.8638 N/A N/A 0.9865 150.9 10.362 7.538 N/A N/A 19.8579 1.551 5.6842 1.4441 7.4009 8.2751 16599.51 3.6327 87.8435 1379.99 20.8635 4.6765 1.6508 59.326 1.4349 36.851 18.2563
14 2022-12-13 1.0545 144.85 1.9558 N/A 24.287 7.4391 N/A 0.85753 409.65 N/A N/A N/A 4.6938 N/A 4.9298 10.8965 N/A N/A 0.9869 151.1 10.4679 7.5495 N/A N/A 19.6649 1.5553 5.5784 1.4341 7.3637 8.2033 16521.81 3.6266 87.2965 1378.75 20.9435 4.6704 1.6464 58.852 1.4288 36.707 18.6855
15 2022-12-12 1.0562 144.86 1.9558 N/A 24.307 7.4379 N/A 0.86006 416.78 N/A N/A N/A 4.6923 N/A 4.9318 10.9075 N/A N/A 0.9855 150.7 10.5548 7.554 N/A N/A 19.6913 1.5625 5.556 1.4428 7.367 8.2103 16524.63 3.6232 87.253 1377.93 20.9047 4.6652 1.6523 58.788 1.4284 36.708 18.4697
16 2022-12-09 1.0559 143.3 1.9558 N/A 24.293 7.4379 N/A 0.8595 417.53 N/A N/A N/A 4.6869 N/A 4.9224 10.9188 N/A N/A 0.9856 149.5 10.5345 7.555 N/A N/A 19.6872 1.5553 5.5457 1.438 7.3475 8.2169 16453.46 3.6128 86.9535 1373.94 20.849 4.6512 1.6482 58.47 1.426 36.656 18.2358
17 2022-12-08 1.0519 143.75 1.9558 N/A 24.324 7.4382 N/A 0.86258 417.66 N/A N/A N/A 4.6853 N/A 4.9131 10.906 N/A N/A 0.9889 149.5 10.488 7.5553 N/A N/A 19.6114 1.559 5.488 1.4307 7.3324 8.1889 16423.92 3.6206 86.6755 1387.06 20.6989 4.6257 1.6547 58.233 1.4256 36.559 18.0225
18 2022-12-07 1.0529 144.44 1.9558 N/A 24.322 7.4382 N/A 0.86408 410.63 N/A N/A N/A 4.7003 N/A 4.918 10.919 N/A N/A 0.9893 148.7 10.5255 7.5525 N/A N/A 19.6256 1.5728 5.5023 1.4387 7.3476 8.1997 16465.17 3.626 86.692 1390.87 20.7534 4.6301 1.6573 58.432 1.4286 36.904 18.1353
19 2022-12-06 1.0516 143.33 1.9558 N/A 24.316 7.438 N/A 0.8617 415.08 N/A N/A N/A 4.6975 N/A 4.913 10.889 N/A N/A 0.9872 148.9 10.4408 7.5563 N/A N/A 19.601 1.5625 5.5113 1.4326 7.3494 8.1813 16441.49 3.5831 86.6485 1386.39 20.6884 4.6223 1.6583 58.782 1.4263 36.827 18.2068
20 2022-12-05 1.0587 143.07 1.9558 N/A 24.351 7.4369 N/A 0.86085 412.13 N/A N/A N/A 4.695 N/A 4.9215 10.8931 N/A N/A 0.9893 148.9 10.3366 7.551 N/A N/A 19.7326 1.5542 5.5491 1.4198 7.3573 8.2236 16332.36 3.5856 86.5249 1370.87 20.7295 4.6255 1.6498 59.245 1.4271 36.732 18.2038
21 2022-12-02 1.0538 141.32 1.9558 N/A 24.377 7.4373 N/A 0.85855 410 N/A N/A N/A 4.684 N/A 4.9298 10.902 N/A N/A 0.9834 148.7 10.2615 7.5503 N/A N/A 19.6392 1.5457 5.4657 1.416 7.3971 8.2035 16179.78 3.5769 85.6435 1366.67 20.187 4.6241 1.6453 58.734 1.4227 36.614 18.2749
22 2022-12-01 1.0454 142.48 1.9558 N/A 24.361 7.4373 N/A 0.85715 413.5 N/A N/A N/A 4.6998 N/A 4.9303 10.8984 N/A N/A 0.9868 148.7 10.2495 7.55 N/A N/A 19.4778 1.5377 5.4508 1.4059 7.3965 8.1371 16160.84 3.5642 84.933 1363.81 20.1472 4.605 1.6446 58.793 1.4195 36.526 18.5393
23 2022-11-30 1.0376 144.28 1.9558 N/A 24.338 7.4366 N/A 0.86488 408.4 N/A N/A N/A 4.6635 N/A 4.9245 10.9345 N/A N/A 0.9854 147.1 10.2648 7.549 N/A N/A 19.3333 1.5425 5.5063 1.4021 7.3437 8.0944 16271.81 3.5691 84.4215 1365.14 20.0111 4.6147 1.6634 58.697 1.418 36.588 17.5768
24 2022-11-29 1.0366 143.36 1.9558 N/A 24.334 7.4367 N/A 0.86218 406.5 N/A N/A N/A 4.673 N/A 4.9193 10.901 N/A N/A 0.9862 147.1 10.3313 7.55 N/A N/A 19.3181 1.5414 5.5126 1.4005 7.4289 8.0965 16301.58 3.5581 84.6548 1375.7 19.8075 4.6735 1.6639 58.64 1.4237 36.706 17.6027
25 2022-11-28 1.0463 144.9 1.9558 N/A 24.348 7.4367 N/A 0.86606 408.87 N/A N/A N/A 4.6938 N/A 4.9246 10.8973 N/A N/A 0.9872 146.7 10.364 7.5488 N/A N/A 19.4844 1.5632 5.6354 1.4062 7.5326 8.1782 16440.45 3.6002 85.437 1396.56 20.22 4.6874 1.6827 59.21 1.4375 37.285 17.9376
26 2022-11-25 1.0375 144.62 1.9558 N/A 24.367 7.4365 N/A 0.85885 411.33 N/A N/A N/A 4.6875 N/A 4.9255 10.8183 N/A N/A 0.9836 146.5 10.2985 7.5473 N/A N/A 19.3333 1.5404 5.5476 1.3864 7.4425 8.1084 16282.44 3.5551 84.7145 1383.2 20.1069 4.648 1.6651 58.795 1.4277 37.153 17.7677
27 2022-11-24 1.0413 143.9 1.9558 N/A 24.392 7.4369 N/A 0.85933 413.33 N/A N/A N/A 4.6958 N/A 4.9205 10.8573 N/A N/A 0.9818 146.5 10.3435 7.547 N/A N/A 19.3969 1.5414 5.5504 1.3894 7.4442 8.1324 16295.35 3.5607 85.0295 1382.28 20.1501 4.6806 1.6598 58.992 1.4319 37.258 17.7246
28 2022-11-23 1.0325 145.75 1.9558 N/A 24.356 7.437 N/A 0.86369 405.75 N/A N/A N/A 4.7033 N/A 4.937 10.8933 N/A N/A 0.9795 146.7 10.3659 7.5435 N/A N/A 19.2316 1.5522 5.565 1.3856 7.3982 8.0708 16189.81 3.5681 84.466 1397.42 20.001 4.7237 1.6718 58.914 1.4295 37.423 17.7103
29 2022-11-22 1.0274 145.2 1.9558 N/A 24.351 7.4377 N/A 0.86358 408.23 N/A N/A N/A 4.7125 N/A 4.9269 10.9653 N/A N/A 0.9791 145.7 10.4445 7.5438 N/A N/A 19.1221 1.5473 5.4578 1.3765 7.3344 8.0313 16106.79 3.5615 83.8768 1392.68 20.0951 4.7055 1.6707 58.942 1.4167 37.11 17.7568
30 2022-11-21 1.0246 145.33 1.9558 N/A 24.356 7.4377 N/A 0.86793 409.43 N/A N/A N/A 4.7075 N/A 4.9413 10.9873 N/A N/A 0.9817 147.9 10.4898 7.5425 N/A N/A 19.0822 1.5471 5.4401 1.377 7.3419 7.9989 16116.76 3.5515 83.7375 1395 19.9357 4.6927 1.6766 58.822 1.4162 37.121 17.7858
31 2022-11-18 1.0366 145.12 1.9558 N/A 24.351 7.4385 N/A 0.87063 407.41 N/A N/A N/A 4.7033 N/A 4.9413 10.9805 N/A N/A 0.9881 148.9 10.486 7.5415 N/A N/A 19.3009 1.5433 5.547 1.3841 7.379 8.1092 16224.36 3.591 84.6875 1389.02 20.162 4.7202 1.6757 59.41 1.4229 37.069 17.908
32 2022-11-17 1.0319 144.8 1.9558 N/A 24.399 7.4383 N/A 0.87475 415.6 N/A N/A N/A 4.7153 N/A 4.9254 10.9871 N/A N/A 0.9818 148.9 10.498 7.541 N/A N/A 19.2124 1.5526 5.6535 1.382 7.3859 8.077 16224.01 3.5796 84.394 1394.06 20.062 4.7122 1.6986 59.293 1.4221 37.123 18.0961
33 2022-11-16 1.0412 145.29 1.9558 N/A 24.355 7.4386 N/A 0.87483 408.18 N/A N/A N/A 4.7065 N/A 4.9206 10.8754 N/A N/A 0.9795 148.9 10.3675 7.5443 N/A N/A 19.3783 1.54 5.5438 1.3801 7.372 8.1444 16248.37 3.5684 84.5905 1378.1 20.1227 4.7323 1.6897 59.678 1.425 37.103 18.0195
34 2022-11-15 1.0404 144.84 1.9558 N/A 24.326 7.4388 N/A 0.87455 405.45 N/A N/A N/A 4.7073 N/A 4.9116 10.8081 N/A N/A 0.979 149.9 10.357 7.5459 N/A N/A 19.3608 1.5415 5.548 1.3816 7.3299 8.143 16164.78 3.5694 84.1304 1365.61 20.0795 4.7208 1.6897 59.532 1.4238 36.939 17.8822
35 2022-11-14 1.0319 144.86 1.9558 N/A 24.289 7.4382 N/A 0.87513 407.28 N/A N/A N/A 4.6898 N/A 4.9043 10.7713 N/A N/A 0.9751 150.3 10.3143 7.5465 N/A N/A 19.1923 1.5427 5.4605 1.3706 7.2906 8.0852 16052.12 3.541 83.7779 1369.32 20.0985 4.7429 1.6957 59.04 1.4177 36.978 17.8393
36 2022-11-11 1.0308 143.89 1.9558 N/A 24.278 7.4384 N/A 0.87538 402.08 N/A N/A N/A 4.6765 N/A 4.894 10.7241 N/A N/A 0.9844 148.7 10.2635 7.5445 N/A N/A 19.0987 1.5459 5.5147 1.3698 7.3267 8.0758 15979.45 3.5255 83.2253 1359.2 20.0239 4.77 1.702 59.106 1.4199 37.088 17.7944
37 2022-11-10 0.9954 145.47 1.9558 N/A 24.361 7.4381 N/A 0.87298 400.95 N/A N/A N/A 4.706 N/A 4.8913 10.8743 N/A N/A 0.9834 147.5 10.3615 7.5427 N/A N/A 18.51 1.5525 5.286 1.3467 7.2184 7.8128 15615.6 3.5453 81.3058 1373.96 19.4562 4.6789 1.6984 57.793 1.3963 36.7 17.6882
38 2022-11-09 1.0039 146.82 1.9558 N/A 24.337 7.4382 N/A 0.87774 403.53 N/A N/A N/A 4.701 N/A 4.9045 10.845 N/A N/A 0.988 146.7 10.322 7.5425 N/A N/A 18.6728 1.5538 5.1947 1.3501 7.2813 7.8801 15717.07 3.5621 81.6575 1369.73 19.6554 4.7098 1.7033 58.236 1.4061 36.999 17.877
39 2022-11-08 0.9996 146.25 1.9558 N/A 24.326 7.4378 N/A 0.87378 400.75 N/A N/A N/A 4.6918 N/A 4.8978 10.8373 N/A N/A 0.9911 146.3 10.2795 7.539 N/A N/A 18.5991 1.5435 5.203 1.3489 7.2495 7.8468 15652.76 3.5436 81.518 1377.94 19.4495 4.7346 1.686 58.187 1.4022 37.22 17.8397
40 2022-11-07 0.9993 146.18 1.9558 N/A 24.301 7.4393 N/A 0.87135 401.03 N/A N/A N/A 4.6865 N/A 4.8855 10.832 N/A N/A 0.9874 145.9 10.2555 7.5375 N/A N/A 18.5875 1.5428 5.07 1.3464 7.2189 7.8444 15648.95 3.5402 81.8407 1391.25 19.4395 4.7362 1.6834 58.361 1.4022 37.284 17.7583
41 2022-11-04 0.9872 145.19 1.9558 N/A 24.422 7.4419 N/A 0.87478 401.15 N/A N/A N/A 4.6825 N/A 4.8893 10.8538 N/A N/A 0.9863 145.5 10.2019 7.5353 N/A N/A 18.3845 1.5311 4.9682 1.3351 7.0894 7.7493 15491.81 3.5065 81.02 1397.7 19.2611 4.6872 1.6769 57.672 1.3891 36.906 17.7983
42 2022-11-03 0.9753 144.58 1.9558 N/A 24.539 7.4433 N/A 0.87228 407.87 N/A N/A N/A 4.709 N/A 4.9013 10.932 N/A N/A 0.9889 144.9 10.3543 7.5375 N/A N/A 18.1602 1.5517 5.0262 1.3452 7.1367 7.656 15400.2 3.4847 80.8845 1391.75 19.2363 4.6271 1.6957 57.463 1.3878 37.091 18.0173
43 2022-11-02 0.9908 145.75 1.9558 N/A 24.506 7.4431 N/A 0.861 407 N/A N/A N/A 4.7035 N/A 4.912 10.9065 N/A N/A 0.9861 143.7 10.2388 7.5335 N/A N/A 18.4488 1.5426 5.0964 1.347 7.2156 7.7774 15492.57 3.4987 81.992 1402.01 19.4921 4.6944 1.6844 57.841 1.3983 37.314 17.9608
44 2022-11-01 0.9947 146.35 1.9558 N/A 24.484 7.4438 N/A 0.86058 406.9 N/A N/A N/A 4.7053 N/A 4.9138 10.874 N/A N/A 0.9878 143.3 10.1835 7.5342 N/A N/A 18.5216 1.5409 5.1337 1.3469 7.2165 7.8079 15534.6 3.4922 82.084 1404.63 19.5984 4.7119 1.6876 57.786 1.4017 37.45 17.9802
45 2022-10-31 0.9914 147.4 1.9558 N/A 24.488 7.4444 N/A 0.86115 409.65 N/A N/A N/A 4.7085 N/A 4.9143 10.901 N/A N/A 0.9925 143.3 10.3028 7.531 N/A N/A 18.4562 1.5529 5.2694 1.3553 7.238 7.7822 15489.55 3.4933 82.1035 1416.12 19.7122 4.6873 1.7099 57.8 1.4038 37.748 18.1736
46 2022-10-28 0.9951 146.79 1.9558 N/A 24.465 7.4423 N/A 0.8612 411.7 N/A N/A N/A 4.7275 N/A 4.9189 10.9403 N/A N/A 0.992 143.3 10.2695 7.532 N/A N/A 18.5219 1.5511 5.327 1.3542 7.2159 7.8107 15481.88 3.5215 82.0565 1417.7 19.7718 4.6994 1.7151 57.739 1.4055 37.724 18.053
47 2022-10-27 1.0037 147.37 1.9558 N/A 24.53 7.4387 N/A 0.86745 412.15 N/A N/A N/A 4.7585 N/A 4.8893 10.9583 N/A N/A 0.9949 143.1 10.342 7.533 N/A N/A 18.681 1.561 5.3889 1.3672 7.2552 7.8782 15629.06 3.5376 82.656 1428.57 20.015 4.7324 1.7316 58.441 1.4154 37.975 18.1521
48 2022-10-26 1.0023 147.32 1.9558 N/A 24.535 7.4381 N/A 0.86603 408.09 N/A N/A N/A 4.7548 N/A 4.8806 10.953 N/A N/A 0.9917 143.5 10.3408 7.532 N/A N/A 18.6461 1.5466 5.2944 1.3568 7.1948 7.8678 15589.27 3.5145 82.206 1422.11 19.8501 4.7262 1.7249 58.493 1.4104 37.862 18.0212
49 2022-10-25 0.9861 146.84 1.9558 N/A 24.472 7.4387 N/A 0.87143 413.7 N/A N/A N/A 4.777 N/A 4.9036 10.9728 N/A N/A 0.9888 142.9 10.391 7.5315 N/A N/A 18.3508 1.5599 5.2254 1.3537 7.2072 7.7407 15407.12 3.506 81.653 1417.5 19.6353 4.6697 1.7321 57.988 1.405 37.758 18.2211
50 2022-10-24 0.9851 146.76 1.9558 N/A 24.482 7.4385 N/A 0.8707 411.88 N/A N/A N/A 4.7908 N/A 4.9128 11.0795 N/A N/A 0.9856 142.5 10.392 7.5337 N/A N/A 18.3298 1.5631 5.1461 1.3502 7.1544 7.7329 15362.63 3.4997 81.5451 1418.4 19.6514 4.6674 1.7343 58.021 1.4008 37.6 18.0625
51 2022-10-21 0.973 147.59 1.9558 N/A 24.511 7.4382 N/A 0.87728 412.88 N/A N/A N/A 4.7885 N/A 4.9125 11.0868 N/A N/A 0.9855 141.1 10.4315 7.5325 N/A N/A 18.0988 1.5646 5.1117 1.3465 7.0504 7.6376 15199.12 3.4803 80.739 1404.32 19.5521 4.6101 1.7347 57.287 1.3917 37.349 18.0021
52 2022-10-20 0.9811 146.99 1.9558 N/A 24.525 7.4389 N/A 0.87258 411.2 N/A N/A N/A 4.7728 N/A 4.9203 10.982 N/A N/A 0.9836 141.1 10.402 7.5353 N/A N/A 18.2257 1.5554 5.1387 1.3461 7.0858 7.7008 15250.05 3.4754 81.1755 1400.3 19.7005 4.6396 1.7206 57.742 1.3959 37.36 17.9106
53 2022-10-19 0.9778 146.34 1.9558 N/A 24.563 7.439 N/A 0.86993 413.78 N/A N/A N/A 4.7878 N/A 4.9248 10.9448 N/A N/A 0.981 141.1 10.3823 7.5325 N/A N/A 18.1793 1.5568 5.1755 1.3479 7.0672 7.6757 15185.1 3.4628 81.1955 1398.35 19.6845 4.6152 1.7264 57.741 1.3931 37.469 17.8339
54 2022-10-18 0.9835 146.65 1.9558 N/A 24.593 7.4393 N/A 0.86928 413.08 N/A N/A N/A 4.804 N/A 4.9359 10.906 N/A N/A 0.9792 141.5 10.3528 7.5298 N/A N/A 18.2813 1.5557 5.1795 1.3495 7.0805 7.72 15214.98 3.464 80.9195 1400.92 19.664 4.6382 1.7251 57.897 1.3963 37.422 17.7904
55 2022-10-17 0.9739 145 1.9558 N/A 24.562 7.4379 N/A 0.8625 418.3 N/A N/A N/A 4.8143 N/A 4.937 10.9893 N/A N/A 0.9762 140.9 10.342 7.5265 N/A N/A 18.1043 1.5599 5.1497 1.3452 7.013 7.6448 15061.8 3.4486 80.128 1399.41 19.5 4.5934 1.7404 57.433 1.3896 37.169 17.6769
56 2022-10-14 0.9717 143.63 1.9558 N/A 24.587 7.4378 N/A 0.86823 418.24 N/A N/A N/A 4.8328 N/A 4.9335 11.0035 N/A N/A 0.9757 140.5 10.3323 7.5266 N/A N/A 18.0614 1.5493 5.1177 1.3426 6.9952 7.6278 15031.5 3.444 79.9695 1398.5 19.5032 4.5689 1.7302 57.375 1.3852 37.109 17.6932
57 2022-10-13 0.9739 142.94 1.9558 N/A 24.569 7.4385 N/A 0.86513 430.65 N/A N/A N/A 4.8303 N/A 4.9355 11.0098 N/A N/A 0.9725 140.5 10.3525 7.531 N/A N/A 18.1041 1.5495 5.1214 1.3443 6.9945 7.644 14952.86 3.4731 79.9981 1392.71 19.4442 4.5691 1.7314 57.352 1.3949 36.843 17.8173
58 2022-10-12 0.9706 142.34 1.9558 N/A 24.561 7.4399 N/A 0.8784 429.65 N/A N/A N/A 4.8495 N/A 4.94 11.02 N/A N/A 0.9664 140.1 10.4145 7.529 N/A N/A 18.0427 1.5525 5.1378 1.3395 6.9603 7.6192 14907.04 3.4623 79.8955 1384.66 19.4522 4.5448 1.7372 57.148 1.3941 36.902 17.6876
59 2022-10-11 0.9723 141.54 1.9558 N/A 24.535 7.439 N/A 0.87703 428.73 N/A N/A N/A 4.869 N/A 4.9394 11.0015 N/A N/A 0.9675 140.7 10.4235 7.5293 N/A N/A 18.0686 1.545 5.0456 1.3402 6.9669 7.6325 14930.83 3.4776 79.9555 1392.84 19.4115 4.5436 1.7323 57.243 1.3967 37.03 17.6153
60 2022-10-10 0.9697 141.16 1.9558 N/A 24.521 7.4384 N/A 0.8773 428.2 N/A N/A N/A 4.8655 N/A 4.94 10.9502 N/A N/A 0.968 139.9 10.3378 7.528 N/A N/A 18.0131 1.536 5.0328 1.3312 6.9344 7.612 14872.51 3.4463 79.9678 1384.26 19.3588 4.5091 1.7369 57.197 1.3939 36.81 17.5866
61 2022-10-07 0.9797 141.92 1.9558 N/A 24.517 7.4381 N/A 0.87383 423.85 N/A N/A N/A 4.8595 N/A 4.9415 10.8555 N/A N/A 0.97 140.7 10.4498 7.527 N/A N/A 18.209 1.5266 5.1075 1.3437 6.9715 7.6906 14933.14 3.4477 80.546 1381.42 19.643 4.5556 1.7328 57.747 1.3996 36.602 17.6222
62 2022-10-06 0.986 142.68 1.9558 N/A 24.479 7.439 N/A 0.87583 422.59 N/A N/A N/A 4.8505 N/A 4.9364 10.8728 N/A N/A 0.9709 139.9 10.4278 7.5288 N/A N/A 18.3191 1.5263 5.1185 1.3475 7.0164 7.74 15021.24 3.4846 81.0615 1388.39 19.817 4.5726 1.728 57.949 1.4057 36.827 17.5769
63 2022-10-05 0.9915 143.18 1.9558 N/A 24.524 7.4388 N/A 0.8734 423.6 N/A N/A N/A 4.791 N/A 4.9385 10.8376 N/A N/A 0.9756 141.3 10.4858 7.5255 N/A N/A 18.4201 1.538 5.1575 1.3493 7.0555 7.7831 15061.81 3.503 80.909 1406.71 19.8625 4.5911 1.7419 58.212 1.4124 37.102 17.6228
64 2022-10-04 0.9891 143.3 1.9558 N/A 24.544 7.4374 N/A 0.87273 417.68 N/A N/A N/A 4.8193 N/A 4.9418 10.8166 N/A N/A 0.9767 141.9 10.4915 7.523 N/A N/A 18.3374 1.5318 5.0589 1.3503 7.0384 7.7644 15080.18 3.4885 80.6995 1412.2 19.777 4.5939 1.7368 58.104 1.4148 37.16 17.5437
65 2022-10-03 0.9764 141.49 1.9558 N/A 24.527 7.4366 N/A 0.8707 424.86 N/A N/A N/A 4.832 N/A 4.9479 10.8743 N/A N/A 0.9658 141.7 10.5655 7.5275 N/A N/A 18.124 1.5128 5.178 1.3412 6.9481 7.6647 14969.79 3.498 79.898 1408.25 19.604 4.5383 1.7263 57.599 1.4015 37.181 17.5871
66 2022-09-30 0.9748 141.01 1.9558 N/A 24.549 7.4365 N/A 0.883 422.18 N/A N/A N/A 4.8483 N/A 4.949 10.8993 N/A N/A 0.9561 140.9 10.5838 7.524 N/A N/A 18.0841 1.5076 5.2584 1.3401 6.9368 7.6521 14863.26 3.4759 79.425 1400.69 19.6393 4.5201 1.7177 57.276 1.4001 36.823 17.5353
67 2022-09-29 0.9706 140.46 1.9558 N/A 24.687 7.4365 N/A 0.89485 421.93 N/A N/A N/A 4.857 N/A 4.9481 10.958 N/A N/A 0.9538 140.1 10.4518 7.528 N/A N/A 18 1.4982 5.2521 1.3294 6.9223 7.6192 14735.97 3.4422 79.314 1388.34 19.5779 4.4992 1.704 56.86 1.3961 36.946 17.4466
68 2022-09-28 0.9565 138.39 1.9558 N/A 24.65 7.4368 N/A 0.90268 411.72 N/A N/A N/A 4.8043 N/A 4.9485 10.9194 N/A N/A 0.9437 139.7 10.4576 7.5313 N/A N/A 17.7311 1.4924 5.1728 1.3157 6.9199 7.5084 14622.96 3.3931 78.2655 1378.84 19.5294 4.4281 1.6998 56.528 1.3846 36.687 17.2916
69 2022-09-27 0.9644 139.28 1.9558 N/A 24.661 7.4366 N/A 0.89275 406.65 N/A N/A N/A 4.764 N/A 4.9444 10.8533 N/A N/A 0.9503 139.3 10.3473 7.528 N/A N/A 17.824 1.4859 5.1235 1.3196 6.9156 7.5704 14604.52 3.3714 78.574 1370.06 19.5832 4.4466 1.6921 56.933 1.3838 36.565 17.2361
70 2022-09-26 0.9646 139.07 1.9558 N/A 24.64 7.4365 N/A 0.89404 408.83 N/A N/A N/A 4.7608 N/A 4.9418 10.9275 N/A N/A 0.9555 138.9 10.3585 7.5278 N/A N/A 17.8001 1.4858 5.1504 1.3195 6.9075 7.572 14620.74 3.4069 78.704 1379.4 19.6066 4.4401 1.6886 56.908 1.3842 36.496 17.4247
71 2022-09-23 0.9754 139.43 1.9558 N/A 24.658 7.4365 N/A 0.88201 406.3 N/A N/A N/A 4.7543 N/A 4.9433 10.9328 N/A N/A 0.9565 139.9 10.2335 7.5228 N/A N/A 17.9515 1.4828 5.0456 1.3177 6.9442 7.6567 14697.3 3.4152 79.0705 1381.97 19.5708 4.4659 1.6846 57.217 1.3897 36.636 17.3853
72 2022-09-22 0.9884 139.18 1.9558 N/A 24.657 7.4365 N/A 0.87256 405.25 N/A N/A N/A 4.7592 N/A 4.9411 10.8724 N/A N/A 0.9684 139.9 10.235 7.5235 N/A N/A 18.1559 1.484 5.0677 1.3278 6.9804 7.7583 14824.28 3.4216 79.897 1384.79 19.6129 4.514 1.6832 57.721 1.3998 36.803 17.3514
73 2022-09-21 0.9906 142.66 1.9558 N/A 24.637 7.4364 N/A 0.87335 405.1 N/A N/A N/A 4.7505 N/A 4.9443 10.9214 N/A N/A 0.9549 140.3 10.2858 7.5205 N/A N/A 18.149 1.4851 5.0924 1.3262 6.9821 7.7761 14866.28 3.4298 79.1555 1381.38 19.7847 4.5097 1.6844 57.285 1.4006 36.786 17.4879
74 2022-09-20 0.9986 143.34 1.9558 N/A 24.556 7.4368 N/A 0.87395 398.58 N/A N/A N/A 4.7208 N/A 4.934 10.8338 N/A N/A 0.9644 140.9 10.273 7.5198 N/A N/A 18.2833 1.4893 5.2139 1.3268 7.003 7.8382 14997.82 3.4406 79.6095 1390.71 19.9667 4.5516 1.6908 57.497 1.4074 36.968 17.7261
75 2022-09-19 0.999 143.42 1.9558 N/A 24.494 7.4373 N/A 0.87785 400.85 N/A N/A N/A 4.7058 N/A 4.93 10.7993 N/A N/A 0.9658 139.9 10.2826 7.5215 N/A N/A 18.2738 1.495 5.2886 1.3294 7.0066 7.8416 14975.43 3.446 79.653 1391.82 20.113 4.5455 1.6807 57.347 1.4082 36.983 17.7267
76 2022-09-16 0.9954 142.53 1.9558 N/A 24.497 7.4366 N/A 0.874 403.98 N/A N/A N/A 4.7143 N/A 4.9238 10.7541 N/A N/A 0.9579 138.3 10.1985 7.5235 N/A N/A 18.1923 1.4894 5.2279 1.3226 6.9787 7.8133 14904.67 3.4267 79.3605 1383.58 20.0028 4.5141 1.6717 57.111 1.4025 36.8 17.6004
77 2022-09-15 0.9992 143.43 1.9558 N/A 24.518 7.4366 N/A 0.86934 407.15 N/A N/A N/A 4.7273 N/A 4.9238 10.69 N/A N/A 0.9572 138.7 10.1203 7.5258 N/A N/A 18.2477 1.4853 5.1837 1.3172 6.9852 7.8423 14925.35 3.4384 79.7119 1397.18 20.0021 4.5314 1.6689 57.258 1.4062 36.816 17.5283
78 2022-09-14 0.999 143.08 1.9558 N/A 24.527 7.4366 N/A 0.86498 402.9 N/A N/A N/A 4.7163 N/A 4.9297 10.675 N/A N/A 0.9612 139.7 10.1125 7.5195 N/A N/A 18.2397 1.4873 5.1827 1.3177 6.955 7.8405 14903.93 3.4339 79.422 1391.97 20.028 4.5225 1.6675 57.054 1.4039 36.608 17.4342
79 2022-09-13 1.0175 144.5 1.9558 N/A 24.551 7.4366 N/A 0.86793 396.83 N/A N/A N/A 4.705 N/A 4.921 10.6108 N/A N/A 0.9669 140.1 9.9988 7.5255 N/A N/A 18.564 1.4736 5.1764 1.32 7.0467 7.9855 15099.17 3.4125 80.5453 1397.3 20.1615 4.5869 1.6555 57.665 1.4186 36.859 17.3112
80 2022-09-12 1.0155 144.49 1.9558 N/A 24.546 7.4365 N/A 0.86778 395.73 N/A N/A N/A 4.6965 N/A 4.9135 10.6368 N/A N/A 0.9667 140.9 9.9718 7.5195 N/A N/A 18.5232 1.4749 5.1933 1.3194 7.0348 7.9709 15083.83 3.4346 80.692 1397.58 20.1025 4.5733 1.6499 57.701 1.4168 36.873 17.322
81 2022-09-09 1.0049 143.3 1.9558 N/A 24.536 7.4365 N/A 0.8686 396.3 N/A N/A N/A 4.721 N/A 4.9019 10.6643 N/A N/A 0.9657 140.9 9.9836 7.5245 N/A N/A 18.3282 1.4704 5.2087 1.307 6.9543 7.8871 14905.33 3.4416 79.9685 1384.64 19.991 4.52 1.6463 57.098 1.4063 36.508 17.3753
82 2022-09-08 1.0009 143.65 1.9558 N/A 24.543 7.4365 N/A 0.86656 395.48 N/A N/A N/A 4.7155 N/A 4.8756 10.7075 N/A N/A 0.9739 140.3 10.0615 7.515 N/A N/A 18.2546 1.4824 5.2042 1.3134 6.9564 7.8568 14891.86 3.429 79.7375 1381.7 20.013 4.5051 1.6491 57.031 1.4054 36.418 17.3797
83 2022-09-07 0.9885 143.2 1.9558 N/A 24.631 7.4365 N/A 0.8651 401.83 N/A N/A N/A 4.729 N/A 4.8585 10.6888 N/A N/A 0.975 141.3 9.9483 7.5143 N/A N/A 18.0262 1.4748 5.1881 1.3037 6.8968 7.7596 14779.47 3.4053 79.028 1374.44 19.9225 4.4497 1.6459 56.532 1.3931 36.322 17.2582
84 2022-09-06 0.9928 140.91 1.9558 N/A 24.55 7.4365 N/A 0.85743 402.65 N/A N/A N/A 4.7068 N/A 4.8424 10.6825 N/A N/A 0.9745 141.9 9.8945 7.5133 N/A N/A 18.0938 1.4651 5.13 1.3029 6.9091 7.7932 14783.94 3.39 79.2305 1366.65 19.8545 4.4676 1.6313 56.655 1.3947 36.242 17.0805
85 2022-09-05 0.992 139.47 1.9558 N/A 24.622 7.4364 N/A 0.86358 403.9 N/A N/A N/A 4.736 N/A 4.8198 10.729 N/A N/A 0.9747 142.7 9.9188 7.5173 N/A N/A 18.0792 1.4616 5.1407 1.3043 6.8768 7.7867 14782.83 3.3826 79.2332 1359.98 19.8192 4.4563 1.6289 56.477 1.3932 36.263 17.088
86 2022-09-02 0.9993 140.36 1.9558 N/A 24.481 7.437 N/A 0.86478 398.38 N/A N/A N/A 4.7063 N/A 4.8335 10.7498 N/A N/A 0.9839 141.5 10.0035 7.5225 N/A N/A 18.2072 1.4671 5.2153 1.3131 6.9031 7.8439 14895.92 3.396 79.8096 1360.84 20.1024 4.4809 1.6394 56.854 1.4013 36.624 17.2791
87 2022-09-01 1.0004 139.34 1.9558 N/A 24.488 7.4372 N/A 0.86473 399.58 N/A N/A N/A 4.7128 N/A 4.8447 10.7415 N/A N/A 0.9802 141.7 10.013 7.521 N/A N/A 18.2149 1.4651 5.2239 1.3169 6.9017 7.8511 14878 3.3644 79.6195 1353.69 20.1954 4.4828 1.6389 56.609 1.4002 36.71 17.1524
88 2022-08-31 1 138.72 1.9558 N/A 24.55 7.4371 N/A 0.86035 402.8 N/A N/A N/A 4.7283 N/A 4.8595 10.6788 N/A N/A 0.9796 141.7 9.9388 7.5148 N/A N/A 18.1849 1.4591 5.1482 1.3111 6.8947 7.8488 14849.93 3.3399 79.5465 1342.79 20.2044 4.4755 1.6322 56.153 1.3969 36.45 17.0667
89 2022-08-30 1.0034 138.71 1.9558 N/A 24.577 7.4376 N/A 0.85645 406.38 N/A N/A N/A 4.7323 N/A 4.8657 10.65 N/A N/A 0.9741 142.1 9.7553 7.5103 N/A N/A 18.239 1.4472 5.0286 1.3047 6.9233 7.8751 14875 3.3168 79.8025 1350.92 20.0077 4.4907 1.6245 56.393 1.3997 36.494 16.8567
90 2022-08-29 0.9986 138.49 1.9558 N/A 24.592 7.4379 N/A 0.8542 409.9 N/A N/A N/A 4.745 N/A 4.8699 10.628 N/A N/A 0.967 141.1 9.7675 7.5119 N/A N/A 18.1605 1.4529 5.0663 1.3026 6.9044 7.8368 14871.09 3.3146 79.8295 1347.47 19.9876 4.4837 1.6305 56.187 1.395 36.399 16.8891
91 2022-08-26 1.0007 137.02 1.9558 N/A 24.635 7.4379 N/A 0.8459 410.48 N/A N/A N/A 4.7485 N/A 4.8729 10.5703 N/A N/A 0.9642 140.3 9.667 7.5135 N/A N/A 18.1923 1.4333 5.1069 1.2944 6.8671 7.8521 14825.57 3.2537 79.9025 1333.46 19.924 4.4706 1.6112 56.109 1.3906 36.035 16.7995
92 2022-08-25 0.997 136.07 1.9558 N/A 24.648 7.4374 N/A 0.84293 408.93 N/A N/A N/A 4.7578 N/A 4.8758 10.5525 N/A N/A 0.9616 140.3 9.64 7.514 N/A N/A 18.112 1.4306 5.0879 1.2881 6.8317 7.8234 14753.15 3.2791 79.6555 1331.98 19.8132 4.4586 1.6006 55.842 1.3857 35.732 16.7903
93 2022-08-24 0.9934 135.74 1.9558 N/A 24.629 7.4381 N/A 0.84283 410.93 N/A N/A N/A 4.7668 N/A 4.88 10.586 N/A N/A 0.9576 139.5 9.636 7.5125 N/A N/A 18.0362 1.4389 5.0606 1.2908 6.822 7.795 14757.6 3.2599 79.3006 1332.84 19.7781 4.4559 1.6065 55.7 1.3857 35.906 16.8976
94 2022-08-23 0.9927 136.34 1.9558 N/A 24.658 7.4374 N/A 0.84343 410.55 N/A N/A N/A 4.7788 N/A 4.8839 10.6063 N/A N/A 0.9602 140.1 9.7438 7.5128 N/A N/A 17.983 1.4437 5.0984 1.2928 6.7952 7.79 14743.28 3.2598 79.2805 1332.1 19.9152 4.4557 1.6071 55.661 1.386 35.856 16.9568
95 2022-08-22 1.0001 137.08 1.9558 N/A 24.651 7.437 N/A 0.84658 408 N/A N/A N/A 4.764 N/A 4.8853 10.65 N/A N/A 0.958 140.9 9.7719 7.5113 N/A N/A 18.1268 1.4478 5.1752 1.2989 6.8457 7.8468 14895.47 3.2778 79.8615 1344.21 20.1583 4.4854 1.6125 56.218 1.3958 36.099 17.0766
96 2022-08-19 1.0054 137.67 1.9558 N/A 24.625 7.4373 N/A 0.84938 407.35 N/A N/A N/A 4.751 N/A 4.8811 10.6095 N/A N/A 0.9616 140.5 9.8418 7.5155 N/A N/A 18.2028 1.4584 5.2334 1.3062 6.8531 7.8877 14951.91 3.2879 80.2988 1343.39 20.3273 4.5007 1.6203 56.325 1.3979 35.988 17.1007
97 2022-08-18 1.0178 137.17 1.9558 N/A 24.611 7.4389 N/A 0.84391 405.13 N/A N/A N/A 4.724 N/A 4.8808 10.5903 N/A N/A 0.9683 140.5 9.8283 7.5215 N/A N/A 18.4095 1.4617 5.2326 1.3118 6.906 7.9844 15092.62 3.2993 81.042 1344.81 20.313 4.5536 1.6145 56.776 1.4053 36.254 17.0004
98 2022-08-17 1.0164 137.36 1.9558 N/A 24.566 7.4377 N/A 0.84208 404.28 N/A N/A N/A 4.7078 N/A 4.8825 10.5617 N/A N/A 0.9686 140.3 9.8428 7.5071 N/A N/A 18.2568 1.4655 5.2838 1.3117 6.8917 7.9705 15015.81 3.311 80.7555 1337.02 20.3825 4.5413 1.6165 56.772 1.4051 36.052 16.9125
99 2022-08-16 1.0131 136.11 1.9558 N/A 24.54 7.4368 N/A 0.84218 406.2 N/A N/A N/A 4.7043 N/A 4.882 10.5365 N/A N/A 0.9625 140.3 9.8428 7.51 N/A N/A 18.1994 1.4463 5.1835 1.3076 6.8767 7.9449 14968.68 3.3087 80.3745 1329.66 20.1595 4.5245 1.6012 56.602 1.398 35.93 16.6556
100 2022-08-15 1.0195 135.61 1.9558 N/A 24.46 7.4373 N/A 0.84375 398.6 N/A N/A N/A 4.6858 N/A 4.8849 10.498 N/A N/A 0.9631 140.3 9.871 7.5028 N/A N/A 18.3143 1.4508 5.2268 1.3167 6.905 7.9899 15042.36 3.3294 81.061 1336.35 20.3914 4.5465 1.6002 57.122 1.4036 36.218 16.7375
101 2022-08-12 1.0285 137.47 1.9558 N/A 24.38 7.4395 N/A 0.84715 392.3 N/A N/A N/A 4.6773 N/A 4.8915 10.4515 N/A N/A 0.9689 140.3 9.813 7.5138 N/A N/A 18.4733 1.4496 5.3007 1.3148 6.9352 8.06 15104.2 3.345 81.9935 1342.59 20.4925 4.5709 1.5985 57.246 1.4106 36.393 16.7318
102 2022-08-11 1.0338 136.57 1.9558 N/A 24.346 7.4395 N/A 0.84575 394.18 N/A N/A N/A 4.6828 N/A 4.9055 10.36 N/A N/A 0.9712 139.7 9.804 7.515 N/A N/A 18.5674 1.4532 5.2447 1.3202 6.9668 8.1118 15215.93 3.3505 82.2845 1344.62 20.6398 4.5952 1.6045 57.225 1.4151 36.343 16.7083
103 2022-08-10 1.0252 138.16 1.9558 N/A 24.397 7.4397 N/A 0.84608 397.65 N/A N/A N/A 4.7063 N/A 4.9138 10.3773 N/A N/A 0.9713 139.7 9.9118 7.5158 N/A N/A 18.4099 1.4682 5.251 1.3207 6.9222 8.046 15218.87 3.3773 81.468 1344.16 20.713 4.5693 1.6211 57.061 1.4107 36.42 16.8788
104 2022-08-09 1.0234 138.26 1.9558 N/A 24.532 7.4407 N/A 0.8452 397.35 N/A N/A N/A 4.7085 N/A 4.9038 10.3875 N/A N/A 0.9763 140.1 9.9365 7.514 N/A N/A 18.3342 1.4687 5.2478 1.3163 6.9106 8.0334 15197.09 3.3865 81.406 1336.74 20.7145 4.5592 1.6304 56.939 1.411 36.264 17.05
105 2022-08-08 1.0199 137.62 1.9558 N/A 24.515 7.4405 N/A 0.84165 394.27 N/A N/A N/A 4.7043 N/A 4.9163 10.365 N/A N/A 0.9763 140.1 9.9405 7.5123 N/A N/A 18.3175 1.4607 5.238 1.3134 6.8931 8.0061 15147.65 3.3895 81.166 1329.93 20.681 4.5477 1.6202 56.554 1.4058 36.38 16.9694
106 2022-08-05 1.0233 136.22 1.9558 N/A 24.581 7.4415 N/A 0.84268 393.78 N/A N/A N/A 4.7085 N/A 4.9251 10.3573 N/A N/A 0.9776 138.9 9.982 7.5148 N/A N/A 18.3853 1.4713 5.3348 1.3185 6.9068 8.0328 15236.2 3.4033 81.0469 1324.53 20.8367 4.5598 1.6248 56.524 1.4077 36.373 17.0342
107 2022-08-04 1.0181 135.81 1.9558 N/A 24.659 7.4425 N/A 0.84231 395.98 N/A N/A N/A 4.7233 N/A 4.9261 10.374 N/A N/A 0.9765 138.7 9.9065 7.515 N/A N/A 18.2922 1.4607 5.3614 1.307 6.8769 7.9919 15200.94 3.4101 80.7715 1333.7 20.756 4.5387 1.6172 56.633 1.4037 36.606 17.0352
108 2022-08-03 1.0194 136.18 1.9558 N/A 24.65 7.4427 N/A 0.83629 395.03 N/A N/A N/A 4.691 N/A 4.9245 10.3913 N/A N/A 0.9773 139.3 9.8743 7.5178 N/A N/A 18.3112 1.4681 5.3547 1.3085 6.883 8.0022 15184.35 3.4362 80.6895 1336.03 21.0788 4.5435 1.6266 56.855 1.4069 36.963 17.1283
109 2022-08-02 1.0224 133.9 1.9558 N/A 24.644 7.4432 N/A 0.83665 396.82 N/A N/A N/A 4.7063 N/A 4.9298 10.3995 N/A N/A 0.9744 139.3 9.9305 7.5195 N/A N/A 18.3564 1.4745 5.3175 1.315 6.9117 8.0257 15204.85 3.4486 80.3243 1339.16 20.952 4.5531 1.6254 56.834 1.4103 36.914 16.982
110 2022-08-01 1.0233 135.38 1.9558 N/A 24.628 7.4457 N/A 0.837 401.35 N/A N/A N/A 4.734 N/A 4.9283 10.3668 N/A N/A 0.9717 138.7 9.8638 7.521 N/A N/A 18.3475 1.4535 5.2723 1.3076 6.9105 8.0329 15203.21 3.4546 80.9335 1333.3 20.7635 4.5568 1.616 56.734 1.4087 36.977 16.8613
111 2022-07-29 1.0198 136.42 1.9558 N/A 24.61 7.4438 N/A 0.8399 404.8 N/A N/A N/A 4.7375 N/A 4.9343 10.3875 N/A N/A 0.9744 138.3 9.8773 7.518 N/A N/A 18.2472 1.4646 5.2739 1.31 6.8705 8.0054 15155.56 3.4714 80.882 1329.4 20.6745 4.5386 1.6283 56.375 1.4088 36.978 16.8627
112 2022-07-28 1.0122 137.26 1.9558 N/A 24.609 7.4442 N/A 0.83586 407.3 N/A N/A N/A 4.7908 N/A 4.9342 10.449 N/A N/A 0.9745 138.7 9.8983 7.52 N/A N/A 18.1417 1.4535 5.33 1.2986 6.8325 7.9456 15107.59 3.4701 80.6535 1320.45 20.676 4.5071 1.6172 56.592 1.4009 37.097 17.0011
113 2022-07-27 1.0152 138.89 1.9558 N/A 24.575 7.4446 N/A 0.84138 404.67 N/A N/A N/A 4.7978 N/A 4.9334 10.4545 N/A N/A 0.9768 139.1 9.9558 7.514 N/A N/A 18.1859 1.462 5.4039 1.3049 6.8534 7.9692 15213.07 3.4855 81.135 1333.99 20.753 4.5263 1.6306 56.455 1.4088 37.4 17.1347
114 2022-07-26 1.0124 138.35 1.9558 N/A 24.607 7.4449 N/A 0.84558 400.99 N/A N/A N/A 4.742 N/A 4.9324 10.4445 N/A N/A 0.9765 139.1 10.0105 7.5145 N/A N/A 18.0705 1.4605 5.4437 1.3035 6.8451 7.9466 15185.27 3.4891 80.805 1326.65 20.7845 4.5113 1.6235 56.16 1.4066 37.18 17.087
115 2022-07-25 1.0236 139.84 1.9558 N/A 24.535 7.4449 N/A 0.84813 396.5 N/A N/A N/A 4.708 N/A 4.9339 10.3973 N/A N/A 0.9869 139.5 10.0704 7.5195 N/A N/A 18.2653 1.4707 5.5976 1.3168 6.9094 8.0345 15303.87 3.5201 81.6675 1341.25 20.9376 4.5586 1.6325 57.209 1.4176 37.525 17.1502
116 2022-07-22 1.019 139.51 1.9558 N/A 24.514 7.4443 N/A 0.85141 398.3 N/A N/A N/A 4.7508 N/A 4.9321 10.4328 N/A N/A 0.9832 139.5 10.1498 7.5234 N/A N/A 18.094 1.4677 5.5821 1.3105 6.8852 7.9985 15275.69 3.5083 81.384 1335.66 20.9595 4.5366 1.6265 57.24 1.4151 37.392 17.2009
117 2022-07-21 1.0199 141.46 1.9558 N/A 24.496 7.4446 N/A 0.85545 400.13 N/A N/A N/A 4.761 N/A 4.9391 10.426 N/A N/A 0.9924 139.7 10.175 7.52 N/A N/A 18.0327 1.4848 5.5777 1.3178 6.904 8.0056 15342.25 3.5203 81.451 1337.47 20.941 4.5457 1.6479 57.512 1.4218 37.66 17.5195
118 2022-07-20 1.0199 140.92 1.9558 N/A 24.493 7.4452 N/A 0.85178 399.5 N/A N/A N/A 4.782 N/A 4.9396 10.4606 N/A N/A 0.9896 139.5 10.1323 7.5143 N/A N/A 17.9444 1.4767 5.5427 1.3132 6.8892 8.0062 15275.82 3.5147 81.599 1337.61 20.8967 4.5406 1.6308 57.398 1.4204 37.405 17.3924
119 2022-07-19 1.0245 141.01 1.9558 N/A 24.555 7.4449 N/A 0.85303 397.45 N/A N/A N/A 4.7598 N/A 4.9395 10.4964 N/A N/A 0.9918 138.9 10.176 7.5093 N/A N/A 18.018 1.4869 5.5454 1.3264 6.9064 8.0423 15344.49 3.5295 81.898 1340.33 20.8552 4.559 1.6456 57.583 1.4269 37.492 17.457
120 2022-07-18 1.0131 140.16 1.9558 N/A 24.508 7.4435 N/A 0.84708 402.05 N/A N/A N/A 4.776 N/A 4.9389 10.5265 N/A N/A 0.9911 138.9 10.2553 7.513 N/A N/A 17.7225 1.4839 5.4505 1.3151 6.8266 7.9528 15157.63 3.5004 81.034 1333.33 20.7095 4.5113 1.6432 57.056 1.4153 37.13 17.383
121 2022-07-15 1.0059 139.49 1.9558 N/A 24.561 7.443 N/A 0.84988 403.73 N/A N/A N/A 4.7953 N/A 4.9407 10.5943 N/A N/A 0.9849 138.9 10.2763 7.516 N/A N/A 17.5451 1.4886 5.4434 1.3147 6.7943 7.8963 15081.58 3.5044 80.316 1333.79 20.9209 4.4752 1.6377 56.678 1.4113 36.866 17.2875
122 2022-07-14 1.0005 139.04 1.9558 N/A 24.417 7.4425 N/A 0.8456 408.78 N/A N/A N/A 4.8146 N/A 4.942 10.6019 N/A N/A 0.9841 138.89 10.2536 7.5122 N/A N/A 17.494 1.4893 5.4586 1.3162 6.7618 7.8539 15119.56 3.4915 80.0752 1322.29 20.9585 4.4462 1.6437 56.565 1.4065 36.632 17.202
123 2022-07-13 1.0067 138.02 1.9558 N/A 24.397 7.4416 N/A 0.84371 409.35 N/A N/A N/A 4.824 N/A 4.9414 10.602 N/A N/A 0.9829 138.3 10.2428 7.5155 N/A N/A 17.5629 1.4802 5.4533 1.3073 6.7722 7.9025 15117.08 3.4864 80.1285 1311.4 20.9029 4.4667 1.635 56.669 1.4134 36.377 17.0527
124 2022-07-12 1.0042 137.31 1.9558 N/A 24.582 7.4408 N/A 0.84823 409.98 N/A N/A N/A 4.819 N/A 4.9413 10.629 N/A N/A 0.9883 139.1 10.2754 7.517 N/A N/A 17.4392 1.49 5.4009 1.3094 6.7518 7.8828 15054.05 3.4987 79.8965 1315.1 20.8883 4.4556 1.6395 56.648 1.4127 36.392 17.1509
125 2022-07-11 1.0098 138.77 1.9558 N/A 24.592 7.4414 N/A 0.8454 408.22 N/A N/A N/A 4.7968 N/A 4.943 10.6943 N/A N/A 0.9908 139.3 10.299 7.518 N/A N/A 17.5447 1.491 5.3673 1.314 6.7793 7.9265 15131.92 3.5108 80.2435 1320.36 20.7845 4.4704 1.6466 56.574 1.4178 36.585 17.1634
126 2022-07-08 1.0163 138.05 1.9558 N/A 24.614 7.4424 N/A 0.84585 402.45 N/A N/A N/A 4.763 N/A 4.9431 10.6665 N/A N/A 0.9913 139.5 10.263 7.519 N/A N/A 17.6026 1.4871 5.4345 1.3201 6.8095 7.9769 15210.73 3.5325 80.528 1321.61 20.8477 4.4992 1.6464 56.882 1.4228 36.602 17.1922
127 2022-07-07 1.018 138.11 1.9558 N/A 24.779 7.4405 N/A 0.85105 410.04 N/A N/A N/A 4.7721 N/A 4.9448 10.723 N/A N/A 0.9906 139.3 10.291 7.5193 N/A N/A 17.5551 1.4883 5.4983 1.3227 6.823 7.9893 15265.27 3.5548 80.6 1324.66 20.9675 4.5077 1.6461 56.939 1.4255 36.74 17.0372
128 2022-07-06 1.0177 137.71 1.9558 N/A 24.778 7.4403 N/A 0.85676 411.8 N/A N/A N/A 4.771 N/A 4.944 10.745 N/A N/A 0.9896 138.5 10.2803 7.5198 N/A N/A 17.5505 1.4961 5.5116 1.3274 6.8289 7.9864 15287.49 3.5884 80.5321 1331.69 21.0194 4.5028 1.6505 56.779 1.4305 36.78 17.0246
129 2022-07-05 1.029 139.77 1.9558 N/A 24.751 7.4396 N/A 0.85845 407.38 N/A N/A N/A 4.7448 N/A 4.9438 10.8031 N/A N/A 0.9932 139.1 10.285 7.5246 N/A N/A 17.5049 1.518 5.5141 1.3364 6.9029 8.0748 15487.93 3.6343 81.673 1348.97 21.0171 4.5477 1.6772 57.009 1.4455 36.879 16.9143
130 2022-07-04 1.0455 141.51 1.9558 N/A 24.745 7.4391 N/A 0.8596 401.52 N/A N/A N/A 4.71 N/A 4.944 10.7658 N/A N/A 1.0037 139.3 10.2958 7.5301 N/A N/A 17.5994 1.5205 5.5663 1.3435 6.9977 8.2033 15684.13 3.6655 82.5067 1353.4 21.1972 4.6138 1.6748 57.487 1.4587 37.298 17.0275
131 2022-07-01 1.0425 141.05 1.9558 N/A 24.753 7.4391 N/A 0.86648 401.11 N/A N/A N/A 4.7168 N/A 4.9457 10.7783 N/A N/A 1.0027 138.7 10.3651 7.531 N/A N/A 17.4608 1.5382 5.5117 1.3492 6.987 8.1801 15621.64 3.6717 82.3747 1352.58 21.115 4.5943 1.6929 57.452 1.4565 37.186 17.1323
132 2022-06-30 1.0387 141.54 1.9558 N/A 24.739 7.4392 N/A 0.8582 397.04 N/A N/A N/A 4.6904 N/A 4.9464 10.73 N/A N/A 0.996 138.9 10.3485 7.5307 N/A N/A 17.322 1.5099 5.4229 1.3425 6.9624 8.1493 15552 3.6392 82.113 1351.6 20.9641 4.5781 1.6705 57.15 1.4483 36.754 17.0143
133 2022-06-29 1.0517 143.53 1.9558 N/A 24.739 7.4392 N/A 0.86461 394.28 N/A N/A N/A 4.6869 N/A 4.9419 10.6848 N/A N/A 1.0005 139.9 10.3065 7.5285 N/A N/A 17.4998 1.5256 5.5163 1.3513 7.0382 8.2532 15612.61 3.6344 83.037 1364.02 21.1375 4.6272 1.6871 57.773 1.4607 36.925 16.9295
134 2022-06-28 1.0561 143.67 1.9558 N/A 24.726 7.4394 N/A 0.8635 398.55 N/A N/A N/A 4.6905 N/A 4.9443 10.6543 N/A N/A 1.0101 139.5 10.337 7.532 N/A N/A 17.5891 1.521 5.5308 1.3565 7.0775 8.288 15669.91 3.6267 83.408 1361.75 21.088 4.6432 1.6822 57.85 1.4645 37.154 16.9072
135 2022-06-27 1.0572 143.25 1.9558 N/A 24.724 7.4408 N/A 0.862 402.62 N/A N/A N/A 4.699 N/A 4.944 10.6713 N/A N/A 1.0143 139.7 10.408 7.5333 N/A N/A 17.4794 1.5278 5.5446 1.3639 7.0737 8.2946 15635.36 3.6009 82.9325 1357.68 21.041 4.6559 1.6801 57.9 1.4641 37.361 16.7967
136 2022-06-24 1.0524 142.19 1.9558 N/A 24.731 7.4398 N/A 0.85773 401.34 N/A N/A N/A 4.7023 N/A 4.9463 10.694 N/A N/A 1.0072 139.7 10.4345 7.5295 N/A N/A 18.2856 1.5248 5.4851 1.3657 7.0478 8.2609 15633.96 3.621 82.3985 1364.09 20.9901 4.6327 1.6731 57.83 1.462 37.36 16.7137
137 2022-06-23 1.0493 142.11 1.9558 N/A 24.75 7.4388 N/A 0.85818 399.6 N/A N/A N/A 4.7085 N/A 4.9468 10.705 N/A N/A 1.013 139.9 10.475 7.5286 N/A N/A 18.2199 1.5212 5.4515 1.36 7.0367 8.236 15594.75 3.6192 82.1489 1367.21 21.0924 4.623 1.6713 57.44 1.4589 37.261 16.817
138 2022-06-22 1.0521 143.11 1.9558 N/A 24.712 7.4387 N/A 0.85885 396 N/A N/A N/A 4.6905 N/A 4.9467 10.6688 N/A N/A 1.0153 138.7 10.5045 7.5228 N/A N/A 18.255 1.5254 5.4349 1.366 7.0604 8.2589 15618.98 3.6432 82.4075 1369.29 21.1491 4.6345 1.6835 57.174 1.4615 37.281 16.7985
139 2022-06-21 1.055 143.75 1.9558 N/A 24.69 7.4393 N/A 0.8601 396.48 N/A N/A N/A 4.6435 N/A 4.9462 10.646 N/A N/A 1.0214 138.7 10.3283 7.5205 N/A N/A 18.3049 1.5177 5.442 1.366 7.068 8.2817 15639.62 3.6505 82.423 1365.09 21.2485 4.6399 1.6675 57.304 1.4612 37.294 16.7881
140 2022-06-20 1.0517 141.94 1.9558 N/A 24.728 7.4387 N/A 0.85748 397.85 N/A N/A N/A 4.652 N/A 4.9453 10.6375 N/A N/A 1.0162 137.3 10.4085 7.5175 N/A N/A 18.2239 1.5061 5.4117 1.3662 7.0346 8.2558 15589.89 3.639 81.994 1357.54 21.3016 4.6291 1.6549 56.872 1.4589 37.157 16.8603
141 2022-06-17 1.0486 141.21 1.9558 N/A 24.742 7.4384 N/A 0.855 400.53 N/A N/A N/A 4.7003 N/A 4.9469 10.6748 N/A N/A 1.0105 137.7 10.4525 7.5155 N/A N/A 18.1495 1.5039 5.3824 1.3631 7.0308 8.2314 15537.05 3.6112 81.871 1356.27 21.4474 4.6159 1.6601 56.371 1.4547 36.974 16.7133
142 2022-06-16 1.04 138.24 1.9558 N/A 24.742 7.4386 N/A 0.8555 398.1 N/A N/A N/A 4.7138 N/A 4.9443 10.6942 N/A N/A 1.0142 137.5 10.4588 7.5245 N/A N/A 18.0126 1.4939 5.2559 1.3446 6.9844 8.1638 15427.31 3.5934 81.1945 1346.88 21.4115 4.5786 1.6608 55.7 1.4451 36.566 16.6052
143 2022-06-15 1.0431 140.49 1.9558 N/A 24.703 7.4392 N/A 0.86328 397.96 N/A N/A N/A 4.669 N/A 4.9427 10.6278 N/A N/A 1.0435 137.5 10.3868 7.5245 N/A N/A 18.0465 1.5051 5.3164 1.3498 7.0013 8.1883 15361.97 3.6007 81.5142 1346.86 21.4763 4.6037 1.6706 55.627 1.4519 36.529 16.7111
144 2022-06-14 1.0452 140.62 1.9558 N/A 24.749 7.4403 N/A 0.86578 398.68 N/A N/A N/A 4.6563 N/A 4.9443 10.622 N/A N/A 1.0394 138.3 10.3945 7.5238 N/A N/A 18.06 1.5174 5.3329 1.3522 7.0417 8.2048 15400.02 3.6208 81.559 1346.72 21.4832 4.6224 1.6755 55.669 1.4541 36.566 16.7959
145 2022-06-13 1.0455 140.51 1.9558 N/A 24.724 7.4397 N/A 0.8585 399.3 N/A N/A N/A 4.6373 N/A 4.9459 10.616 N/A N/A 1.0375 138.7 10.3222 7.5215 N/A N/A 18.0495 1.4998 5.2785 1.3435 7.0434 8.2071 15376.17 3.5994 81.606 1349.93 21.2102 4.6195 1.6635 55.72 1.4538 36.425 16.807
146 2022-06-10 1.0578 141.69 1.9558 N/A 24.705 7.4389 N/A 0.85048 398.48 N/A N/A N/A 4.6053 N/A 4.9442 10.5255 N/A N/A 1.0404 137.7 10.1495 7.5225 N/A N/A 18.0116 1.4845 5.1718 1.3484 7.0868 8.3031 15393.27 3.5626 82.3355 1344.25 20.8285 4.6564 1.6482 56.101 1.462 36.774 16.5209
147 2022-06-09 1.0743 143.93 1.9558 N/A 24.689 7.4391 N/A 0.85653 396.45 N/A N/A N/A 4.5925 N/A 4.9453 10.5045 N/A N/A 1.0495 138.7 10.1818 7.5223 N/A N/A 18.5104 1.4985 5.2506 1.3506 7.1722 8.4317 15646.25 3.5859 83.526 1348.99 21.0248 4.7199 1.6673 56.872 1.4779 37.079 16.4132
148 2022-06-08 1.0739 143.92 1.9558 N/A 24.622 7.4386 N/A 0.85575 391.25 N/A N/A N/A 4.5698 N/A 4.945 10.4938 N/A N/A 1.0486 138.9 10.1395 7.5215 N/A N/A 18.453 1.4917 5.2447 1.3467 7.1785 8.4275 15577.86 3.5848 83.414 1349.34 21.0458 4.7187 1.6644 56.799 1.4769 37.076 16.4626
149 2022-06-07 1.0662 141.66 1.9558 N/A 24.739 7.4395 N/A 0.85365 389.33 N/A N/A N/A 4.5813 N/A 4.9426 10.5039 N/A N/A 1.0423 138.9 10.1843 7.5244 N/A N/A 17.8702 1.4884 5.1256 1.3437 7.1146 8.3656 15412.37 3.5661 82.873 1340.75 20.8435 4.6865 1.6582 56.421 1.4685 36.768 16.4059
150 2022-06-06 1.0726 140.16 1.9558 N/A 24.715 7.439 N/A 0.85415 388.05 N/A N/A N/A 4.5808 N/A 4.9424 10.452 N/A N/A 1.032 138.3 10.0853 7.5222 N/A N/A 17.796 1.4842 5.0986 1.3463 7.1223 8.4154 15464.73 3.5697 83.245 1341.13 20.9078 4.7076 1.6428 56.67 1.4732 36.774 16.4142
151 2022-06-03 1.073 139.59 1.9558 N/A 24.708 7.4388 N/A 0.8542 394.78 N/A N/A N/A 4.5955 N/A 4.9428 10.4589 N/A N/A 1.0296 137.9 10.103 7.522 N/A N/A 17.738 1.4805 5.1643 1.3484 7.1465 8.4167 15498.1 3.5751 83.273 1337.4 20.985 4.7094 1.6409 56.738 1.4741 36.777 16.6153
152 2022-06-02 1.0692 138.72 1.9558 N/A 24.702 7.4391 N/A 0.85195 394.9 N/A N/A N/A 4.5787 N/A 4.9398 10.4705 N/A N/A 1.0264 136.9 10.0845 7.5325 N/A N/A 17.6175 1.4829 5.1335 1.352 7.135 8.3896 15481.86 3.5705 82.922 1334.06 20.9831 4.6949 1.6413 56.467 1.4701 36.754 16.6143
153 2022-06-01 1.0712 138.68 1.9558 N/A 24.748 7.4393 N/A 0.85158 395.03 N/A N/A N/A 4.5913 N/A 4.9428 10.4758 N/A N/A 1.0305 137.1 10.0438 7.5345 N/A N/A 17.6223 1.4861 5.0646 1.3536 7.1586 8.4057 15574.33 3.5682 83.051 1331.44 21.0678 4.6951 1.6442 56.182 1.47 36.801 16.609
154 2022-05-31 1.0713 137.36 1.9558 N/A 24.714 7.4394 N/A 0.85138 396.2 N/A N/A N/A 4.5805 N/A 4.9408 10.5053 N/A N/A 1.0281 136.3 10.0983 7.541 N/A N/A 17.5817 1.4933 5.0965 1.3573 7.1402 8.4063 15580.15 3.5746 83.231 1329.32 20.987 4.6907 1.6459 56.323 1.4687 36.751 16.745
155 2022-05-30 1.0764 137.25 1.9558 N/A 24.712 7.4391 N/A 0.8515 392.18 N/A N/A N/A 4.5855 N/A 4.9441 10.518 N/A N/A 1.0327 136.9 10.1256 7.5305 N/A N/A 17.6416 1.4982 5.0629 1.3647 7.1735 8.449 15682.41 3.5722 83.475 1331.66 20.8994 4.6998 1.6439 56.322 1.4719 36.7 16.648
156 2022-05-27 1.0722 136.05 1.9558 N/A 24.7 7.4392 N/A 0.84875 392.83 N/A N/A N/A 4.5858 N/A 4.9427 10.5293 N/A N/A 1.0258 137.9 10.179 7.5379 N/A N/A 17.582 1.4995 5.0959 1.3661 7.1831 8.4165 15583.97 3.597 83.1915 1343.63 21.136 4.6952 1.6426 56.02 1.4679 36.589 16.746
157 2022-05-26 1.0697 135.95 1.9558 N/A 24.676 7.4409 N/A 0.85073 391.72 N/A N/A N/A 4.6083 N/A 4.9423 10.5983 N/A N/A 1.0283 138.1 10.2715 7.5355 N/A N/A 17.5588 1.511 5.1741 1.3715 7.2024 8.397 15628.91 3.5935 83.0065 1352.69 21.1935 4.7045 1.6541 55.975 1.4709 36.589 16.9312
158 2022-05-25 1.0656 135.34 1.9558 N/A 24.648 7.4405 N/A 0.85295 388.25 N/A N/A N/A 4.621 N/A 4.9416 10.5419 N/A N/A 1.0269 138.3 10.2704 7.5355 N/A N/A 17.3954 1.5126 5.1736 1.372 7.1334 8.3647 15587.59 3.585 82.6666 1354.61 21.2213 4.6833 1.6539 55.787 1.4676 36.55 16.7628
159 2022-05-24 1.072 136.49 1.9558 N/A 24.663 7.4411 N/A 0.8575 383.33 N/A N/A N/A 4.6015 N/A 4.9446 10.5013 N/A N/A 1.0334 139.3 10.289 7.5285 N/A N/A 17.2572 1.5152 5.1793 1.3714 7.1449 8.4143 15711.88 3.5848 83.185 1353.65 21.2456 4.7076 1.6656 56.152 1.4722 36.609 16.7814
160 2022-05-23 1.0659 136.05 1.9558 N/A 24.594 7.4413 N/A 0.84783 381.65 N/A N/A N/A 4.621 N/A 4.947 10.4918 N/A N/A 1.031 139.1 10.252 7.5275 N/A N/A 16.8672 1.4982 5.1623 1.3626 7.085 8.3664 15609 3.5745 82.6795 1344.19 21.1273 4.6782 1.6463 55.686 1.4639 36.41 16.7437
161 2022-05-20 1.0577 135.34 1.9558 N/A 24.67 7.4424 N/A 0.8482 382.93 N/A N/A N/A 4.6365 N/A 4.9477 10.4915 N/A N/A 1.028 138.5 10.262 7.5335 N/A N/A 16.8201 1.498 5.1989 1.3526 7.0638 8.2999 15501.99 3.533 82.1617 1340.58 21.0314 4.6422 1.6518 55.181 1.4588 36.284 16.7131
162 2022-05-19 1.0525 134.46 1.9558 N/A 24.7 7.4423 N/A 0.84728 385.83 N/A N/A N/A 4.6423 N/A 4.9474 10.5098 N/A N/A 1.0265 139.5 10.3102 7.5395 N/A N/A 16.8037 1.5036 5.2094 1.349 7.1028 8.2594 15416.76 3.5623 81.7115 1343.21 21.0043 4.6363 1.6551 55.14 1.4576 36.343 16.8315
163 2022-05-18 1.0523 135.76 1.9558 N/A 24.647 7.4419 N/A 0.8467 382.88 N/A N/A N/A 4.6443 N/A 4.9473 10.4675 N/A N/A 1.0486 138.9 10.2125 7.535 N/A N/A 16.7811 1.498 5.1974 1.3488 7.0972 8.2591 15446 3.526 81.6455 1332.76 20.9204 4.6254 1.6548 55.077 1.4598 36.399 16.7313
164 2022-05-17 1.0541 136.32 1.9558 N/A 24.712 7.4414 N/A 0.844 386.3 N/A N/A N/A 4.6488 N/A 4.9478 10.4393 N/A N/A 1.0457 138.7 10.178 7.5245 N/A N/A 16.6027 1.4993 5.2621 1.3517 7.0899 8.2744 15433.23 3.5387 81.6515 1333.66 21.0273 4.6211 1.6561 55.137 1.4589 36.361 16.844
165 2022-05-16 1.0422 135.01 1.9558 N/A 24.71 7.4418 N/A 0.85045 385.85 N/A N/A N/A 4.6675 N/A 4.9469 10.4978 N/A N/A 1.0479 138.3 10.2188 7.5225 N/A N/A 16.3121 1.5057 5.2819 1.3473 7.0786 8.1812 15294.29 3.5474 81.081 1337.9 20.9324 4.5836 1.6601 54.705 1.4531 36.274 16.9195
166 2022-05-13 1.0385 133.91 1.9558 N/A 24.74 7.4412 N/A 0.85115 385 N/A N/A N/A 4.6883 N/A 4.9455 10.4905 N/A N/A 1.0385 140.1 10.2043 7.52 N/A N/A 16.0687 1.5067 5.3204 1.3505 7.0513 8.1522 15193.55 3.5586 80.4315 1330.83 20.988 4.5673 1.6633 54.449 1.45 36.109 16.7789
167 2022-05-12 1.0408 133.85 1.9558 N/A 24.925 7.4413 N/A 0.85293 382.2 N/A N/A N/A 4.668 N/A 4.947 10.5648 N/A N/A 1.0377 139.7 10.2898 7.5235 N/A N/A 16.0132 1.5163 5.4161 1.3569 7.0691 8.1702 15255.73 3.5981 80.667 1341.98 21.2531 4.5725 1.6692 54.589 1.4529 36.15 16.8806
168 2022-05-11 1.0553 137.07 1.9558 N/A 25.365 7.4393 N/A 0.85393 379.13 N/A N/A N/A 4.6575 N/A 4.947 10.526 N/A N/A 1.0446 139.3 10.1793 7.5365 N/A N/A 16.1851 1.5055 5.3859 1.3685 7.0893 8.2839 15308.87 3.6148 81.4935 1343.99 21.387 4.6185 1.6645 54.992 1.4622 36.492 16.9275
169 2022-05-10 1.0554 137.38 1.9558 N/A 25.014 7.4386 N/A 0.85595 380.15 N/A N/A N/A 4.6763 N/A 4.9458 10.6075 N/A N/A 1.0479 139.5 10.2315 7.5385 N/A N/A 16.0883 1.5162 5.4232 1.3707 7.0967 8.2847 15349.06 3.6587 81.5425 1346.56 21.4716 4.6248 1.6707 55.289 1.4667 36.448 17.005
170 2022-05-09 1.0559 138.1 1.9558 N/A 25.055 7.4385 N/A 0.85235 383.23 N/A N/A N/A 4.6985 N/A 4.9467 10.5818 N/A N/A 1.0462 139.5 10.0583 7.5335 N/A N/A 15.8941 1.5048 5.4321 1.3656 7.0886 8.2887 15367.67 3.6239 81.7415 1345.48 21.4341 4.6285 1.6584 55.67 1.4676 36.497 17.1332
171 2022-05-06 1.057 137.9 1.9558 N/A 24.665 7.44 N/A 0.85625 381.47 N/A N/A N/A 4.7028 N/A 4.949 10.4686 N/A N/A 1.0419 138.3 9.9808 7.5336 N/A N/A 15.8078 1.4888 5.3183 1.356 7.0506 8.2969 15312.44 3.5965 81.298 1343.9 21.3555 4.6191 1.644 55.467 1.4642 36.303 16.9614
172 2022-05-05 1.0568 137.18 1.9558 N/A 24.606 7.4405 N/A 0.8519 378.65 N/A N/A N/A 4.6673 N/A 4.9485 10.3748 N/A N/A 1.0355 138 9.8463 7.5398 N/A N/A 15.7051 1.4669 5.2192 1.3483 6.9944 8.2948 15250.92 3.5916 80.6185 1330.89 21.2069 4.5955 1.6273 55.364 1.4561 36.026 16.5862
173 2022-05-04 1.0531 136.84 1.9558 N/A 24.644 7.4409 N/A 0.84194 377.55 N/A N/A N/A 4.6875 N/A 4.947 10.3968 N/A N/A 1.0324 137.2 9.9042 7.5499 N/A N/A 15.5769 1.478 5.24 1.3498 6.9594 8.2655 15201.44 3.5487 80.4035 1331.45 21.2947 4.5847 1.6333 55.26 1.4559 36.137 16.6489
174 2022-05-03 1.0556 137.06 1.9558 N/A 24.662 7.4403 N/A 0.8413 382.15 N/A N/A N/A 4.6925 N/A 4.9475 10.3978 N/A N/A 1.0272 137.6 9.909 7.5555 N/A N/A 15.6941 1.4825 5.3143 1.357 6.9759 8.2838 15288.47 3.5597 80.842 1335.64 21.5025 4.5956 1.6366 55.455 1.4605 36.387 16.8303
175 2022-05-02 1.0524 136.63 1.9558 N/A 24.671 7.4391 N/A 0.8381 378.51 N/A N/A N/A 4.685 N/A 4.9478 10.4035 N/A N/A 1.0253 137.2 9.9248 7.561 N/A N/A 15.6697 1.4913 5.248 1.356 6.9548 8.2581 15293.41 3.5277 80.497 1333.71 21.4758 4.5816 1.6362 55.229 1.4585 36.208 16.7383
176 2022-04-29 1.054 137.01 1.9558 N/A 24.605 7.4415 N/A 0.83908 378.71 N/A N/A N/A 4.678 N/A 4.9479 10.2958 N/A N/A 1.0229 137.8 9.7525 7.5667 N/A N/A 15.6385 1.4699 5.1608 1.3426 6.9441 8.2703 15301.52 3.4993 80.638 1326.71 21.4181 4.5886 1.6119 55.2 1.4545 36.026 16.6473
177 2022-04-28 1.0485 137.13 1.9558 N/A 24.526 7.4421 N/A 0.8435 377.06 N/A N/A N/A 4.6891 N/A 4.9479 10.3594 N/A N/A 1.0216 137.8 9.899 7.5703 N/A N/A 15.5362 1.4814 5.2465 1.3498 6.9381 8.2267 15222.05 3.5096 80.367 1337.82 21.4531 4.5741 1.6221 54.845 1.4556 36.152 16.7472
178 2022-04-27 1.0583 135.57 1.9558 N/A 24.55 7.441 N/A 0.84215 379.74 N/A N/A N/A 4.7043 N/A 4.948 10.4035 N/A N/A 1.0229 138.2 9.7838 7.565 N/A N/A 15.6857 1.4828 5.3045 1.3572 6.9377 8.3045 15259.86 3.5178 81.0705 1341.98 21.6259 4.6142 1.6118 55.195 1.4602 36.331 16.8406
179 2022-04-26 1.0674 136.15 1.9558 N/A 24.423 7.4393 N/A 0.84135 374.46 N/A N/A N/A 4.6466 N/A 4.9458 10.3935 N/A N/A 1.0229 138.4 9.7943 7.5625 N/A N/A 15.7944 1.4828 5.249 1.3613 6.9837 8.3735 15365.76 3.5147 81.7265 1340.02 21.6538 4.6485 1.6102 55.681 1.4666 36.596 16.7787
180 2022-04-25 1.0746 137.73 1.9558 N/A 24.418 7.4391 N/A 0.8433 374.08 N/A N/A N/A 4.6398 N/A 4.9455 10.3476 N/A N/A 1.0267 139.2 9.7018 7.562 N/A N/A 15.864 1.4972 5.1953 1.3709 7.0398 8.4325 15533.84 3.5306 82.321 1344.49 21.8989 4.6815 1.624 56.259 1.4757 36.542 16.8549
181 2022-04-22 1.0817 138.83 1.9558 N/A 24.32 7.4402 N/A 0.83925 370.35 N/A N/A N/A 4.6336 N/A 4.9455 10.278 N/A N/A 1.0336 139.8 9.6255 7.5625 N/A N/A 15.9446 1.4816 5.0926 1.3714 7.0332 8.4859 15603.47 3.5288 82.6943 1344.04 22.0034 4.6784 1.6193 56.721 1.4784 36.724 16.8652
182 2022-04-21 1.0887 139.61 1.9558 N/A 24.38 7.4403 N/A 0.83523 370.6 N/A N/A N/A 4.63 N/A 4.945 10.2553 N/A N/A 1.0335 139 9.5788 7.5635 N/A N/A 15.9983 1.4653 5.0324 1.36 7.0228 8.5406 15624.02 3.5153 82.965 1348.33 21.8836 4.6716 1.6053 57.081 1.482 36.891 16.5996
183 2022-04-20 1.083 138.53 1.9558 N/A 24.409 7.4405 N/A 0.82965 371.36 N/A N/A N/A 4.6338 N/A 4.9436 10.23 N/A N/A 1.0254 139.2 9.5443 7.561 N/A N/A 15.8892 1.4581 5.0481 1.3579 6.9448 8.494 15537.05 3.4908 82.6348 1337.89 21.6392 4.6415 1.595 56.747 1.4779 36.567 16.3019
184 2022-04-19 1.0803 138.4 1.9558 N/A 24.424 7.4391 N/A 0.82955 374.12 N/A N/A N/A 4.6553 N/A 4.9411 10.3408 N/A N/A 1.0208 139.8 9.5228 7.562 N/A N/A 15.8416 1.4663 5.0261 1.3631 6.9008 8.4698 15498.35 3.5038 82.6038 1339.46 21.4725 4.5961 1.6016 56.683 1.4763 36.466 16.0401
185 2022-04-14 1.0878 136.32 1.9558 N/A 24.42 7.4389 N/A 0.82908 376.57 N/A N/A N/A 4.6478 N/A 4.9459 10.3008 N/A N/A 1.0189 140.4 9.5313 7.5587 N/A N/A 15.9046 1.4612 5.1226 1.3663 6.932 8.5298 15621.3 3.4896 82.814 1334.71 21.5941 4.603 1.5957 56.759 1.4732 36.615 15.9331
186 2022-04-13 1.0826 136.26 1.9558 N/A 24.45 7.4377 N/A 0.8328 378.45 N/A N/A N/A 4.6453 N/A 4.9415 10.3323 N/A N/A 1.0116 140.2 9.5693 7.5538 N/A N/A 15.7992 1.4603 5.0449 1.37 6.8939 8.4867 15549.1 3.4782 82.478 1328.47 21.417 4.5799 1.5991 56.446 1.4769 36.305 15.682
187 2022-04-12 1.0861 136.29 1.9558 N/A 24.45 7.4379 N/A 0.83455 377.78 N/A N/A N/A 4.6552 N/A 4.9417 10.332 N/A N/A 1.0131 139.6 9.5395 7.5513 N/A N/A 15.9548 1.4599 5.0944 1.3724 6.9199 8.5112 15609.66 3.4972 82.7285 1335.49 21.5616 4.5972 1.5874 56.574 1.4803 36.531 15.849
188 2022-04-11 1.09 137.01 1.9558 N/A 24.429 7.4375 N/A 0.83693 378.27 N/A N/A N/A 4.6456 N/A 4.9397 10.3128 N/A N/A 1.018 140 9.5478 7.5519 N/A N/A 16.0485 1.4654 5.155 1.3738 6.9405 8.544 15658.28 3.501 82.7085 1345.23 21.8653 4.6112 1.5938 56.753 1.4874 36.613 15.9127
189 2022-04-08 1.0861 134.87 1.9558 N/A 24.479 7.4372 N/A 0.83355 375.66 N/A N/A N/A 4.6437 N/A 4.9425 10.2768 N/A N/A 1.0155 139.6 9.508 7.549 N/A N/A 16.0237 1.4552 5.1583 1.3675 6.9115 8.5134 15601.96 3.501 82.389 1333.12 21.8729 4.585 1.5849 55.99 1.4801 36.488 15.9968
190 2022-04-07 1.0916 135.32 1.9558 N/A 24.512 7.4378 N/A 0.8345 379.26 N/A N/A N/A 4.637 N/A 4.9419 10.313 N/A N/A 1.0185 141 9.5595 7.5562 N/A N/A 16.0929 1.4578 5.146 1.3704 6.9448 8.5554 15692.35 3.5259 82.951 1330.92 21.9806 4.6046 1.5816 56.114 1.4848 36.541 16.052
191 2022-04-06 1.0923 135.3 1.9558 N/A 24.441 7.4378 N/A 0.83473 377.77 N/A N/A N/A 4.6328 N/A 4.9433 10.2855 N/A N/A 1.0187 141.4 9.5523 7.547 N/A N/A 16.0998 1.4431 5.0996 1.3647 6.9498 8.5617 15683.36 3.5199 82.8343 1330.44 21.8759 4.604 1.5718 56.167 1.4844 36.701 15.9934
192 2022-04-05 1.0969 134.76 1.9558 N/A 24.338 7.4378 N/A 0.8349 370.93 N/A N/A N/A 4.6265 N/A 4.9438 10.2593 N/A N/A 1.0141 141.6 9.5398 7.5399 N/A N/A 16.15 1.4374 5.0384 1.3647 6.9783 8.5917 15732.77 3.5152 82.635 1330.81 21.7474 4.6185 1.5657 56.194 1.4867 36.697 15.9529
193 2022-04-04 1.1005 135.08 1.9558 N/A 24.32 7.4385 N/A 0.8389 369.15 N/A N/A N/A 4.6375 N/A 4.9432 10.3849 N/A N/A 1.0203 141.8 9.5489 7.5455 N/A N/A 16.183 1.4651 5.1162 1.3749 7.0026 8.6226 15783.89 3.5312 83.118 1338.41 21.82 4.643 1.586 56.521 1.4938 36.894 16.0957
194 2022-04-01 1.1052 135.35 1.9558 N/A 24.376 7.4388 N/A 0.84145 368.12 N/A N/A N/A 4.6401 N/A 4.9452 10.332 N/A N/A 1.0217 142 9.6628 7.5675 N/A N/A 16.2411 1.4696 5.2188 1.3805 7.0311 8.6596 15887.5 3.5315 83.9847 1345.61 21.9087 4.6534 1.5911 57.084 1.4985 36.941 16.1685
195 2022-03-31 1.1101 135.17 1.9558 N/A 24.375 7.4379 N/A 0.84595 369.77 N/A N/A N/A 4.6531 N/A 4.9463 10.337 N/A N/A 1.0267 142 9.711 7.574 N/A N/A 16.2823 1.4829 5.3009 1.3896 7.0403 8.6918 15947 3.5243 84.134 1347.37 22.0903 4.6677 1.6014 57.514 1.5028 36.911 16.1727
196 2022-03-30 1.1126 135.47 1.9558 N/A 24.45 7.4391 N/A 0.84563 368.13 N/A N/A N/A 4.6679 N/A 4.9477 10.3498 N/A N/A 1.0309 142.2 9.6398 7.572 N/A N/A 16.3296 1.4809 5.2808 1.3891 7.0666 8.7081 15957.24 3.5399 84.38 1346.97 22.1557 4.6779 1.5947 57.906 1.5064 37.144 16.1288
197 2022-03-29 1.1085 136.66 1.9558 N/A 24.464 7.4388 N/A 0.8444 369.8 N/A N/A N/A 4.6594 N/A 4.9478 10.329 N/A N/A 1.0362 142.2 9.5995 7.5815 N/A N/A 16.3275 1.4795 5.2434 1.387 7.055 8.6767 15896.31 3.5505 83.9685 1345.62 22.1561 4.6707 1.6054 57.602 1.5051 37.29 16.1804
198 2022-03-28 1.0966 135.93 1.9558 N/A 24.65 7.4393 N/A 0.83643 374.13 N/A N/A N/A 4.718 N/A 4.9483 10.4225 N/A N/A 1.0257 142.8 9.5123 7.5735 N/A N/A 16.275 1.459 5.2133 1.3702 6.9862 8.5861 15737.77 3.5313 83.4825 1342.49 21.9841 4.6238 1.5838 57.08 1.4921 37.027 15.9925
199 2022-03-25 1.1002 134.07 1.9558 N/A 24.645 7.4404 N/A 0.8338 373.81 N/A N/A N/A 4.7307 N/A 4.9487 10.3505 N/A N/A 1.0207 142.2 9.5205 7.5754 N/A N/A 16.3304 1.4624 5.2634 1.3781 7.0007 8.6117 15777.69 3.5351 83.8235 1343.32 21.9908 4.6324 1.5787 57.322 1.4919 36.906 16.0386
200 2022-03-24 1.0978 133.71 1.9558 N/A 24.72 7.4397 N/A 0.83288 374.44 N/A N/A N/A 4.7421 N/A 4.9489 10.3555 N/A N/A 1.0225 141.2 9.4923 7.5745 N/A N/A 16.2917 1.4668 5.3057 1.3806 6.9933 8.5897 15778.31 3.5461 83.879 1342.53 22.177 4.6396 1.5812 57.426 1.4912 36.837 16.1478
201 2022-03-23 1.0985 132.65 1.9558 N/A 24.605 7.4381 N/A 0.8328 372.25 N/A N/A N/A 4.7052 N/A 4.9463 10.4005 N/A N/A 1.0269 141.4 9.6425 7.571 N/A N/A 16.3108 1.4728 5.3903 1.384 7.0003 8.5948 15792.11 3.5407 83.9675 1337.76 22.1978 4.6401 1.5822 57.565 1.4919 36.965 16.2501
202 2022-03-22 1.1024 132.96 1.9558 N/A 24.679 7.4402 N/A 0.83228 371.23 N/A N/A N/A 4.6851 N/A 4.9463 10.3822 N/A N/A 1.0275 142.7 9.6233 7.575 N/A N/A 16.3432 1.4802 5.4105 1.3867 7.0137 8.6285 15808.01 3.5521 83.9145 1343.81 22.3667 4.6483 1.586 57.749 1.4957 36.881 16.343
203 2022-03-21 1.1038 131.57 1.9558 N/A 24.683 7.4411 N/A 0.83775 374.48 N/A N/A N/A 4.696 N/A 4.947 10.4088 N/A N/A 1.0278 142.7 9.6575 7.5733 N/A N/A 16.3773 1.4897 5.502 1.3898 7.0152 8.6387 15826.61 3.5637 84.1835 1342.62 22.48 4.6415 1.5997 57.817 1.496 37.038 16.4543
204 2022-03-18 1.1008 131.4 1.9558 N/A 24.837 7.4423 N/A 0.83925 375.33 N/A N/A N/A 4.7135 N/A 4.9483 10.4303 N/A N/A 1.0314 142.9 9.694 7.5685 N/A N/A 16.3054 1.4945 5.5784 1.3911 7.0031 8.6101 15782.11 3.5761 83.7825 1337.31 22.5905 4.6157 1.6026 57.622 1.4952 36.745 16.5347
205 2022-03-17 1.1051 131.27 1.9558 N/A 24.777 7.4439 N/A 0.84315 372.05 N/A N/A N/A 4.6889 N/A 4.9465 10.4503 N/A N/A 1.0385 142.1 9.78 7.573 N/A N/A 16.3123 1.5055 5.6339 1.3998 7.0176 8.6391 15835.97 3.5777 83.8435 1340.02 22.788 4.6364 1.613 57.69 1.498 36.767 16.5286
206 2022-03-16 1.0994 130.05 1.9558 N/A 24.687 7.4412 N/A 0.83988 371.18 N/A N/A N/A 4.6765 N/A 4.9473 10.4205 N/A N/A 1.0336 143.5 9.7988 7.5725 N/A N/A 16.1783 1.5165 5.6523 1.3967 6.9817 8.5996 15690.36 3.5872 83.7805 1353.77 22.854 4.6147 1.6168 57.433 1.4966 36.681 16.5574
207 2022-03-15 1.0991 129.67 1.9558 N/A 24.867 7.441 N/A 0.84053 371.41 N/A N/A N/A 4.7355 N/A 4.9482 10.526 N/A N/A 1.0322 144.9 9.849 7.575 N/A N/A 16.0968 1.5234 5.6385 1.4099 7.0117 8.6026 15710.44 3.6088 83.9555 1366.05 22.9352 4.6239 1.6216 57.536 1.4993 36.842 16.6249
208 2022-03-14 1.096 129.3 1.9558 N/A 24.89 7.4405 N/A 0.83915 373.88 N/A N/A N/A 4.7218 N/A 4.949 10.5368 N/A N/A 1.0249 145.1 9.8588 7.5745 N/A N/A 16.2 1.5137 5.5286 1.3978 6.9738 8.5815 15678.53 3.586 83.931 1357.77 22.8311 4.6087 1.613 57.398 1.4947 36.59 16.5029
209 2022-03-11 1.099 128.46 1.9558 N/A 25.213 7.4402 N/A 0.8397 380.92 N/A N/A N/A 4.782 N/A 4.949 10.646 N/A N/A 1.023 144.9 9.8033 7.5713 N/A N/A 16.2554 1.5017 5.5077 1.4024 6.9633 8.6007 15696.64 3.5683 83.9875 1354.04 22.9524 4.6098 1.6053 57.461 1.4949 36.542 16.4896
210 2022-03-10 1.1084 128.54 1.9558 N/A 25.316 7.4401 N/A 0.84175 381.63 N/A N/A N/A 4.8239 N/A 4.9491 10.7073 N/A N/A 1.027 145.5 9.919 7.5665 N/A N/A 16.574 1.5109 5.5958 1.4189 7.0063 8.6688 15824.95 3.6219 84.607 1360.48 23.3153 4.6414 1.6185 57.825 1.5058 36.71 16.7264
211 2022-03-09 1.0993 127.31 1.9558 N/A 25.364 7.444 N/A 0.8357 379.66 N/A N/A N/A 4.8196 N/A 4.9485 10.734 N/A N/A 1.0198 145.3 9.798 7.5625 N/A N/A 16.1323 1.4991 5.5201 1.4108 6.9454 8.5974 15710.06 3.5978 84.2025 1357.08 23.2145 4.6028 1.6055 57.259 1.4966 36.326 16.656
212 2022-03-08 1.0892 126.03 1.9558 N/A 25.642 7.4441 N/A 0.83185 388.28 N/A N/A N/A 4.9103 N/A 4.9494 10.8803 N/A N/A 1.0111 145.9 9.7925 7.5715 N/A N/A 15.8183 1.4971 5.5346 1.3978 6.8805 8.5183 15639.76 3.6022 83.924 1344.71 23.2866 4.5556 1.5958 56.9 1.4856 36.156 16.7051
213 2022-03-07 1.0895 125.55 1.9558 N/A 25.584 7.4406 N/A 0.82625 393.25 N/A N/A N/A 4.9525 N/A 4.9494 10.8573 N/A N/A 1.0069 145.8 9.8325 7.56 N/A N/A 15.6577 1.4751 5.5065 1.3864 6.8846 8.5154 15685.76 3.5653 83.8125 1338.45 23.0249 4.5426 1.5861 56.832 1.4831 35.866 16.6951
214 2022-03-04 1.0929 126.17 1.9558 N/A 25.737 7.4394 N/A 0.82388 386.54 N/A N/A N/A 4.853 N/A 4.9495 10.7935 N/A N/A 1.0056 144.2 9.8358 7.5584 N/A N/A 15.5681 1.4872 5.5313 1.3937 6.9065 8.5411 15725.3 3.5603 83.4354 1332.23 22.7543 4.5661 1.6005 56.814 1.4872 35.776 16.8044
215 2022-03-03 1.1076 128.18 1.9558 N/A 25.634 7.4399 N/A 0.82773 378.64 N/A N/A N/A 4.7691 N/A 4.9496 10.7688 N/A N/A 1.0192 143.4 9.8418 7.57 N/A N/A 15.6897 1.5139 5.6041 1.3992 6.9996 8.6547 15934.42 3.5872 84.174 1334.2 22.8945 4.637 1.6329 57.293 1.5042 36.063 16.8798
216 2022-03-02 1.1106 128.08 1.9558 N/A 25.866 7.4387 N/A 0.83316 382.31 N/A N/A N/A 4.8021 N/A 4.9493 10.788 N/A N/A 1.0216 143 9.8826 7.574 N/A N/A 15.628 1.5272 5.7313 1.4088 7.0153 8.6785 15980.03 3.5954 84.1765 1338.99 22.999 4.6595 1.6404 57.206 1.5059 36.339 17.1904
217 2022-03-01 1.1162 128.15 1.9558 N/A 25.465 7.4377 N/A 0.8329 379.6 N/A N/A N/A 4.7947 N/A 4.949 10.6893 N/A N/A 1.0247 142 9.8598 7.567 117.201 N/A 15.5509 1.5365 5.7598 1.4158 7.0462 8.7234 16033.36 3.6152 84.5015 1342.6 22.8558 4.6802 1.6484 57.295 1.515 36.505 17.2145
218 2022-02-28 1.1199 129.31 1.9558 N/A 24.997 7.4404 N/A 0.8355 369.72 N/A N/A N/A 4.6835 N/A 4.9484 10.6055 N/A N/A 1.0336 141.8 9.9465 7.5655 115.4842 N/A 15.4532 1.5508 5.7828 1.4264 7.067 8.7514 16100.72 3.63 84.554 1347.62 22.9011 4.7019 1.6628 57.432 1.5201 36.593 17.2863
219 2022-02-25 1.1216 129.64 1.9558 N/A 24.66 7.4418 N/A 0.8374 365.28 N/A N/A N/A 4.6369 N/A 4.9479 10.5848 N/A N/A 1.0398 140.8 9.9756 7.5535 92.5673 N/A 15.4799 1.5541 5.738 1.4325 7.0828 8.7578 16088.71 3.6389 84.347 1346.44 22.9145 4.7107 1.6651 57.549 1.5176 36.441 17.0315
220 2022-02-24 1.1163 128.28 1.9558 N/A 25.09 7.4405 N/A 0.83463 368.63 N/A N/A N/A 4.6554 N/A 4.9501 10.7338 N/A N/A 1.032 142 10.0878 7.552 95.7175 N/A 16.0525 1.5593 5.6874 1.4316 7.0601 8.7178 16074 3.6618 84.296 1347.7 22.9355 4.6896 1.6692 57.45 1.5125 36.514 17.1634
221 2022-02-23 1.1344 130.58 1.9558 N/A 24.473 7.4388 N/A 0.83463 357.25 N/A N/A N/A 4.5481 N/A 4.9468 10.5658 N/A N/A 1.0431 141.2 10.0335 7.5362 90.8791 N/A 15.6871 1.5592 5.6808 1.4394 7.1669 8.8529 16270.12 3.6515 84.6135 1350.23 22.9079 4.748 1.6679 57.98 1.5253 36.601 17.0508
222 2022-02-22 1.1342 130.54 1.9558 N/A 24.496 7.4392 N/A 0.83685 355.89 N/A N/A N/A 4.5447 N/A 4.9464 10.5996 N/A N/A 1.0422 141.2 10.1018 7.537 89.8055 N/A 15.6959 1.5739 5.7677 1.4441 7.1771 8.8495 16293.92 3.6584 84.758 1353.34 23.033 4.7472 1.6848 58.208 1.5268 36.748 17.1768
223 2022-02-21 1.1338 130.2 1.9558 N/A 24.345 7.4397 N/A 0.83298 357.54 N/A N/A N/A 4.5351 N/A 4.9448 10.6535 N/A N/A 1.0387 141.4 10.1738 7.536 89.0866 N/A 15.4689 1.5751 5.8045 1.4454 7.1831 8.8443 16276.34 3.6433 84.677 1353.02 22.9951 4.7387 1.687 58.3 1.5265 36.588 17.1895
224 2022-02-18 1.1354 130.59 1.9558 N/A 24.337 7.4382 N/A 0.83425 356.37 N/A N/A N/A 4.5201 N/A 4.9453 10.5796 N/A N/A 1.0452 140.8 10.1465 7.5355 86.2815 N/A 15.4678 1.5754 5.8435 1.4424 7.184 8.8566 16304.49 3.6276 84.6525 1356.45 23.027 4.7528 1.6896 58.403 1.5255 36.435 17.0858
225 2022-02-17 1.137 130.84 1.9558 N/A 24.383 7.4398 N/A 0.83493 356.08 N/A N/A N/A 4.5065 N/A 4.9432 10.593 N/A N/A 1.0466 141.6 10.1225 7.533 86.388 N/A 15.4945 1.5786 5.8495 1.4439 7.206 8.8692 16291.53 3.6231 85.2935 1360.7 23.0367 4.7612 1.695 58.314 1.5278 36.537 16.9893
226 2022-02-16 1.1372 131.56 1.9558 N/A 24.365 7.441 N/A 0.8394 355.65 N/A N/A N/A 4.4961 N/A 4.9436 10.5363 N/A N/A 1.0516 141.4 10.1095 7.5295 85.3679 N/A 15.481 1.5859 5.8765 1.4416 7.2101 8.8712 16232.55 3.6256 85.3885 1361.31 23.1718 4.7595 1.7108 58.346 1.5291 36.771 17.214
227 2022-02-15 1.1345 131.18 1.9558 N/A 24.419 7.4422 N/A 0.83765 355.33 N/A N/A N/A 4.5036 N/A 4.941 10.5739 N/A N/A 1.0483 141.2 10.0893 7.529 85.5025 N/A 15.4716 1.5888 5.8977 1.4433 7.1969 8.8527 16187.89 3.6596 85.443 1357.5 23.1113 4.7493 1.7143 58.144 1.5265 36.724 17.1767
228 2022-02-14 1.1316 130.6 1.9558 N/A 24.527 7.4411 N/A 0.8372 357.06 N/A N/A N/A 4.54 N/A 4.9457 10.6158 N/A N/A 1.0472 142.6 10.0693 7.5293 86.348 N/A 15.351 1.5902 5.8965 1.4431 7.1937 8.8283 16190.53 3.6835 85.4715 1354.5 23.1331 4.742 1.7112 58.114 1.5247 36.8 17.131
229 2022-02-11 1.1417 132.24 1.9558 N/A 24.405 7.44 N/A 0.83958 353.38 N/A N/A N/A 4.5204 N/A 4.9458 10.553 N/A N/A 1.0557 141.8 10.0732 7.5312 85.855 N/A 15.4066 1.5927 5.9263 1.4498 7.2564 8.9054 16339.46 3.6958 85.8535 1363.68 23.3183 4.7832 1.7085 58.482 1.5339 37.282 17.2736
230 2022-02-10 1.1439 132.42 1.9558 N/A 24.35 7.4404 N/A 0.84248 354.02 N/A N/A N/A 4.4921 N/A 4.9451 10.5275 N/A N/A 1.0571 141.8 10.0693 7.5275 85.0187 N/A 15.4838 1.5894 5.9668 1.4498 7.2722 8.9142 16390.21 3.6796 85.9373 1367.52 23.3584 4.7855 1.7076 58.583 1.5345 37.331 17.3078
231 2022-02-09 1.1435 132.04 1.9558 N/A 24.288 7.4437 N/A 0.84255 352.94 N/A N/A N/A 4.5135 N/A 4.9449 10.4075 N/A N/A 1.0555 142.2 10.0585 7.5285 85.5289 N/A 15.551 1.5933 6.0198 1.4514 7.2759 8.9106 16390.99 3.6817 85.5765 1365.72 23.4719 4.7853 1.7107 58.603 1.5349 37.404 17.5281
232 2022-02-08 1.1408 131.68 1.9558 N/A 24.259 7.4437 N/A 0.84363 353.09 N/A N/A N/A 4.5312 N/A 4.945 10.4433 N/A N/A 1.0545 142.4 10.0758 7.5215 85.7797 N/A 15.5558 1.6025 6.0209 1.4505 7.2636 8.8923 16418.4 3.6753 85.2545 1367.88 23.5601 4.774 1.7196 58.715 1.5349 37.606 17.638
233 2022-02-07 1.1447 131.59 1.9558 N/A 24.222 7.4443 N/A 0.84685 353.48 N/A N/A N/A 4.5432 N/A 4.9461 10.4483 N/A N/A 1.0571 143.4 10.0658 7.52 86.5824 N/A 15.5235 1.6097 6.0541 1.4546 7.2807 8.9202 16478.97 3.6547 85.5345 1371.76 23.575 4.7909 1.7278 58.978 1.5389 37.735 17.7
234 2022-02-04 1.1464 131.72 1.9558 N/A 24.36 7.4432 N/A 0.84593 352.92 N/A N/A N/A 4.5474 N/A 4.9466 10.4465 N/A N/A 1.0567 142.8 10.0483 7.5275 87.3095 N/A 15.5072 1.6165 6.083 1.4583 7.2923 8.9286 16493.16 3.6741 85.6445 1374.04 23.5856 4.7914 1.7287 58.754 1.5419 37.797 17.5875
235 2022-02-03 1.1286 129.63 1.9558 N/A 24.135 7.4388 N/A 0.83208 353.94 N/A N/A N/A 4.5315 N/A 4.9461 10.387 N/A N/A 1.0407 142.4 9.9545 7.5295 86.1788 N/A 15.3047 1.5849 5.9843 1.4334 7.1795 8.7966 16243.28 3.5949 84.518 1358.42 23.2359 4.7215 1.7001 57.608 1.5212 37.424 17.2864
236 2022-02-02 1.1323 129.37 1.9558 N/A 24.298 7.4383 N/A 0.83395 354.45 N/A N/A N/A 4.5449 N/A 4.9463 10.385 N/A N/A 1.0399 143.2 9.9228 7.526 85.815 N/A 15.3011 1.5828 5.9677 1.433 7.2026 8.8245 16243.98 3.5777 84.613 1359.23 23.2134 4.7392 1.701 57.785 1.5254 37.575 17.3459
237 2022-02-01 1.126 129.12 1.9558 N/A 24.335 7.4407 N/A 0.83498 356.38 N/A N/A N/A 4.5804 N/A 4.9465 10.4438 N/A N/A 1.0374 143.8 9.9638 7.5275 86.3238 N/A 15.0644 1.5868 5.9572 1.4299 7.1625 8.7779 16126.29 3.566 84.197 1353.61 23.1296 4.7129 1.7032 57.516 1.5199 37.378 17.1633
238 2022-01-31 1.1156 128.79 1.9558 N/A 24.372 7.4419 N/A 0.83153 357.19 N/A N/A N/A 4.5892 N/A 4.9475 10.489 N/A N/A 1.0404 143.2 10.0085 7.5293 86.7251 N/A 14.931 1.582 6.003 1.4233 7.0963 8.6994 16036.76 3.564 83.3655 1349.08 23.1856 4.6693 1.6983 56.985 1.511 37.144 17.3734
239 2022-01-28 1.1138 128.68 1.9558 N/A 24.443 7.4432 N/A 0.83178 358.42 N/A N/A N/A 4.5755 N/A 4.9463 10.552 N/A N/A 1.0378 144 10.026 7.529 86.6113 N/A 15.1424 1.5971 6.0147 1.4239 7.0857 8.681 16047.76 3.5697 83.6015 1349.47 23.1854 4.6668 1.7031 57.028 1.5109 37.229 17.3844
240 2022-01-27 1.116 128.74 1.9558 N/A 24.427 7.4428 N/A 0.83368 358.09 N/A N/A N/A 4.5592 N/A 4.9466 10.445 N/A N/A 1.0391 145.2 9.9903 7.5328 87.139 N/A 15.1946 1.5771 6.0159 1.4161 7.1061 8.6951 16052.42 3.5695 83.7893 1344.5 23.143 4.6844 1.6872 57.295 1.5089 37.124 17.1112
241 2022-01-26 1.1277 128.86 1.9558 N/A 24.531 7.442 N/A 0.83458 359.67 N/A N/A N/A 4.5864 N/A 4.9451 10.4493 N/A N/A 1.0386 145.6 10.0115 7.529 89.265 N/A 15.2877 1.5727 6.1084 1.4173 7.1293 8.7791 16185.31 3.5834 84.4288 1350.03 23.1845 4.7268 1.6865 57.728 1.5162 37.169 17.0858
242 2022-01-25 1.1268 128.49 1.9558 N/A 24.5 7.4437 N/A 0.83713 359.44 N/A N/A N/A 4.5751 N/A 4.9448 10.502 N/A N/A 1.0364 146 10.1385 7.5295 88.7384 N/A 15.2723 1.5814 6.2049 1.4247 7.1325 8.7725 16169.54 3.5898 84.277 1350.71 23.2909 4.7213 1.6911 57.753 1.5157 37.28 17.2669
243 2022-01-24 1.1304 128.62 1.9558 N/A 24.528 7.4431 N/A 0.83803 359.84 N/A N/A N/A 4.5572 N/A 4.9453 10.5038 N/A N/A 1.0308 145.6 10.1638 7.529 88.649 N/A 15.1621 1.5866 6.1901 1.4269 7.1533 8.8003 16213.69 3.5846 84.3495 1352.41 23.2566 4.7352 1.6901 58.045 1.5216 37.382 17.2509
244 2022-01-21 1.1348 129.14 1.9558 N/A 24.347 7.4431 N/A 0.83633 358.19 N/A N/A N/A 4.5318 N/A 4.9453 10.414 N/A N/A 1.0353 145.6 10.0523 7.528 86.838 N/A 15.223 1.5774 6.2063 1.4211 7.1946 8.837 16244.2 3.5668 84.419 1351.89 23.2229 4.7508 1.6884 58.171 1.526 37.358 17.1546
245 2022-01-20 1.1338 129.53 1.9558 N/A 24.263 7.4424 N/A 0.83265 355.81 N/A N/A N/A 4.5228 N/A 4.9453 10.3708 N/A N/A 1.0382 145.4 9.9578 7.525 86.8952 N/A 15.2094 1.5662 6.1621 1.4158 7.1936 8.8274 16267.5 3.5564 84.362 1349.16 23.1684 4.7489 1.6731 58.285 1.5261 37.319 17.2531
246 2022-01-19 1.1345 129.86 1.9558 N/A 24.313 7.4419 N/A 0.83168 355.88 N/A N/A N/A 4.5229 N/A 4.9449 10.3428 N/A N/A 1.0383 145.2 9.9368 7.5238 86.48 N/A 15.4207 1.5709 6.2657 1.4144 7.2003 8.8392 16283.78 3.5529 84.4135 1347.1 23.0922 4.757 1.6684 58.429 1.5293 37.467 17.3889
247 2022-01-18 1.1367 130.39 1.9558 N/A 24.426 7.4425 N/A 0.83673 357 N/A N/A N/A 4.526 N/A 4.9449 10.3185 N/A N/A 1.0414 146 9.9638 7.5225 86.7325 N/A 15.4447 1.5833 6.2797 1.4228 7.2212 8.8576 16318.64 3.5557 84.813 1355.33 23.1443 4.7554 1.6798 58.553 1.5349 37.635 17.5398
248 2022-01-17 1.1403 130.64 1.9558 N/A 24.467 7.4417 N/A 0.83573 356.09 N/A N/A N/A 4.5256 N/A 4.9443 10.305 N/A N/A 1.0429 146.8 9.9623 7.5275 87.3907 N/A 15.2757 1.5811 6.2808 1.4287 7.2402 8.8844 16337.73 3.5479 84.7295 1359.89 23.1901 4.7704 1.6765 58.496 1.5374 37.761 17.601
249 2022-01-14 1.1447 130.17 1.9558 N/A 24.493 7.4414 N/A 0.83508 356.1 N/A N/A N/A 4.5414 N/A 4.9429 10.2684 N/A N/A 1.0429 147 9.9863 7.5205 88.0011 N/A 15.5256 1.5803 6.3361 1.433 7.2728 8.9119 16388.85 3.5565 84.9445 1361.27 23.2684 4.7831 1.6745 58.727 1.5418 38.033 17.6043
250 2022-01-13 1.1463 130.98 1.9558 N/A 24.458 7.4409 N/A 0.83545 355.24 N/A N/A N/A 4.5361 N/A 4.944 10.238 N/A N/A 1.0453 147 9.9333 7.5202 86.603 N/A 15.5744 1.5709 6.3518 1.4304 7.2913 8.9289 16379.02 3.5638 84.717 1359.24 23.3894 4.7875 1.6676 58.572 1.5427 38.08 17.6381
251 2022-01-12 1.137 131.19 1.9558 N/A 24.423 7.4414 N/A 0.83338 355.98 N/A N/A N/A 4.5359 N/A 4.9453 10.264 N/A N/A 1.0486 147 9.927 7.524 84.7559 N/A 15.5922 1.5762 6.3458 1.4261 7.2379 8.863 16295.93 3.5406 84.0285 1353.27 23.1852 4.7595 1.6775 58.08 1.5358 37.936 17.5645
252 2022-01-11 1.1336 130.95 1.9558 N/A 24.412 7.4404 N/A 0.83475 357.45 N/A N/A N/A 4.5438 N/A 4.945 10.3075 N/A N/A 1.0502 147 10.0165 7.5236 84.8663 N/A 15.696 1.5804 6.389 1.4329 7.2255 8.8384 16221.39 3.549 83.7481 1352.85 23.0888 4.7515 1.6772 57.979 1.5342 37.862 17.7094
253 2022-01-10 1.1318 130.45 1.9558 N/A 24.357 7.4381 N/A 0.83398 358.4 N/A N/A N/A 4.5334 N/A 4.9449 10.3038 N/A N/A 1.0446 146.2 10.0253 7.5278 84.9825 N/A 15.7183 1.5774 6.3969 1.4327 7.2128 8.8233 16181.9 3.5303 83.8 1355.68 23.0597 4.7536 1.6753 58.141 1.5344 38.074 17.6999
254 2022-01-07 1.1298 130.9 1.9558 N/A 24.439 7.438 N/A 0.8343 358.68 N/A N/A N/A 4.5496 N/A 4.9451 10.2839 N/A N/A 1.0422 146 10.0288 7.5214 85.298 N/A 15.7206 1.5804 6.4343 1.4374 7.206 8.8133 16188.43 3.5135 83.978 1359.96 23.1109 4.7553 1.6748 58.046 1.5356 38.074 17.6701
255 2022-01-06 1.1315 131.05 1.9558 N/A 24.528 7.4393 N/A 0.83593 359.84 N/A N/A N/A 4.5614 N/A 4.9435 10.3265 N/A N/A 1.0395 146.8 10.035 7.5197 86.5088 N/A 15.5504 1.5778 6.442 1.4451 7.2187 8.8272 16291.88 3.5247 84.2475 1362.06 23.2549 4.767 1.6752 57.943 1.5388 37.962 17.7932
256 2022-01-05 1.1319 131.03 1.9558 N/A 24.581 7.4384 N/A 0.83546 362.15 N/A N/A N/A 4.5666 N/A 4.946 10.2545 N/A N/A 1.0364 146.8 9.9672 7.519 85.7275 N/A 15.2446 1.56 6.4146 1.4399 7.2087 8.8227 16263.02 3.4989 84.161 1354.61 23.1422 4.7466 1.6597 57.713 1.534 37.607 17.9369
257 2022-01-04 1.1279 131.17 1.9558 N/A 24.745 7.4378 N/A 0.83618 365.12 N/A N/A N/A 4.5667 N/A 4.9481 10.2808 N/A N/A 1.0355 147.8 10.0138 7.5185 84.9202 N/A 15.1384 1.5682 6.4174 1.4382 7.1924 8.7919 16199.73 3.4909 84.2055 1352.91 23.1808 4.7214 1.6668 57.988 1.531 37.582 18.108
258 2022-01-03 1.1355 130.56 1.9558 N/A 24.818 7.4382 N/A 0.84135 367.71 N/A N/A N/A 4.5895 N/A 4.9483 10.2958 N/A N/A 1.0372 147.6 10.0013 7.519 84.5313 N/A 15.0777 1.5691 6.3539 1.442 7.2174 8.8541 16202.02 3.5139 84.3949 1354.4 23.2259 4.7379 1.6651 58.051 1.5333 37.665 17.9661

128
ext/lines/lines.go Normal file
View File

@@ -0,0 +1,128 @@
// Package lines provides a virtual table to read large files line-by-line.
package lines
import (
"bufio"
"bytes"
"fmt"
"io"
"math"
"os"
"github.com/ncruces/go-sqlite3"
)
// Register registers the lines and lines_read virtual tables.
// The lines virtual table reads from a database blob or text.
// The lines_read virtual table reads from a file or an [io.ReaderAt].
func Register(db *sqlite3.Conn) {
sqlite3.CreateModule[lines](db, "lines", nil,
func(db *sqlite3.Conn, _, _, _ string, _ ...string) (lines, error) {
err := db.DeclareVtab(`CREATE TABLE x(line TEXT, data HIDDEN)`)
db.VtabConfig(sqlite3.VTAB_INNOCUOUS)
return false, err
})
sqlite3.CreateModule[lines](db, "lines_read", nil,
func(db *sqlite3.Conn, _, _, _ string, _ ...string) (lines, error) {
err := db.DeclareVtab(`CREATE TABLE x(line TEXT, data HIDDEN)`)
db.VtabConfig(sqlite3.VTAB_DIRECTONLY)
return true, err
})
}
type lines bool
func (l lines) BestIndex(idx *sqlite3.IndexInfo) error {
for i, cst := range idx.Constraint {
if cst.Column == 1 && cst.Op == sqlite3.INDEX_CONSTRAINT_EQ && cst.Usable {
idx.ConstraintUsage[i] = sqlite3.IndexConstraintUsage{
Omit: true,
ArgvIndex: 1,
}
idx.EstimatedCost = 1e6
idx.EstimatedRows = 100
return nil
}
}
return sqlite3.CONSTRAINT
}
func (l lines) Open() (sqlite3.VTabCursor, error) {
return &cursor{reader: bool(l)}, nil
}
type cursor struct {
scanner *bufio.Scanner
closer io.Closer
rowID int64
eof bool
reader bool
}
func (c *cursor) Close() (err error) {
if c.closer != nil {
err = c.closer.Close()
c.closer = nil
}
return err
}
func (c *cursor) EOF() bool {
return c.eof
}
func (c *cursor) Next() error {
c.rowID++
c.eof = !c.scanner.Scan()
return c.scanner.Err()
}
func (c *cursor) RowID() (int64, error) {
return c.rowID, nil
}
func (c *cursor) Column(ctx *sqlite3.Context, n int) error {
if n == 0 {
ctx.ResultRawText(c.scanner.Bytes())
}
return nil
}
func (c *cursor) Filter(idxNum int, idxStr string, arg ...sqlite3.Value) error {
if err := c.Close(); err != nil {
return err
}
var r io.Reader
data := arg[0]
typ := data.Type()
if c.reader {
switch typ {
case sqlite3.NULL:
if p, ok := data.Pointer().(io.ReaderAt); ok {
r = io.NewSectionReader(p, 0, math.MaxInt64)
}
case sqlite3.TEXT:
f, err := os.Open(data.Text())
if err != nil {
return err
}
c.closer = f
r = f
}
} else {
switch typ {
case sqlite3.TEXT:
r = bytes.NewReader(data.RawText())
case sqlite3.BLOB:
r = bytes.NewReader(data.RawBlob())
}
}
if r == nil {
return fmt.Errorf("lines: unsupported argument:%.0w %v", sqlite3.MISMATCH, typ)
}
c.scanner = bufio.NewScanner(r)
c.rowID = 0
return c.Next()
}

186
ext/lines/lines_test.go Normal file
View File

@@ -0,0 +1,186 @@
package lines_test
import (
"database/sql"
"errors"
"fmt"
"log"
"os"
"strings"
"testing"
"github.com/ncruces/go-sqlite3"
"github.com/ncruces/go-sqlite3/driver"
_ "github.com/ncruces/go-sqlite3/embed"
"github.com/ncruces/go-sqlite3/ext/lines"
)
func Example() {
db, err := driver.Open(":memory:", func(c *sqlite3.Conn) error {
lines.Register(c)
return nil
})
if err != nil {
log.Fatal(err)
}
defer db.Close()
// https://storage.googleapis.com/quickdraw_dataset/full/simplified/calendar.ndjson
f, err := os.Open("calendar.ndjson")
if err != nil {
log.Fatal(err)
}
defer f.Close()
rows, err := db.Query(`
SELECT
line ->> '$.countrycode' as countrycode,
COUNT(*)
FROM lines_read(?)
GROUP BY 1
ORDER BY 2 DESC
LIMIT 5`,
sqlite3.Pointer(f))
if err != nil {
log.Fatal(err)
}
defer rows.Close()
var countrycode sql.RawBytes
var count int
for rows.Next() {
err := rows.Scan(&countrycode, &count)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s: %d\n", countrycode, count)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
// Sample output:
// US: 141001
// GB: 22560
// CA: 11759
// RU: 9250
// DE: 8748
}
func Test_lines(t *testing.T) {
t.Parallel()
db, err := driver.Open(":memory:", func(c *sqlite3.Conn) error {
lines.Register(c)
return nil
})
if err != nil {
log.Fatal(err)
}
defer db.Close()
const data = "line 1\nline 2\nline 3"
rows, err := db.Query(`SELECT rowid, line FROM lines(?)`, data)
if err != nil {
t.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int64
var line string
err := rows.Scan(&id, &line)
if err != nil {
t.Fatal(err)
}
}
}
func Test_lines_error(t *testing.T) {
t.Parallel()
db, err := driver.Open(":memory:", func(c *sqlite3.Conn) error {
lines.Register(c)
return nil
})
if err != nil {
log.Fatal(err)
}
defer db.Close()
_, err = db.Exec(`SELECT rowid, line FROM lines(?)`, nil)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
_, err = db.Exec(`SELECT rowid, line FROM lines_read(?)`, "xpto")
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
}
func Test_lines_read(t *testing.T) {
t.Parallel()
db, err := driver.Open(":memory:", func(c *sqlite3.Conn) error {
lines.Register(c)
return nil
})
if err != nil {
log.Fatal(err)
}
defer db.Close()
const data = "line 1\nline 2\nline 3"
rows, err := db.Query(`SELECT rowid, line FROM lines_read(?)`,
sqlite3.Pointer(strings.NewReader(data)))
if err != nil {
t.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int64
var line string
err := rows.Scan(&id, &line)
if err != nil {
t.Fatal(err)
}
}
}
func Test_lines_test(t *testing.T) {
t.Parallel()
db, err := driver.Open(":memory:", func(c *sqlite3.Conn) error {
lines.Register(c)
return nil
})
if err != nil {
log.Fatal(err)
}
defer db.Close()
rows, err := db.Query(`SELECT rowid, line FROM lines_read(?)`, "lines_test.go")
if errors.Is(err, os.ErrNotExist) {
t.Skip(err)
}
if err != nil {
t.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int64
var line string
err := rows.Scan(&id, &line)
if err != nil {
t.Fatal(err)
}
}
}

267
ext/pivot/pivot.go Normal file
View File

@@ -0,0 +1,267 @@
// Package pivot implements a pivot virtual table.
//
// https://github.com/jakethaw/pivot_vtab
package pivot
import (
"errors"
"fmt"
"strings"
"github.com/ncruces/go-sqlite3"
)
// Register registers the pivot virtual table.
func Register(db *sqlite3.Conn) {
sqlite3.CreateModule(db, "pivot", declare, declare)
}
type table struct {
db *sqlite3.Conn
scan string
cell string
keys []string
cols []*sqlite3.Value
}
func declare(db *sqlite3.Conn, _, _, _ string, arg ...string) (_ *table, err error) {
if len(arg) != 3 {
return nil, fmt.Errorf("pivot: wrong number of arguments")
}
table := &table{db: db}
defer func() {
if err != nil {
table.Close()
}
}()
var sep string
var create strings.Builder
create.WriteString("CREATE TABLE x(")
// Row key query.
table.scan = "SELECT * FROM\n" + arg[0]
stmt, _, err := db.Prepare(table.scan)
if err != nil {
return nil, err
}
defer stmt.Close()
table.keys = make([]string, stmt.ColumnCount())
for i := range table.keys {
name := sqlite3.QuoteIdentifier(stmt.ColumnName(i))
table.keys[i] = name
create.WriteString(sep)
create.WriteString(name)
sep = ","
}
stmt.Close()
// Column definition query.
stmt, _, err = db.Prepare("SELECT * FROM\n" + arg[1])
if err != nil {
return nil, err
}
if stmt.ColumnCount() != 2 {
return nil, fmt.Errorf("pivot: column definition query expects 2 result columns")
}
for stmt.Step() {
name := sqlite3.QuoteIdentifier(stmt.ColumnText(1))
table.cols = append(table.cols, stmt.ColumnValue(0).Dup())
create.WriteString(",")
create.WriteString(name)
}
stmt.Close()
// Pivot cell query.
table.cell = "SELECT * FROM\n" + arg[2]
stmt, _, err = db.Prepare(table.cell)
if err != nil {
return nil, err
}
if stmt.ColumnCount() != 1 {
return nil, fmt.Errorf("pivot: cell query expects 1 result columns")
}
if stmt.BindCount() != len(table.keys)+1 {
return nil, fmt.Errorf("pivot: cell query expects %d bound parameters", len(table.keys)+1)
}
create.WriteByte(')')
err = db.DeclareVtab(create.String())
if err != nil {
return nil, err
}
return table, nil
}
func (t *table) Close() error {
for i := range t.cols {
t.cols[i].Close()
}
return nil
}
func (t *table) BestIndex(idx *sqlite3.IndexInfo) error {
var idxStr strings.Builder
idxStr.WriteString(t.scan)
argvIndex := 1
sep := " WHERE "
for i, cst := range idx.Constraint {
if !cst.Usable || !(0 <= cst.Column && cst.Column < len(t.keys)) {
continue
}
var op string
switch cst.Op {
case sqlite3.INDEX_CONSTRAINT_EQ:
op = "="
case sqlite3.INDEX_CONSTRAINT_LT:
op = "<"
case sqlite3.INDEX_CONSTRAINT_GT:
op = ">"
case sqlite3.INDEX_CONSTRAINT_LE:
op = "<="
case sqlite3.INDEX_CONSTRAINT_GE:
op = ">="
case sqlite3.INDEX_CONSTRAINT_NE:
op = "<>"
case sqlite3.INDEX_CONSTRAINT_MATCH:
op = "MATCH"
case sqlite3.INDEX_CONSTRAINT_LIKE:
op = "LIKE"
case sqlite3.INDEX_CONSTRAINT_GLOB:
op = "GLOB"
case sqlite3.INDEX_CONSTRAINT_REGEXP:
op = "REGEXP"
case sqlite3.INDEX_CONSTRAINT_IS, sqlite3.INDEX_CONSTRAINT_ISNULL:
op = "IS"
case sqlite3.INDEX_CONSTRAINT_ISNOT, sqlite3.INDEX_CONSTRAINT_ISNOTNULL:
op = "IS NOT"
default:
continue
}
idxStr.WriteString(sep)
idxStr.WriteString(t.keys[cst.Column])
idxStr.WriteString(" ")
idxStr.WriteString(op)
idxStr.WriteString(" ?")
idx.ConstraintUsage[i] = sqlite3.IndexConstraintUsage{
ArgvIndex: argvIndex,
Omit: true,
}
sep = " AND "
argvIndex++
}
sep = " ORDER BY "
idx.OrderByConsumed = true
for _, ord := range idx.OrderBy {
if !(0 <= ord.Column && ord.Column < len(t.keys)) {
idx.OrderByConsumed = false
continue
}
idxStr.WriteString(sep)
idxStr.WriteString(t.keys[ord.Column])
if ord.Desc {
idxStr.WriteString(" DESC")
}
sep = ","
}
idx.EstimatedCost = 1e9 / float64(argvIndex)
idx.IdxStr = idxStr.String()
return nil
}
func (t *table) Open() (sqlite3.VTabCursor, error) {
return &cursor{table: t}, nil
}
func (t *table) Rename(new string) error {
return nil
}
type cursor struct {
table *table
scan *sqlite3.Stmt
cell *sqlite3.Stmt
rowID int64
}
func (c *cursor) Close() error {
return errors.Join(c.scan.Close(), c.cell.Close())
}
func (c *cursor) Filter(idxNum int, idxStr string, arg ...sqlite3.Value) error {
err := c.scan.Close()
if err != nil {
return err
}
c.scan, _, err = c.table.db.Prepare(idxStr)
if err != nil {
return err
}
for i, arg := range arg {
err := c.scan.BindValue(i+1, arg)
if err != nil {
return err
}
}
if c.cell == nil {
c.cell, _, err = c.table.db.Prepare(c.table.cell)
if err != nil {
return err
}
}
c.rowID = 0
return c.Next()
}
func (c *cursor) Next() error {
if c.scan.Step() {
count := c.scan.ColumnCount()
for i := 0; i < count; i++ {
err := c.cell.BindValue(i+1, c.scan.ColumnValue(i))
if err != nil {
return err
}
}
c.rowID++
}
return c.scan.Err()
}
func (c *cursor) EOF() bool {
return !c.scan.Busy()
}
func (c *cursor) RowID() (int64, error) {
return c.rowID, nil
}
func (c *cursor) Column(ctx *sqlite3.Context, col int) error {
count := c.scan.ColumnCount()
if col < count {
ctx.ResultValue(c.scan.ColumnValue(col))
return nil
}
err := c.cell.BindValue(count+1, *c.table.cols[col-count])
if err != nil {
return err
}
if c.cell.Step() {
ctx.ResultValue(c.cell.ColumnValue(0))
}
return c.cell.Reset()
}

219
ext/pivot/pivot_test.go Normal file
View File

@@ -0,0 +1,219 @@
package pivot_test
import (
"fmt"
"log"
"strings"
"testing"
"github.com/ncruces/go-sqlite3"
_ "github.com/ncruces/go-sqlite3/embed"
"github.com/ncruces/go-sqlite3/ext/pivot"
)
// https://antonz.org/sqlite-pivot-table/
func Example() {
db, err := sqlite3.Open(":memory:")
if err != nil {
log.Fatal(err)
}
defer db.Close()
pivot.Register(db)
err = db.Exec(`
CREATE TABLE sales(product TEXT, year INT, income DECIMAL);
INSERT INTO sales(product, year, income) VALUES
('alpha', 2020, 100),
('alpha', 2021, 120),
('alpha', 2022, 130),
('alpha', 2023, 140),
('beta', 2020, 10),
('beta', 2021, 20),
('beta', 2022, 40),
('beta', 2023, 80),
('gamma', 2020, 80),
('gamma', 2021, 75),
('gamma', 2022, 78),
('gamma', 2023, 80);
`)
if err != nil {
log.Fatal(err)
}
err = db.Exec(`
CREATE VIRTUAL TABLE v_sales USING pivot(
-- rows
(SELECT DISTINCT product FROM sales),
-- columns
(SELECT DISTINCT year, year FROM sales),
-- cells
(SELECT sum(income) FROM sales WHERE product = ? AND year = ?)
)`)
if err != nil {
log.Fatal(err)
}
stmt, _, err := db.Prepare(`SELECT * FROM v_sales`)
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
cols := make([]string, stmt.ColumnCount())
for i := range cols {
cols[i] = stmt.ColumnName(i)
}
fmt.Println(pretty(cols))
for stmt.Step() {
for i := range cols {
cols[i] = stmt.ColumnText(i)
}
fmt.Println(pretty(cols))
}
if err := stmt.Reset(); err != nil {
log.Fatal(err)
}
// Output:
// product 2020 2021 2022 2023
// alpha 100 120 130 140
// beta 10 20 40 80
// gamma 80 75 78 80
}
func TestRegister(t *testing.T) {
t.Parallel()
db, err := sqlite3.Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
pivot.Register(db)
err = db.Exec(`
CREATE TABLE r AS
SELECT 1 id UNION SELECT 2 UNION SELECT 3;
CREATE TABLE c(
id INTEGER PRIMARY KEY,
name TEXT
);
INSERT INTO c (name) VALUES
('a'),('b'),('c'),('d');
CREATE TABLE x(
r_id INT,
c_id INT,
val TEXT
);
INSERT INTO x (r_id, c_id, val)
SELECT r.id, c.id, c.name || r.id
FROM c, r;
`)
if err != nil {
t.Fatal(err)
}
err = db.Exec(`
CREATE VIRTUAL TABLE v_x USING pivot(
-- rows
(SELECT id r_id FROM r),
-- columns
(SELECT id c_id, name FROM c),
-- cells
(SELECT val FROM x WHERE r_id = ?1 AND c_id = ?2)
)`)
if err != nil {
t.Fatal(err)
}
stmt, _, err := db.Prepare(`SELECT * FROM v_x WHERE rowid <> 0 AND r_id <> 1 ORDER BY rowid, r_id DESC LIMIT 1`)
if err != nil {
t.Fatal(err)
}
defer stmt.Close()
if stmt.Step() {
if got := stmt.ColumnInt(0); got != 3 {
t.Errorf("got %d, want 3", got)
}
}
}
func TestRegister_errors(t *testing.T) {
t.Parallel()
db, err := sqlite3.Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
pivot.Register(db)
err = db.Exec(`CREATE VIRTUAL TABLE pivot USING pivot()`)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
err = db.Exec(`CREATE VIRTUAL TABLE split_date USING pivot(SELECT 1, SELECT 2, SELECT 3)`)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
err = db.Exec(`CREATE VIRTUAL TABLE split_date USING pivot((SELECT 1), SELECT 2, SELECT 3)`)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
err = db.Exec(`CREATE VIRTUAL TABLE split_date USING pivot((SELECT 1), (SELECT 2), SELECT 3)`)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
err = db.Exec(`CREATE VIRTUAL TABLE split_date USING pivot((SELECT 1), (SELECT 1, 2), SELECT 3)`)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
err = db.Exec(`CREATE VIRTUAL TABLE split_date USING pivot((SELECT 1), (SELECT 1, 2), (SELECT 3, 4))`)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
err = db.Exec(`CREATE VIRTUAL TABLE split_date USING pivot((SELECT 1), (SELECT 1, 2), (SELECT 3))`)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
}
func pretty(cols []string) string {
var buf strings.Builder
for i, s := range cols {
if i != 0 {
buf.WriteByte(' ')
}
for buf.Len()%8 != 0 {
buf.WriteByte(' ')
}
buf.WriteString(s)
}
return buf.String()
}

210
ext/statement/stmt.go Normal file
View File

@@ -0,0 +1,210 @@
// Package statement defines table-valued functions natively using SQL.
//
// https://github.com/0x09/sqlite-statement-vtab
package statement
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"unsafe"
"github.com/ncruces/go-sqlite3"
)
// Register registers the statement virtual table.
func Register(db *sqlite3.Conn) {
sqlite3.CreateModule(db, "statement", declare, declare)
}
type table struct {
stmt *sqlite3.Stmt
sql string
inuse bool
}
func declare(db *sqlite3.Conn, _, _, _ string, arg ...string) (*table, error) {
if len(arg) != 1 {
return nil, fmt.Errorf("statement: wrong number of arguments")
}
sql := "SELECT * FROM\n" + arg[0]
stmt, _, err := db.Prepare(sql)
if err != nil {
return nil, err
}
var sep string
var str strings.Builder
str.WriteString("CREATE TABLE x(")
outputs := stmt.ColumnCount()
for i := 0; i < outputs; i++ {
name := sqlite3.QuoteIdentifier(stmt.ColumnName(i))
str.WriteString(sep)
str.WriteString(name)
str.WriteString(" ")
str.WriteString(stmt.ColumnDeclType(i))
sep = ","
}
inputs := stmt.BindCount()
for i := 1; i <= inputs; i++ {
str.WriteString(sep)
name := stmt.BindName(i)
if name == "" {
str.WriteString("[")
str.WriteString(strconv.Itoa(i))
str.WriteString("] HIDDEN")
} else {
str.WriteString(sqlite3.QuoteIdentifier(name[1:]))
str.WriteString(" HIDDEN")
}
sep = ","
}
str.WriteByte(')')
err = db.DeclareVtab(str.String())
if err != nil {
stmt.Close()
return nil, err
}
return &table{sql: sql, stmt: stmt}, nil
}
func (t *table) Close() error {
return t.stmt.Close()
}
func (t *table) BestIndex(idx *sqlite3.IndexInfo) error {
idx.EstimatedCost = 1000
var argvIndex = 1
var needIndex bool
var listIndex []int
outputs := t.stmt.ColumnCount()
for i, cst := range idx.Constraint {
// Skip if this is a constraint on one of our output columns.
if cst.Column < outputs {
continue
}
// A given query plan is only usable if all provided input columns
// are usable and have equal constraints only.
if !cst.Usable || cst.Op != sqlite3.INDEX_CONSTRAINT_EQ {
return sqlite3.CONSTRAINT
}
// The non-zero argvIdx values must be contiguous.
// If they're not, build a list and serialize it through IdxStr.
nextIndex := cst.Column - outputs + 1
idx.ConstraintUsage[i] = sqlite3.IndexConstraintUsage{
ArgvIndex: argvIndex,
Omit: true,
}
if nextIndex != argvIndex {
needIndex = true
}
listIndex = append(listIndex, nextIndex)
argvIndex++
}
if needIndex {
buf, err := json.Marshal(listIndex)
if err != nil {
return err
}
idx.IdxStr = unsafe.String(&buf[0], len(buf))
}
return nil
}
func (t *table) Open() (sqlite3.VTabCursor, error) {
stmt := t.stmt
if !t.inuse {
t.inuse = true
} else {
var err error
stmt, _, err = t.stmt.Conn().Prepare(t.sql)
if err != nil {
return nil, err
}
}
return &cursor{table: t, stmt: stmt}, nil
}
func (t *table) Rename(new string) error {
return nil
}
type cursor struct {
table *table
stmt *sqlite3.Stmt
arg []sqlite3.Value
rowID int64
}
func (c *cursor) Close() error {
if c.stmt == c.table.stmt {
c.table.inuse = false
c.stmt.ClearBindings()
return c.stmt.Reset()
}
return c.stmt.Close()
}
func (c *cursor) Filter(idxNum int, idxStr string, arg ...sqlite3.Value) error {
c.arg = arg
c.rowID = 0
c.stmt.ClearBindings()
if err := c.stmt.Reset(); err != nil {
return err
}
var list []int
if idxStr != "" {
buf := unsafe.Slice(unsafe.StringData(idxStr), len(idxStr))
err := json.Unmarshal(buf, &list)
if err != nil {
return err
}
}
for i, arg := range arg {
param := i + 1
if list != nil {
param = list[i]
}
err := c.stmt.BindValue(param, arg)
if err != nil {
return err
}
}
return c.Next()
}
func (c *cursor) Next() error {
if c.stmt.Step() {
c.rowID++
}
return c.stmt.Err()
}
func (c *cursor) EOF() bool {
return !c.stmt.Busy()
}
func (c *cursor) RowID() (int64, error) {
return c.rowID, nil
}
func (c *cursor) Column(ctx *sqlite3.Context, col int) error {
switch outputs := c.stmt.ColumnCount(); {
case col < outputs:
ctx.ResultValue(c.stmt.ColumnValue(col))
case col-outputs < len(c.arg):
ctx.ResultValue(c.arg[col-outputs])
}
return nil
}

145
ext/statement/stmt_test.go Normal file
View File

@@ -0,0 +1,145 @@
package statement_test
import (
"fmt"
"log"
"testing"
"github.com/ncruces/go-sqlite3"
_ "github.com/ncruces/go-sqlite3/embed"
"github.com/ncruces/go-sqlite3/ext/statement"
)
func Example() {
db, err := sqlite3.Open(":memory:")
if err != nil {
log.Fatal(err)
}
defer db.Close()
statement.Register(db)
err = db.Exec(`
CREATE VIRTUAL TABLE split_date USING statement((
SELECT
strftime('%Y', :date) AS year,
strftime('%m', :date) AS month,
strftime('%d', :date) AS day
))`)
if err != nil {
log.Fatal(err)
}
stmt, _, err := db.Prepare(`SELECT * FROM split_date('2022-02-22')`)
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
if stmt.Step() {
fmt.Printf("Twosday was %d-%d-%d", stmt.ColumnInt(0), stmt.ColumnInt(1), stmt.ColumnInt(2))
}
if err := stmt.Reset(); err != nil {
log.Fatal(err)
}
// Output:
// Twosday was 2022-2-22
}
func TestRegister(t *testing.T) {
t.Parallel()
db, err := sqlite3.Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
statement.Register(db)
err = db.Exec(`
CREATE VIRTUAL TABLE arguments USING statement((SELECT ? AS a, ? AS b, ? AS c))
`)
if err != nil {
t.Fatal(err)
}
err = db.Exec(`
SELECT * from arguments WHERE [2] = 'y' AND [3] = 'z'
`)
if err != nil {
t.Fatal(err)
}
err = db.Exec(`
CREATE VIRTUAL TABLE hypot USING statement((SELECT sqrt(:x * :x + :y * :y) AS hypotenuse))
`)
if err != nil {
t.Fatal(err)
}
stmt, _, err := db.Prepare(`
SELECT x, y, * FROM hypot WHERE x = 3 AND y = 4
`)
if err != nil {
t.Fatal(err)
}
defer stmt.Close()
if stmt.Step() {
x := stmt.ColumnInt(0)
y := stmt.ColumnInt(1)
hypot := stmt.ColumnInt(2)
if x != 3 || y != 4 || hypot != 5 {
t.Errorf("hypot(%d, %d) = %d", x, y, hypot)
}
}
}
func TestRegister_errors(t *testing.T) {
t.Parallel()
db, err := sqlite3.Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
statement.Register(db)
err = db.Exec(`CREATE VIRTUAL TABLE split_date USING statement()`)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
err = db.Exec(`CREATE VIRTUAL TABLE split_date USING statement(SELECT 1, SELECT 2)`)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
err = db.Exec(`CREATE VIRTUAL TABLE split_date USING statement((SELECT 1, SELECT 2))`)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
err = db.Exec(`CREATE VIRTUAL TABLE split_date USING statement((SELECT 1; SELECT 2))`)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
err = db.Exec(`CREATE VIRTUAL TABLE split_date USING statement((CREATE TABLE x(val)))`)
if err == nil {
t.Fatal("want error")
} else {
t.Log(err)
}
}

109
ext/stats/stats.go Normal file
View File

@@ -0,0 +1,109 @@
// Package stats provides aggregate functions for statistics.
//
// Functions:
// - stddev_pop: population standard deviation
// - stddev_samp: sample standard deviation
// - var_pop: population variance
// - var_samp: sample variance
// - covar_pop: population covariance
// - covar_samp: sample covariance
// - corr: correlation coefficient
//
// See: [ANSI SQL Aggregate Functions]
//
// [ANSI SQL Aggregate Functions]: https://www.oreilly.com/library/view/sql-in-a/9780596155322/ch04s02.html
package stats
import "github.com/ncruces/go-sqlite3"
// Register registers statistics functions.
func Register(db *sqlite3.Conn) {
flags := sqlite3.DETERMINISTIC | sqlite3.INNOCUOUS
db.CreateWindowFunction("var_pop", 1, flags, newVariance(var_pop))
db.CreateWindowFunction("var_samp", 1, flags, newVariance(var_samp))
db.CreateWindowFunction("stddev_pop", 1, flags, newVariance(stddev_pop))
db.CreateWindowFunction("stddev_samp", 1, flags, newVariance(stddev_samp))
db.CreateWindowFunction("covar_pop", 2, flags, newCovariance(var_pop))
db.CreateWindowFunction("covar_samp", 2, flags, newCovariance(var_samp))
db.CreateWindowFunction("corr", 2, flags, newCovariance(corr))
}
const (
var_pop = iota
var_samp
stddev_pop
stddev_samp
corr
)
func newVariance(kind int) func() sqlite3.AggregateFunction {
return func() sqlite3.AggregateFunction { return &variance{kind: kind} }
}
type variance struct {
kind int
welford
}
func (fn *variance) Value(ctx sqlite3.Context) {
var r float64
switch fn.kind {
case var_pop:
r = fn.var_pop()
case var_samp:
r = fn.var_samp()
case stddev_pop:
r = fn.stddev_pop()
case stddev_samp:
r = fn.stddev_samp()
}
ctx.ResultFloat(r)
}
func (fn *variance) Step(ctx sqlite3.Context, arg ...sqlite3.Value) {
if a := arg[0]; a.Type() != sqlite3.NULL {
fn.enqueue(a.Float())
}
}
func (fn *variance) Inverse(ctx sqlite3.Context, arg ...sqlite3.Value) {
if a := arg[0]; a.Type() != sqlite3.NULL {
fn.dequeue(a.Float())
}
}
func newCovariance(kind int) func() sqlite3.AggregateFunction {
return func() sqlite3.AggregateFunction { return &covariance{kind: kind} }
}
type covariance struct {
kind int
welford2
}
func (fn *covariance) Value(ctx sqlite3.Context) {
var r float64
switch fn.kind {
case var_pop:
r = fn.covar_pop()
case var_samp:
r = fn.covar_samp()
case corr:
r = fn.correlation()
}
ctx.ResultFloat(r)
}
func (fn *covariance) Step(ctx sqlite3.Context, arg ...sqlite3.Value) {
a, b := arg[0], arg[1]
if a.Type() != sqlite3.NULL && b.Type() != sqlite3.NULL {
fn.enqueue(a.Float(), b.Float())
}
}
func (fn *covariance) Inverse(ctx sqlite3.Context, arg ...sqlite3.Value) {
a, b := arg[0], arg[1]
if a.Type() != sqlite3.NULL && b.Type() != sqlite3.NULL {
fn.dequeue(a.Float(), b.Float())
}
}

140
ext/stats/stats_test.go Normal file
View File

@@ -0,0 +1,140 @@
package stats
import (
"math"
"testing"
"github.com/ncruces/go-sqlite3"
_ "github.com/ncruces/go-sqlite3/embed"
)
func TestRegister_variance(t *testing.T) {
t.Parallel()
db, err := sqlite3.Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
Register(db)
err = db.Exec(`CREATE TABLE IF NOT EXISTS data (x)`)
if err != nil {
t.Fatal(err)
}
err = db.Exec(`INSERT INTO data (x) VALUES (4), (7.0), ('13'), (NULL), (16)`)
if err != nil {
t.Fatal(err)
}
stmt, _, err := db.Prepare(`
SELECT
sum(x), avg(x),
var_samp(x), var_pop(x),
stddev_samp(x), stddev_pop(x)
FROM data`)
if err != nil {
t.Fatal(err)
}
defer stmt.Close()
if stmt.Step() {
if got := stmt.ColumnFloat(0); got != 40 {
t.Errorf("got %v, want 40", got)
}
if got := stmt.ColumnFloat(1); got != 10 {
t.Errorf("got %v, want 10", got)
}
if got := stmt.ColumnFloat(2); got != 30 {
t.Errorf("got %v, want 30", got)
}
if got := stmt.ColumnFloat(3); got != 22.5 {
t.Errorf("got %v, want 22.5", got)
}
if got := stmt.ColumnFloat(4); got != math.Sqrt(30) {
t.Errorf("got %v, want √30", got)
}
if got := stmt.ColumnFloat(5); got != math.Sqrt(22.5) {
t.Errorf("got %v, want √22.5", got)
}
}
{
stmt, _, err := db.Prepare(`SELECT var_samp(x) OVER (ROWS 1 PRECEDING) FROM data`)
if err != nil {
t.Fatal(err)
}
defer stmt.Close()
want := [...]float64{0, 4.5, 18, 0, 0}
for i := 0; stmt.Step(); i++ {
if got := stmt.ColumnFloat(0); got != want[i] {
t.Errorf("got %v, want %v", got, want[i])
}
if got := stmt.ColumnType(0); (got == sqlite3.FLOAT) != (want[i] != 0) {
t.Errorf("got %v, want %v", got, want[i])
}
}
}
}
func TestRegister_covariance(t *testing.T) {
t.Parallel()
db, err := sqlite3.Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
Register(db)
err = db.Exec(`CREATE TABLE IF NOT EXISTS data (x, y)`)
if err != nil {
t.Fatal(err)
}
err = db.Exec(`INSERT INTO data (x, y) VALUES (3, 70), (5, 80), (2, 60), (7, 90), (4, 75)`)
if err != nil {
t.Fatal(err)
}
stmt, _, err := db.Prepare(`SELECT
corr(x, y), covar_samp(x, y), covar_pop(x, y) FROM data`)
if err != nil {
t.Fatal(err)
}
defer stmt.Close()
if stmt.Step() {
if got := stmt.ColumnFloat(0); got != 0.9881049293224639 {
t.Errorf("got %v, want 0.9881049293224639", got)
}
if got := stmt.ColumnFloat(1); got != 21.25 {
t.Errorf("got %v, want 21.25", got)
}
if got := stmt.ColumnFloat(2); got != 17 {
t.Errorf("got %v, want 17", got)
}
}
{
stmt, _, err := db.Prepare(`SELECT covar_samp(x, y) OVER (ROWS 1 PRECEDING) FROM data`)
if err != nil {
t.Fatal(err)
}
defer stmt.Close()
want := [...]float64{0, 10, 30, 75, 22.5}
for i := 0; stmt.Step(); i++ {
if got := stmt.ColumnFloat(0); got != want[i] {
t.Errorf("got %v, want %v", got, want[i])
}
if got := stmt.ColumnType(0); (got == sqlite3.FLOAT) != (want[i] != 0) {
t.Errorf("got %v, want %v", got, want[i])
}
}
}
}

109
ext/stats/welford.go Normal file
View File

@@ -0,0 +1,109 @@
package stats
import "math"
// Welford's algorithm with Kahan summation:
// https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm
// https://en.wikipedia.org/wiki/Kahan_summation_algorithm
type welford struct {
m1, m2 kahan
n uint64
}
func (w welford) average() float64 {
return w.m1.hi
}
func (w welford) var_pop() float64 {
return w.m2.hi / float64(w.n)
}
func (w welford) var_samp() float64 {
return w.m2.hi / float64(w.n-1) // Bessel's correction
}
func (w welford) stddev_pop() float64 {
return math.Sqrt(w.var_pop())
}
func (w welford) stddev_samp() float64 {
return math.Sqrt(w.var_samp())
}
func (w *welford) enqueue(x float64) {
w.n++
d1 := x - w.m1.hi - w.m1.lo
w.m1.add(d1 / float64(w.n))
d2 := x - w.m1.hi - w.m1.lo
w.m2.add(d1 * d2)
}
func (w *welford) dequeue(x float64) {
w.n--
d1 := x - w.m1.hi - w.m1.lo
w.m1.sub(d1 / float64(w.n))
d2 := x - w.m1.hi - w.m1.lo
w.m2.sub(d1 * d2)
}
type welford2 struct {
m1x, m2x kahan
m1y, m2y kahan
cov kahan
n uint64
}
func (w welford2) covar_pop() float64 {
return w.cov.hi / float64(w.n)
}
func (w welford2) covar_samp() float64 {
return w.cov.hi / float64(w.n-1) // Bessel's correction
}
func (w welford2) correlation() float64 {
return w.cov.hi / math.Sqrt(w.m2x.hi*w.m2y.hi)
}
func (w *welford2) enqueue(x, y float64) {
w.n++
d1x := x - w.m1x.hi - w.m1x.lo
d1y := y - w.m1y.hi - w.m1y.lo
w.m1x.add(d1x / float64(w.n))
w.m1y.add(d1y / float64(w.n))
d2x := x - w.m1x.hi - w.m1x.lo
d2y := y - w.m1y.hi - w.m1y.lo
w.m2x.add(d1x * d2x)
w.m2y.add(d1y * d2y)
w.cov.add(d1x * d2y)
}
func (w *welford2) dequeue(x, y float64) {
w.n--
d1x := x - w.m1x.hi - w.m1x.lo
d1y := y - w.m1y.hi - w.m1y.lo
w.m1x.sub(d1x / float64(w.n))
w.m1y.sub(d1y / float64(w.n))
d2x := x - w.m1x.hi - w.m1x.lo
d2y := y - w.m1y.hi - w.m1y.lo
w.m2x.sub(d1x * d2x)
w.m2y.sub(d1y * d2y)
w.cov.sub(d1x * d2y)
}
type kahan struct{ hi, lo float64 }
func (k *kahan) add(x float64) {
y := k.lo + x
t := k.hi + y
k.lo = y - (t - k.hi)
k.hi = t
}
func (k *kahan) sub(x float64) {
y := k.lo - x
t := k.hi + y
k.lo = y - (t - k.hi)
k.hi = t
}

81
ext/stats/welford_test.go Normal file
View File

@@ -0,0 +1,81 @@
package stats
import (
"math"
"testing"
)
func Test_welford(t *testing.T) {
t.Parallel()
var s1, s2 welford
s1.enqueue(4)
s1.enqueue(7)
s1.enqueue(13)
s1.enqueue(16)
if got := s1.average(); got != 10 {
t.Errorf("got %v, want 10", got)
}
if got := s1.var_samp(); got != 30 {
t.Errorf("got %v, want 30", got)
}
if got := s1.var_pop(); got != 22.5 {
t.Errorf("got %v, want 22.5", got)
}
if got := s1.stddev_samp(); got != math.Sqrt(30) {
t.Errorf("got %v, want √30", got)
}
if got := s1.stddev_pop(); got != math.Sqrt(22.5) {
t.Errorf("got %v, want √22.5", got)
}
s1.dequeue(4)
s2.enqueue(7)
s2.enqueue(13)
s2.enqueue(16)
if s1.var_pop() != s2.var_pop() {
t.Errorf("got %v, want %v", s1, s2)
}
}
func Test_covar(t *testing.T) {
t.Parallel()
var c1, c2 welford2
c1.enqueue(3, 70)
c1.enqueue(5, 80)
c1.enqueue(2, 60)
c1.enqueue(7, 90)
c1.enqueue(4, 75)
if got := c1.covar_samp(); got != 21.25 {
t.Errorf("got %v, want 21.25", got)
}
if got := c1.covar_pop(); got != 17 {
t.Errorf("got %v, want 17", got)
}
c1.dequeue(3, 70)
c2.enqueue(5, 80)
c2.enqueue(2, 60)
c2.enqueue(7, 90)
c2.enqueue(4, 75)
if c1.covar_pop() != c2.covar_pop() {
t.Errorf("got %v, want %v", c1.covar_pop(), c2.covar_pop())
}
}
func Test_correlation(t *testing.T) {
t.Parallel()
var c welford2
c.enqueue(1, 3)
c.enqueue(2, 2)
c.enqueue(3, 1)
if got := c.correlation(); got != -1 {
t.Errorf("got %v, want -1", got)
}
}

181
ext/unicode/unicode.go Normal file
View File

@@ -0,0 +1,181 @@
// Package unicode provides an alternative to the SQLite ICU extension.
//
// Like the [ICU extension], it provides Unicode aware:
// - upper() and lower() functions,
// - LIKE and REGEXP operators,
// - collation sequences.
//
// The implementation is not 100% compatible with the [ICU extension]:
// - upper() and lower() use [strings.ToUpper], [strings.ToLower] and [cases];
// - the LIKE operator follows [strings.EqualFold] rules;
// - the REGEXP operator uses Go [regex/syntax];
// - collation sequences use [collate].
//
// Expect subtle differences (e.g.) in the handling of Turkish case folding.
//
// [ICU extension]: https://sqlite.org/src/dir/ext/icu
package unicode
import (
"bytes"
"regexp"
"strings"
"unicode/utf8"
"github.com/ncruces/go-sqlite3"
"github.com/ncruces/go-sqlite3/internal/util"
"golang.org/x/text/cases"
"golang.org/x/text/collate"
"golang.org/x/text/language"
)
// Register registers Unicode aware functions for a database connection.
func Register(db *sqlite3.Conn) {
flags := sqlite3.DETERMINISTIC | sqlite3.INNOCUOUS
db.CreateFunction("like", 2, flags, like)
db.CreateFunction("like", 3, flags, like)
db.CreateFunction("upper", 1, flags, upper)
db.CreateFunction("upper", 2, flags, upper)
db.CreateFunction("lower", 1, flags, lower)
db.CreateFunction("lower", 2, flags, lower)
db.CreateFunction("regexp", 2, flags, regex)
db.CreateFunction("icu_load_collation", 2, sqlite3.DIRECTONLY,
func(ctx sqlite3.Context, arg ...sqlite3.Value) {
name := arg[1].Text()
if name == "" {
return
}
err := RegisterCollation(db, arg[0].Text(), name)
if err != nil {
ctx.ResultError(err)
return
}
})
}
// RegisterCollation registers a Unicode collation sequence for a database connection.
func RegisterCollation(db *sqlite3.Conn, locale, name string) error {
tag, err := language.Parse(locale)
if err != nil {
return err
}
return db.CreateCollation(name, collate.New(tag).Compare)
}
func upper(ctx sqlite3.Context, arg ...sqlite3.Value) {
if len(arg) == 1 {
ctx.ResultRawText(bytes.ToUpper(arg[0].RawText()))
return
}
cs, ok := ctx.GetAuxData(1).(cases.Caser)
if !ok {
t, err := language.Parse(arg[1].Text())
if err != nil {
ctx.ResultError(err)
return
}
c := cases.Upper(t)
ctx.SetAuxData(1, c)
cs = c
}
ctx.ResultRawText(cs.Bytes(arg[0].RawText()))
}
func lower(ctx sqlite3.Context, arg ...sqlite3.Value) {
if len(arg) == 1 {
ctx.ResultRawText(bytes.ToLower(arg[0].RawText()))
return
}
cs, ok := ctx.GetAuxData(1).(cases.Caser)
if !ok {
t, err := language.Parse(arg[1].Text())
if err != nil {
ctx.ResultError(err)
return
}
c := cases.Lower(t)
ctx.SetAuxData(1, c)
cs = c
}
ctx.ResultRawText(cs.Bytes(arg[0].RawText()))
}
func regex(ctx sqlite3.Context, arg ...sqlite3.Value) {
re, ok := ctx.GetAuxData(0).(*regexp.Regexp)
if !ok {
r, err := regexp.Compile(arg[0].Text())
if err != nil {
ctx.ResultError(err)
return
}
re = r
ctx.SetAuxData(0, re)
}
ctx.ResultBool(re.Match(arg[1].RawText()))
}
func like(ctx sqlite3.Context, arg ...sqlite3.Value) {
escape := rune(-1)
if len(arg) == 3 {
var size int
b := arg[2].RawText()
escape, size = utf8.DecodeRune(b)
if size != len(b) {
ctx.ResultError(util.ErrorString("ESCAPE expression must be a single character"))
return
}
}
type likeData struct {
*regexp.Regexp
escape rune
}
re, ok := ctx.GetAuxData(0).(likeData)
if !ok || re.escape != escape {
re = likeData{
regexp.MustCompile(like2regex(arg[0].Text(), escape)),
escape,
}
ctx.SetAuxData(0, re)
}
ctx.ResultBool(re.Match(arg[1].RawText()))
}
func like2regex(pattern string, escape rune) string {
var re strings.Builder
start := 0
literal := false
re.Grow(len(pattern) + 10)
re.WriteString(`(?is)\A`) // case insensitive, . matches any character
for i, r := range pattern {
if start < 0 {
start = i
}
if literal {
literal = false
continue
}
var symbol string
switch r {
case '_':
symbol = `.`
case '%':
symbol = `.*`
case escape:
literal = true
default:
continue
}
re.WriteString(regexp.QuoteMeta(pattern[start:i]))
re.WriteString(symbol)
start = -1
}
if start >= 0 {
re.WriteString(regexp.QuoteMeta(pattern[start:]))
}
re.WriteString(`\z`)
return re.String()
}

217
ext/unicode/unicode_test.go Normal file
View File

@@ -0,0 +1,217 @@
package unicode
import (
"errors"
"reflect"
"testing"
"github.com/ncruces/go-sqlite3"
_ "github.com/ncruces/go-sqlite3/embed"
)
func TestRegister(t *testing.T) {
t.Parallel()
db, err := sqlite3.Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
exec := func(fn string) string {
stmt, _, err := db.Prepare(`SELECT ` + fn)
if err != nil {
t.Fatal(err)
}
defer stmt.Close()
if stmt.Step() {
return stmt.ColumnText(0)
}
t.Fatal(stmt.Err())
return ""
}
Register(db)
tests := []struct {
test string
want string
}{
{`upper('hello')`, "HELLO"},
{`lower('HELLO')`, "hello"},
{`upper('привет')`, "ПРИВЕТ"},
{`lower('ПРИВЕТ')`, "привет"},
{`upper('istanbul')`, "ISTANBUL"},
{`upper('istanbul', 'tr-TR')`, "İSTANBUL"},
{`lower('Dünyanın İlk Borsası', 'tr-TR')`, "dünyanın ilk borsası"},
{`upper('Dünyanın İlk Borsası', 'tr-TR')`, "DÜNYANIN İLK BORSASI"},
{`'Hello' REGEXP 'ell'`, "1"},
{`'Hello' REGEXP 'el.'`, "1"},
{`'Hello' LIKE 'hel_'`, "0"},
{`'Hello' LIKE 'hel%'`, "1"},
{`'Hello' LIKE 'h_llo'`, "1"},
{`'Hello' LIKE 'hello'`, "1"},
{`'Привет' LIKE 'ПРИВЕТ'`, "1"},
{`'100%' LIKE '100|%' ESCAPE '|'`, "1"},
}
for _, tt := range tests {
t.Run(tt.test, func(t *testing.T) {
if got := exec(tt.test); got != tt.want {
t.Errorf("exec(%q) = %q, want %q", tt.test, got, tt.want)
}
})
}
err = db.Close()
if err != nil {
t.Fatal(err)
}
}
func TestRegister_collation(t *testing.T) {
t.Parallel()
db, err := sqlite3.Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
Register(db)
err = db.Exec(`CREATE TABLE IF NOT EXISTS words (word VARCHAR(10))`)
if err != nil {
t.Fatal(err)
}
err = db.Exec(`INSERT INTO words (word) VALUES ('côte'), ('cote'), ('coter'), ('coté'), ('cotée'), ('côté')`)
if err != nil {
t.Fatal(err)
}
err = db.Exec(`SELECT icu_load_collation('fr_FR', 'french')`)
if err != nil {
t.Fatal(err)
}
stmt, _, err := db.Prepare(`SELECT word FROM words ORDER BY word COLLATE french`)
if err != nil {
t.Fatal(err)
}
defer stmt.Close()
got, want := []string{}, []string{"cote", "coté", "côte", "côté", "cotée", "coter"}
for stmt.Step() {
got = append(got, stmt.ColumnText(0))
}
if err := stmt.Err(); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(got, want) {
t.Error("not equal")
}
err = stmt.Close()
if err != nil {
t.Fatal(err)
}
err = db.Close()
if err != nil {
t.Fatal(err)
}
}
func TestRegister_error(t *testing.T) {
t.Parallel()
db, err := sqlite3.Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
Register(db)
err = db.Exec(`SELECT upper('hello', 'enUS')`)
if err == nil {
t.Error("want error")
}
if !errors.Is(err, sqlite3.ERROR) {
t.Errorf("got %v, want sqlite3.ERROR", err)
}
err = db.Exec(`SELECT lower('hello', 'enUS')`)
if err == nil {
t.Error("want error")
}
if !errors.Is(err, sqlite3.ERROR) {
t.Errorf("got %v, want sqlite3.ERROR", err)
}
err = db.Exec(`SELECT 'hello' REGEXP '\'`)
if err == nil {
t.Error("want error")
}
if !errors.Is(err, sqlite3.ERROR) {
t.Errorf("got %v, want sqlite3.ERROR", err)
}
err = db.Exec(`SELECT 'hello' LIKE 'HELLO' ESCAPE '\\'`)
if err == nil {
t.Error("want error")
}
if !errors.Is(err, sqlite3.ERROR) {
t.Errorf("got %v, want sqlite3.ERROR", err)
}
err = db.Exec(`SELECT icu_load_collation('enUS', 'error')`)
if err == nil {
t.Error("want error")
}
if !errors.Is(err, sqlite3.ERROR) {
t.Errorf("got %v, want sqlite3.ERROR", err)
}
err = db.Exec(`SELECT icu_load_collation('enUS', '')`)
if err != nil {
t.Error(err)
}
err = db.Close()
if err != nil {
t.Fatal(err)
}
}
func Test_like2regex(t *testing.T) {
t.Parallel()
const prefix = `(?is)\A`
const sufix = `\z`
tests := []struct {
pattern string
escape rune
want string
}{
{`a`, -1, `a`},
{`a.`, -1, `a\.`},
{`a%`, -1, `a.*`},
{`a\`, -1, `a\\`},
{`a_b`, -1, `a.b`},
{`a|b`, '|', `ab`},
{`a|_`, '|', `a_`},
}
for _, tt := range tests {
t.Run(tt.pattern, func(t *testing.T) {
want := prefix + tt.want + sufix
if got := like2regex(tt.pattern, tt.escape); got != want {
t.Errorf("like2regex() = %q, want %q", got, want)
}
})
}
}

175
func.go Normal file
View File

@@ -0,0 +1,175 @@
package sqlite3
import (
"context"
"github.com/ncruces/go-sqlite3/internal/util"
"github.com/tetratelabs/wazero/api"
)
// AnyCollationNeeded registers a fake collating function
// for any unknown collating sequence.
// The fake collating function works like BINARY.
//
// This can be used to load schemas that contain
// one or more unknown collating sequences.
func (c *Conn) AnyCollationNeeded() {
c.call("sqlite3_anycollseq_init", uint64(c.handle), 0, 0)
}
// CreateCollation defines a new collating sequence.
//
// https://sqlite.org/c3ref/create_collation.html
func (c *Conn) CreateCollation(name string, fn func(a, b []byte) int) error {
defer c.arena.mark()()
namePtr := c.arena.string(name)
funcPtr := util.AddHandle(c.ctx, fn)
r := c.call("sqlite3_create_collation_go",
uint64(c.handle), uint64(namePtr), uint64(funcPtr))
return c.error(r)
}
// CreateFunction defines a new scalar SQL function.
//
// https://sqlite.org/c3ref/create_function.html
func (c *Conn) CreateFunction(name string, nArg int, flag FunctionFlag, fn ScalarFunction) error {
defer c.arena.mark()()
namePtr := c.arena.string(name)
funcPtr := util.AddHandle(c.ctx, fn)
r := c.call("sqlite3_create_function_go",
uint64(c.handle), uint64(namePtr), uint64(nArg),
uint64(flag), uint64(funcPtr))
return c.error(r)
}
// ScalarFunction is the type of a scalar SQL function.
type ScalarFunction func(ctx Context, arg ...Value)
// CreateWindowFunction defines a new aggregate or aggregate window SQL function.
// If fn returns a [WindowFunction], then an aggregate window function is created.
// If fn returns an [io.Closer], it will be called to free resources.
//
// https://sqlite.org/c3ref/create_function.html
func (c *Conn) CreateWindowFunction(name string, nArg int, flag FunctionFlag, fn func() AggregateFunction) error {
defer c.arena.mark()()
call := "sqlite3_create_aggregate_function_go"
namePtr := c.arena.string(name)
funcPtr := util.AddHandle(c.ctx, fn)
if _, ok := fn().(WindowFunction); ok {
call = "sqlite3_create_window_function_go"
}
r := c.call(call,
uint64(c.handle), uint64(namePtr), uint64(nArg),
uint64(flag), uint64(funcPtr))
return c.error(r)
}
// AggregateFunction is the interface an aggregate function should implement.
//
// https://sqlite.org/appfunc.html
type AggregateFunction interface {
// Step is invoked to add a row to the current window.
// The function arguments, if any, corresponding to the row being added are passed to Step.
Step(ctx Context, arg ...Value)
// Value is invoked to return the current (or final) value of the aggregate.
Value(ctx Context)
}
// WindowFunction is the interface an aggregate window function should implement.
//
// https://sqlite.org/windowfunctions.html
type WindowFunction interface {
AggregateFunction
// Inverse is invoked to remove the oldest presently aggregated result of Step from the current window.
// The function arguments, if any, are those passed to Step for the row being removed.
Inverse(ctx Context, arg ...Value)
}
func destroyCallback(ctx context.Context, mod api.Module, pApp uint32) {
util.DelHandle(ctx, pApp)
}
func compareCallback(ctx context.Context, mod api.Module, pApp, nKey1, pKey1, nKey2, pKey2 uint32) uint32 {
fn := util.GetHandle(ctx, pApp).(func(a, b []byte) int)
return uint32(fn(util.View(mod, pKey1, uint64(nKey1)), util.View(mod, pKey2, uint64(nKey2))))
}
func funcCallback(ctx context.Context, mod api.Module, pCtx, nArg, pArg uint32) {
db := ctx.Value(connKey{}).(*Conn)
fn := userDataHandle(db, pCtx).(ScalarFunction)
fn(Context{db, pCtx}, callbackArgs(db, nArg, pArg)...)
}
func stepCallback(ctx context.Context, mod api.Module, pCtx, nArg, pArg uint32) {
db := ctx.Value(connKey{}).(*Conn)
fn := aggregateCtxHandle(db, pCtx, nil)
fn.Step(Context{db, pCtx}, callbackArgs(db, nArg, pArg)...)
}
func finalCallback(ctx context.Context, mod api.Module, pCtx uint32) {
var handle uint32
db := ctx.Value(connKey{}).(*Conn)
fn := aggregateCtxHandle(db, pCtx, &handle)
fn.Value(Context{db, pCtx})
if err := util.DelHandle(ctx, handle); err != nil {
Context{db, pCtx}.ResultError(err)
}
}
func valueCallback(ctx context.Context, mod api.Module, pCtx uint32) {
db := ctx.Value(connKey{}).(*Conn)
fn := aggregateCtxHandle(db, pCtx, nil)
fn.Value(Context{db, pCtx})
}
func inverseCallback(ctx context.Context, mod api.Module, pCtx, nArg, pArg uint32) {
db := ctx.Value(connKey{}).(*Conn)
fn := aggregateCtxHandle(db, pCtx, nil).(WindowFunction)
fn.Inverse(Context{db, pCtx}, callbackArgs(db, nArg, pArg)...)
}
func userDataHandle(db *Conn, pCtx uint32) any {
pApp := uint32(db.call("sqlite3_user_data", uint64(pCtx)))
return util.GetHandle(db.ctx, pApp)
}
func aggregateCtxHandle(db *Conn, pCtx uint32, close *uint32) AggregateFunction {
// On close, we're getting rid of the aggregate.
// Don't allocate space to store it.
var size uint64
if close == nil {
size = ptrlen
}
ptr := uint32(db.call("sqlite3_aggregate_context", uint64(pCtx), size))
// If we already have an aggregate, return it.
if ptr != 0 {
if handle := util.ReadUint32(db.mod, ptr); handle != 0 {
fn := util.GetHandle(db.ctx, handle).(AggregateFunction)
if close != nil {
*close = handle
}
return fn
}
}
// Create a new aggregate, and store it if needed.
fn := userDataHandle(db, pCtx).(func() AggregateFunction)()
if ptr != 0 {
util.WriteUint32(db.mod, ptr, util.AddHandle(db.ctx, fn))
}
return fn
}
func callbackArgs(db *Conn, nArg, pArg uint32) []Value {
args := make([]Value, nArg)
for i := range args {
args[i] = Value{
sqlite: db.sqlite,
handle: util.ReadUint32(db.mod, pArg+ptrlen*uint32(i)),
}
}
return args
}

154
func_test.go Normal file
View File

@@ -0,0 +1,154 @@
package sqlite3_test
import (
"bytes"
"fmt"
"log"
"regexp"
"golang.org/x/text/collate"
"golang.org/x/text/language"
"github.com/ncruces/go-sqlite3"
_ "github.com/ncruces/go-sqlite3/embed"
)
func ExampleConn_CreateCollation() {
db, err := sqlite3.Open(":memory:")
if err != nil {
log.Fatal(err)
}
defer db.Close()
err = db.Exec(`CREATE TABLE IF NOT EXISTS words (word VARCHAR(10))`)
if err != nil {
log.Fatal(err)
}
err = db.Exec(`INSERT INTO words (word) VALUES ('côte'), ('cote'), ('coter'), ('coté'), ('cotée'), ('côté')`)
if err != nil {
log.Fatal(err)
}
err = db.CreateCollation("french", collate.New(language.French).Compare)
if err != nil {
log.Fatal(err)
}
stmt, _, err := db.Prepare(`SELECT word FROM words ORDER BY word COLLATE french`)
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
for stmt.Step() {
fmt.Println(stmt.ColumnText(0))
}
if err := stmt.Err(); err != nil {
log.Fatal(err)
}
// Output:
// cote
// coté
// côte
// côté
// cotée
// coter
}
func ExampleConn_CreateFunction() {
db, err := sqlite3.Open(":memory:")
if err != nil {
log.Fatal(err)
}
defer db.Close()
err = db.Exec(`CREATE TABLE IF NOT EXISTS words (word VARCHAR(10))`)
if err != nil {
log.Fatal(err)
}
err = db.Exec(`INSERT INTO words (word) VALUES ('côte'), ('cote'), ('coter'), ('coté'), ('cotée'), ('côté')`)
if err != nil {
log.Fatal(err)
}
err = db.CreateFunction("upper", 1, sqlite3.DETERMINISTIC|sqlite3.INNOCUOUS, func(ctx sqlite3.Context, arg ...sqlite3.Value) {
ctx.ResultRawText(bytes.ToUpper(arg[0].RawText()))
})
if err != nil {
log.Fatal(err)
}
stmt, _, err := db.Prepare(`SELECT upper(word) FROM words`)
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
for stmt.Step() {
fmt.Println(stmt.ColumnText(0))
}
if err := stmt.Err(); err != nil {
log.Fatal(err)
}
// Unordered output:
// COTE
// COTÉ
// CÔTE
// CÔTÉ
// COTÉE
// COTER
}
func ExampleContext_SetAuxData() {
db, err := sqlite3.Open(":memory:")
if err != nil {
log.Fatal(err)
}
defer db.Close()
err = db.Exec(`CREATE TABLE IF NOT EXISTS words (word VARCHAR(10))`)
if err != nil {
log.Fatal(err)
}
err = db.Exec(`INSERT INTO words (word) VALUES ('côte'), ('cote'), ('coter'), ('coté'), ('cotée'), ('côté')`)
if err != nil {
log.Fatal(err)
}
err = db.CreateFunction("regexp", 2, sqlite3.DETERMINISTIC|sqlite3.INNOCUOUS, func(ctx sqlite3.Context, arg ...sqlite3.Value) {
re, ok := ctx.GetAuxData(0).(*regexp.Regexp)
if !ok {
r, err := regexp.Compile(arg[0].Text())
if err != nil {
ctx.ResultError(err)
return
}
ctx.SetAuxData(0, r)
re = r
}
ctx.ResultBool(re.Match(arg[1].RawText()))
})
if err != nil {
log.Fatal(err)
}
stmt, _, err := db.Prepare(`SELECT word FROM words WHERE word REGEXP '^\p{L}+e$'`)
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
for stmt.Step() {
fmt.Println(stmt.ColumnText(0))
}
if err := stmt.Err(); err != nil {
log.Fatal(err)
}
// Unordered output:
// cote
// côte
// cotée
}

87
func_win_test.go Normal file
View File

@@ -0,0 +1,87 @@
package sqlite3_test
import (
"fmt"
"log"
"unicode"
"github.com/ncruces/go-sqlite3"
_ "github.com/ncruces/go-sqlite3/embed"
)
func ExampleConn_CreateWindowFunction() {
db, err := sqlite3.Open(":memory:")
if err != nil {
log.Fatal(err)
}
defer db.Close()
err = db.Exec(`CREATE TABLE IF NOT EXISTS words (word VARCHAR(10))`)
if err != nil {
log.Fatal(err)
}
err = db.Exec(`INSERT INTO words (word) VALUES ('côte'), ('cote'), ('coter'), ('coté'), ('cotée'), ('côté')`)
if err != nil {
log.Fatal(err)
}
err = db.CreateWindowFunction("count_ascii", 1, sqlite3.DETERMINISTIC|sqlite3.INNOCUOUS, newASCIICounter)
if err != nil {
log.Fatal(err)
}
stmt, _, err := db.Prepare(`SELECT count_ascii(word) OVER (ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM words`)
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
for stmt.Step() {
fmt.Println(stmt.ColumnInt(0))
}
if err := stmt.Err(); err != nil {
log.Fatal(err)
}
// Output:
// 1
// 2
// 2
// 1
// 0
// 0
}
type countASCII struct{ result int }
func newASCIICounter() sqlite3.AggregateFunction {
return &countASCII{}
}
func (f *countASCII) Value(ctx sqlite3.Context) {
ctx.ResultInt(f.result)
}
func (f *countASCII) Step(ctx sqlite3.Context, arg ...sqlite3.Value) {
if f.isASCII(arg[0]) {
f.result++
}
}
func (f *countASCII) Inverse(ctx sqlite3.Context, arg ...sqlite3.Value) {
if f.isASCII(arg[0]) {
f.result--
}
}
func (f *countASCII) isASCII(arg sqlite3.Value) bool {
if arg.Type() != sqlite3.TEXT {
return false
}
for _, c := range arg.RawBlob() {
if c > unicode.MaxASCII {
return false
}
}
return true
}

11
go.mod
View File

@@ -1,13 +1,14 @@
module github.com/ncruces/go-sqlite3
go 1.19
go 1.21
require (
github.com/ncruces/julianday v0.1.5
github.com/ncruces/julianday v1.0.0
github.com/psanford/httpreadat v0.1.0
github.com/tetratelabs/wazero v1.2.0
golang.org/x/sync v0.2.0
golang.org/x/sys v0.8.0
github.com/tetratelabs/wazero v1.5.0
golang.org/x/sync v0.5.0
golang.org/x/sys v0.15.0
golang.org/x/text v0.14.0
)
retract v0.4.0 // tagged from the wrong branch

18
go.sum
View File

@@ -1,10 +1,12 @@
github.com/ncruces/julianday v0.1.5 h1:hDJ9ejiMp3DHsoZ5KW4c1lwfMjbARS7u/gbYcd0FBZk=
github.com/ncruces/julianday v0.1.5/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
github.com/psanford/httpreadat v0.1.0 h1:VleW1HS2zO7/4c7c7zNl33fO6oYACSagjJIyMIwZLUE=
github.com/psanford/httpreadat v0.1.0/go.mod h1:Zg7P+TlBm3bYbyHTKv/EdtSJZn3qwbPwpfZ/I9GKCRE=
github.com/tetratelabs/wazero v1.2.0 h1:I/8LMf4YkCZ3r2XaL9whhA0VMyAvF6QE+O7rco0DCeQ=
github.com/tetratelabs/wazero v1.2.0/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
github.com/tetratelabs/wazero v1.5.0 h1:Yz3fZHivfDiZFUXnWMPUoiW7s8tC1sjdBtlJn08qYa0=
github.com/tetratelabs/wazero v1.5.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=

6
go.work Normal file
View File

@@ -0,0 +1,6 @@
go 1.21
use (
.
./gormlite
)

4
go.work.sum Normal file
View File

@@ -0,0 +1,4 @@
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=

View File

@@ -1,5 +1,7 @@
# GORM SQLite Driver
[![Go Reference](https://pkg.go.dev/badge/image)](https://pkg.go.dev/github.com/ncruces/go-sqlite3/gormlite)
## Usage
```go
@@ -12,13 +14,4 @@ import (
db, err := gorm.Open(gormlite.Open("gorm.db"), &gorm.Config{})
```
Checkout [https://gorm.io](https://gorm.io) for details.
### Foreign-key constraint activation
Foreign-key constraint is disabled by default in SQLite. To activate it, use connection URL parameter:
```go
db, err := gorm.Open(gormlite.Open(
"file:gorm.db?_pragma=busy_timeout(10000)&_pragma=locking_mode(normal)&_pragma=foreign_keys(1)"),
&gorm.Config{})
```
Checkout [https://gorm.io](https://gorm.io) for details.

View File

@@ -13,7 +13,7 @@ import (
var (
sqliteSeparator = "`|\"|'|\t"
indexRegexp = regexp.MustCompile(fmt.Sprintf(`(?is)CREATE(?: UNIQUE)? INDEX [%v]?[\w\d-]+[%v]? ON (.*)$`, sqliteSeparator, sqliteSeparator))
indexRegexp = regexp.MustCompile(fmt.Sprintf(`(?is)CREATE(?: UNIQUE)? INDEX [%v]?[\w\d-]+[%v]?(?s:.*?)ON (.*)$`, sqliteSeparator, sqliteSeparator))
tableRegexp = regexp.MustCompile(fmt.Sprintf(`(?is)(CREATE TABLE [%v]?[\w\d-]+[%v]?)(?:\s*\((.*)\))?`, sqliteSeparator, sqliteSeparator))
separatorRegexp = regexp.MustCompile(fmt.Sprintf("[%v]", sqliteSeparator))
columnsRegexp = regexp.MustCompile(fmt.Sprintf(`[(,][%v]?(\w+)[%v]?`, sqliteSeparator, sqliteSeparator))
@@ -125,7 +125,7 @@ func parseDDL(strs ...string) (*ddl, error) {
ColumnTypeValue: sql.NullString{String: matches[2], Valid: true},
PrimaryKeyValue: sql.NullBool{Valid: true},
UniqueValue: sql.NullBool{Valid: true},
NullableValue: sql.NullBool{Valid: true},
NullableValue: sql.NullBool{Bool: true, Valid: true},
DefaultValueValue: sql.NullString{Valid: false},
}
@@ -162,7 +162,7 @@ func parseDDL(strs ...string) (*ddl, error) {
for _, column := range getAllColumns(matches[1]) {
for idx, c := range result.columns {
if c.NameValue.String == column {
c.UniqueValue = sql.NullBool{Bool: true, Valid: true}
c.UniqueValue = sql.NullBool{Bool: strings.ToUpper(strings.Fields(str)[1]) == "UNIQUE", Valid: true}
result.columns[idx] = c
}
}
@@ -175,6 +175,18 @@ func parseDDL(strs ...string) (*ddl, error) {
return &result, nil
}
func (d *ddl) clone() *ddl {
copied := new(ddl)
*copied = *d
copied.fields = make([]string, len(d.fields))
copy(copied.fields, d.fields)
copied.columns = make([]migrator.ColumnType, len(d.columns))
copy(copied.columns, d.columns)
return copied
}
func (d *ddl) compile() string {
if len(d.fields) == 0 {
return d.head
@@ -183,6 +195,21 @@ func (d *ddl) compile() string {
return fmt.Sprintf("%s (%s)", d.head, strings.Join(d.fields, ","))
}
func (d *ddl) renameTable(dst, src string) error {
tableReg, err := regexp.Compile("\\s*('|`|\")?\\b" + regexp.QuoteMeta(src) + "\\b('|`|\")?\\s*")
if err != nil {
return err
}
replaced := tableReg.ReplaceAllString(d.head, fmt.Sprintf(" `%s` ", dst))
if replaced == d.head {
return fmt.Errorf("failed to look up tablename `%s` from DDL head '%s'", src, d.head)
}
d.head = replaced
return nil
}
func (d *ddl) addConstraint(name string, sql string) {
reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]")
@@ -208,6 +235,18 @@ func (d *ddl) removeConstraint(name string) bool {
return false
}
//lint:ignore U1000 ignore unused code.
func (d *ddl) hasConstraint(name string) bool {
reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]")
for _, f := range d.fields {
if reg.MatchString(f) {
return true
}
}
return false
}
func (d *ddl) getColumns() []string {
res := []string{}
@@ -229,3 +268,30 @@ func (d *ddl) getColumns() []string {
}
return res
}
func (d *ddl) alterColumn(name, sql string) bool {
reg := regexp.MustCompile("^(`|'|\"| )" + regexp.QuoteMeta(name) + "(`|'|\"| ) .*?$")
for i := 0; i < len(d.fields); i++ {
if reg.MatchString(d.fields[i]) {
d.fields[i] = sql
return false
}
}
d.fields = append(d.fields, sql)
return true
}
func (d *ddl) removeColumn(name string) bool {
reg := regexp.MustCompile("^(`|'|\"| )" + regexp.QuoteMeta(name) + "(`|'|\"| ) .*?$")
for i := 0; i < len(d.fields); i++ {
if reg.MatchString(d.fields[i]) {
d.fields = append(d.fields[:i], d.fields[i+1:]...)
return true
}
}
return false
}

View File

@@ -20,16 +20,16 @@ func TestParseDDL(t *testing.T) {
"CREATE UNIQUE INDEX `idx_profiles_refer` ON `profiles`(`text`)",
}, 6, []migrator.ColumnType{
{NameValue: sql.NullString{String: "id", Valid: true}, DataTypeValue: sql.NullString{String: "integer", Valid: true}, ColumnTypeValue: sql.NullString{String: "integer", Valid: true}, PrimaryKeyValue: sql.NullBool{Bool: true, Valid: true}, NullableValue: sql.NullBool{Valid: true}, UniqueValue: sql.NullBool{Valid: true}, DefaultValueValue: sql.NullString{Valid: false}},
{NameValue: sql.NullString{String: "text", Valid: true}, DataTypeValue: sql.NullString{String: "varchar", Valid: true}, LengthValue: sql.NullInt64{Int64: 500, Valid: true}, ColumnTypeValue: sql.NullString{String: "varchar(500)", Valid: true}, DefaultValueValue: sql.NullString{String: "hello", Valid: true}, NullableValue: sql.NullBool{Valid: true}, UniqueValue: sql.NullBool{Bool: true, Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}},
{NameValue: sql.NullString{String: "age", Valid: true}, DataTypeValue: sql.NullString{String: "integer", Valid: true}, ColumnTypeValue: sql.NullString{String: "integer", Valid: true}, DefaultValueValue: sql.NullString{String: "18", Valid: true}, NullableValue: sql.NullBool{Valid: true}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}},
{NameValue: sql.NullString{String: "user_id", Valid: true}, DataTypeValue: sql.NullString{String: "integer", Valid: true}, ColumnTypeValue: sql.NullString{String: "integer", Valid: true}, DefaultValueValue: sql.NullString{Valid: false}, NullableValue: sql.NullBool{Valid: true}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}},
{NameValue: sql.NullString{String: "text", Valid: true}, DataTypeValue: sql.NullString{String: "varchar", Valid: true}, LengthValue: sql.NullInt64{Int64: 500, Valid: true}, ColumnTypeValue: sql.NullString{String: "varchar(500)", Valid: true}, DefaultValueValue: sql.NullString{String: "hello", Valid: true}, NullableValue: sql.NullBool{Bool: true, Valid: true}, UniqueValue: sql.NullBool{Bool: true, Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}},
{NameValue: sql.NullString{String: "age", Valid: true}, DataTypeValue: sql.NullString{String: "integer", Valid: true}, ColumnTypeValue: sql.NullString{String: "integer", Valid: true}, DefaultValueValue: sql.NullString{String: "18", Valid: true}, NullableValue: sql.NullBool{Bool: true, Valid: true}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}},
{NameValue: sql.NullString{String: "user_id", Valid: true}, DataTypeValue: sql.NullString{String: "integer", Valid: true}, ColumnTypeValue: sql.NullString{String: "integer", Valid: true}, DefaultValueValue: sql.NullString{Valid: false}, NullableValue: sql.NullBool{Bool: true, Valid: true}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}},
},
},
{"with_check", []string{"CREATE TABLE Persons (ID int NOT NULL,LastName varchar(255) NOT NULL,FirstName varchar(255),Age int,CHECK (Age>=18),CHECK (FirstName<>'John'))"}, 6, []migrator.ColumnType{
{NameValue: sql.NullString{String: "ID", Valid: true}, DataTypeValue: sql.NullString{String: "int", Valid: true}, ColumnTypeValue: sql.NullString{String: "int", Valid: true}, NullableValue: sql.NullBool{Valid: true}, DefaultValueValue: sql.NullString{Valid: false}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}},
{NameValue: sql.NullString{String: "LastName", Valid: true}, DataTypeValue: sql.NullString{String: "varchar", Valid: true}, LengthValue: sql.NullInt64{Int64: 255, Valid: true}, ColumnTypeValue: sql.NullString{String: "varchar(255)", Valid: true}, NullableValue: sql.NullBool{Bool: false, Valid: true}, DefaultValueValue: sql.NullString{Valid: false}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}},
{NameValue: sql.NullString{String: "FirstName", Valid: true}, DataTypeValue: sql.NullString{String: "varchar", Valid: true}, LengthValue: sql.NullInt64{Int64: 255, Valid: true}, ColumnTypeValue: sql.NullString{String: "varchar(255)", Valid: true}, DefaultValueValue: sql.NullString{Valid: false}, NullableValue: sql.NullBool{Valid: true}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}},
{NameValue: sql.NullString{String: "Age", Valid: true}, DataTypeValue: sql.NullString{String: "int", Valid: true}, ColumnTypeValue: sql.NullString{String: "int", Valid: true}, DefaultValueValue: sql.NullString{Valid: false}, NullableValue: sql.NullBool{Valid: true}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}},
{NameValue: sql.NullString{String: "FirstName", Valid: true}, DataTypeValue: sql.NullString{String: "varchar", Valid: true}, LengthValue: sql.NullInt64{Int64: 255, Valid: true}, ColumnTypeValue: sql.NullString{String: "varchar(255)", Valid: true}, DefaultValueValue: sql.NullString{Valid: false}, NullableValue: sql.NullBool{Bool: true, Valid: true}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}},
{NameValue: sql.NullString{String: "Age", Valid: true}, DataTypeValue: sql.NullString{String: "int", Valid: true}, ColumnTypeValue: sql.NullString{String: "int", Valid: true}, DefaultValueValue: sql.NullString{Valid: false}, NullableValue: sql.NullBool{Bool: true, Valid: true}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}},
}},
{"lowercase", []string{"create table test (ID int NOT NULL)"}, 1, []migrator.ColumnType{
{NameValue: sql.NullString{String: "ID", Valid: true}, DataTypeValue: sql.NullString{String: "int", Valid: true}, ColumnTypeValue: sql.NullString{String: "int", Valid: true}, NullableValue: sql.NullBool{Bool: false, Valid: true}, DefaultValueValue: sql.NullString{Valid: false}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}},
@@ -39,7 +39,7 @@ func TestParseDDL(t *testing.T) {
{"with_special_characters", []string{
"CREATE TABLE `test` (`text` varchar(10) DEFAULT \"测试, \")",
}, 1, []migrator.ColumnType{
{NameValue: sql.NullString{String: "text", Valid: true}, DataTypeValue: sql.NullString{String: "varchar", Valid: true}, LengthValue: sql.NullInt64{Int64: 10, Valid: true}, ColumnTypeValue: sql.NullString{String: "varchar(10)", Valid: true}, DefaultValueValue: sql.NullString{String: "测试, ", Valid: true}, NullableValue: sql.NullBool{Valid: true}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}},
{NameValue: sql.NullString{String: "text", Valid: true}, DataTypeValue: sql.NullString{String: "varchar", Valid: true}, LengthValue: sql.NullInt64{Int64: 10, Valid: true}, ColumnTypeValue: sql.NullString{String: "varchar(10)", Valid: true}, DefaultValueValue: sql.NullString{String: "测试, ", Valid: true}, NullableValue: sql.NullBool{Bool: true, Valid: true}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}},
},
},
{
@@ -79,6 +79,42 @@ func TestParseDDL(t *testing.T) {
},
},
},
{
"non-unique index",
[]string{
"CREATE TABLE `test-c` (`field` integer NOT NULL)",
"CREATE INDEX `idx_uq` ON `test-b`(`field`) WHERE field = 0",
},
1,
[]migrator.ColumnType{
{
NameValue: sql.NullString{String: "field", Valid: true},
DataTypeValue: sql.NullString{String: "integer", Valid: true},
ColumnTypeValue: sql.NullString{String: "integer", Valid: true},
PrimaryKeyValue: sql.NullBool{Bool: false, Valid: true},
UniqueValue: sql.NullBool{Bool: false, Valid: true},
NullableValue: sql.NullBool{Bool: false, Valid: true},
},
},
},
{
"index with \n from .schema sqlite",
[]string{
"CREATE TABLE `test-d` (`field` integer NOT NULL)",
"CREATE INDEX `idx_uq`\n ON `test-b`(`field`) WHERE field = 0",
},
1,
[]migrator.ColumnType{
{
NameValue: sql.NullString{String: "field", Valid: true},
DataTypeValue: sql.NullString{String: "integer", Valid: true},
ColumnTypeValue: sql.NullString{String: "integer", Valid: true},
PrimaryKeyValue: sql.NullBool{Bool: false, Valid: true},
UniqueValue: sql.NullBool{Bool: false, Valid: true},
NullableValue: sql.NullBool{Bool: false, Valid: true},
},
},
},
}
for _, p := range params {
@@ -104,7 +140,7 @@ func TestParseDDL_Whitespaces(t *testing.T) {
NameValue: sql.NullString{String: "id", Valid: true},
DataTypeValue: sql.NullString{String: "integer", Valid: true},
ColumnTypeValue: sql.NullString{String: "integer", Valid: true},
NullableValue: sql.NullBool{Bool: false, Valid: true},
NullableValue: sql.NullBool{Bool: true, Valid: true},
DefaultValueValue: sql.NullString{Valid: false},
UniqueValue: sql.NullBool{Bool: true, Valid: true},
PrimaryKeyValue: sql.NullBool{Bool: true, Valid: true},
@@ -113,7 +149,7 @@ func TestParseDDL_Whitespaces(t *testing.T) {
NameValue: sql.NullString{String: "dark_mode", Valid: true},
DataTypeValue: sql.NullString{String: "numeric", Valid: true},
ColumnTypeValue: sql.NullString{String: "numeric", Valid: true},
NullableValue: sql.NullBool{Valid: true},
NullableValue: sql.NullBool{Bool: true, Valid: true},
DefaultValueValue: sql.NullString{String: "true", Valid: true},
UniqueValue: sql.NullBool{Bool: false, Valid: true},
PrimaryKeyValue: sql.NullBool{Bool: false, Valid: true},

11
gormlite/download.sh Executable file
View File

@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euo pipefail
cd -P -- "$(dirname -- "$0")"
curl -#OL "https://github.com/go-gorm/sqlite/raw/master/ddlmod.go"
curl -#OL "https://github.com/go-gorm/sqlite/raw/master/ddlmod_test.go"
curl -#OL "https://github.com/go-gorm/sqlite/raw/master/error_translator.go"
curl -#OL "https://github.com/go-gorm/sqlite/raw/master/migrator.go"
curl -#OL "https://github.com/go-gorm/sqlite/raw/master/sqlite.go"
curl -#OL "https://github.com/go-gorm/sqlite/raw/master/sqlite_test.go"

View File

@@ -7,9 +7,15 @@ import (
"gorm.io/gorm"
)
func (dialector Dialector) Translate(err error) error {
if errors.Is(err, sqlite3.CONSTRAINT_UNIQUE) {
func (_Dialector) Translate(err error) error {
switch {
case
errors.Is(err, sqlite3.CONSTRAINT_UNIQUE),
errors.Is(err, sqlite3.CONSTRAINT_PRIMARYKEY):
return gorm.ErrDuplicatedKey
case
errors.Is(err, sqlite3.CONSTRAINT_FOREIGNKEY):
return gorm.ErrForeignKeyViolated
}
return err
}

View File

@@ -1,7 +0,0 @@
package gormlite
import "errors"
var (
ErrConstraintsNotImplemented = errors.New("constraints not implemented on sqlite, consider using DisableForeignKeyConstraintWhenMigrating, more details https://github.com/go-gorm/gorm/wiki/GORM-V2-Release-Note-Draft#all-new-migrator")
)

View File

@@ -1,16 +1,16 @@
module github.com/ncruces/go-sqlite3/gormlite
go 1.19
go 1.21
require (
github.com/ncruces/go-sqlite3 v0.7.2
gorm.io/gorm v1.25.1
github.com/ncruces/go-sqlite3 v0.11.0
gorm.io/gorm v1.25.5
)
require (
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/ncruces/julianday v0.1.5 // indirect
github.com/tetratelabs/wazero v1.2.0 // indirect
golang.org/x/sys v0.8.0 // indirect
github.com/ncruces/julianday v1.0.0 // indirect
github.com/tetratelabs/wazero v1.5.0 // indirect
golang.org/x/sys v0.15.0 // indirect
)

View File

@@ -2,13 +2,15 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/ncruces/go-sqlite3 v0.7.2 h1:K7jU4rnUxFdUsbEL+B0Xc+VexLTEwGSO6Qh91Qh4hYc=
github.com/ncruces/go-sqlite3 v0.7.2/go.mod h1:t3dP4AP9rJddU+ffFv0h6fWyeOCEhjxrYc1nsYG7aQI=
github.com/ncruces/julianday v0.1.5 h1:hDJ9ejiMp3DHsoZ5KW4c1lwfMjbARS7u/gbYcd0FBZk=
github.com/ncruces/julianday v0.1.5/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
github.com/tetratelabs/wazero v1.2.0 h1:I/8LMf4YkCZ3r2XaL9whhA0VMyAvF6QE+O7rco0DCeQ=
github.com/tetratelabs/wazero v1.2.0/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64=
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
github.com/ncruces/go-sqlite3 v0.11.0 h1:PDjs8Ve2Z0GWmHyKQHGUyG78grCXKhiHCUZQI8CqXO8=
github.com/ncruces/go-sqlite3 v0.11.0/go.mod h1:zaYJ6xP+EQiWJCa3nd3h28cD8DuSIcIqh+LrJMrBN9k=
github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
github.com/tetratelabs/wazero v1.5.0 h1:Yz3fZHivfDiZFUXnWMPUoiW7s8tC1sjdBtlJn08qYa0=
github.com/tetratelabs/wazero v1.5.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=

View File

@@ -3,7 +3,6 @@ package gormlite
import (
"database/sql"
"fmt"
"regexp"
"strings"
"gorm.io/gorm"
@@ -12,11 +11,11 @@ import (
"gorm.io/gorm/schema"
)
type Migrator struct {
type _Migrator struct {
migrator.Migrator
}
func (m *Migrator) RunWithoutForeignKey(fc func() error) error {
func (m *_Migrator) RunWithoutForeignKey(fc func() error) error {
var enabled int
m.DB.Raw("PRAGMA foreign_keys").Scan(&enabled)
if enabled == 1 {
@@ -27,7 +26,7 @@ func (m *Migrator) RunWithoutForeignKey(fc func() error) error {
return fc()
}
func (m Migrator) HasTable(value interface{}) bool {
func (m _Migrator) HasTable(value interface{}) bool {
var count int
m.Migrator.RunWithValue(value, func(stmt *gorm.Statement) error {
return m.DB.Raw("SELECT count(*) FROM sqlite_master WHERE type='table' AND name=?", stmt.Table).Row().Scan(&count)
@@ -35,7 +34,7 @@ func (m Migrator) HasTable(value interface{}) bool {
return count > 0
}
func (m Migrator) DropTable(values ...interface{}) error {
func (m _Migrator) DropTable(values ...interface{}) error {
return m.RunWithoutForeignKey(func() error {
values = m.ReorderModels(values, false)
tx := m.DB.Session(&gorm.Session{})
@@ -52,11 +51,11 @@ func (m Migrator) DropTable(values ...interface{}) error {
})
}
func (m Migrator) GetTables() (tableList []string, err error) {
func (m _Migrator) GetTables() (tableList []string, err error) {
return tableList, m.DB.Raw("SELECT name FROM sqlite_master where type=?", "table").Scan(&tableList).Error
}
func (m Migrator) HasColumn(value interface{}, name string) bool {
func (m _Migrator) HasColumn(value interface{}, name string) bool {
var count int
m.Migrator.RunWithValue(value, func(stmt *gorm.Statement) error {
if stmt.Schema != nil {
@@ -76,31 +75,24 @@ func (m Migrator) HasColumn(value interface{}, name string) bool {
return count > 0
}
func (m Migrator) AlterColumn(value interface{}, name string) error {
func (m _Migrator) AlterColumn(value interface{}, name string) error {
return m.RunWithoutForeignKey(func() error {
return m.recreateTable(value, nil, func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error) {
return m.recreateTable(value, nil, func(ddl *ddl, stmt *gorm.Statement) (*ddl, []interface{}, error) {
if field := stmt.Schema.LookUpField(name); field != nil {
// lookup field from table definition, ddl might looks like `'name' int,` or `'name' int)`
reg, err := regexp.Compile("(`|'|\"| )" + field.DBName + "(`|'|\"| ) .*?(,|\\)\\s*$)")
if err != nil {
return "", nil, err
if ddl.alterColumn(field.DBName, fmt.Sprintf("`%s` ?", field.DBName)) {
return nil, nil, fmt.Errorf("field `%s` not found in origin ddl, ddl= '%s'", name, ddl.compile())
}
createSQL := reg.ReplaceAllString(rawDDL, fmt.Sprintf("`%v` ?$3", field.DBName))
if createSQL == rawDDL {
return "", nil, fmt.Errorf("failed to look up field %v from DDL %v", field.DBName, rawDDL)
}
return createSQL, []interface{}{m.FullDataTypeOf(field)}, nil
return ddl, []interface{}{m.FullDataTypeOf(field)}, nil
}
return "", nil, fmt.Errorf("failed to alter field with name %v", name)
return nil, nil, fmt.Errorf("failed to alter field with name `%s`", name)
})
})
}
// ColumnTypes return columnTypes []gorm.ColumnType and execErr error
func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) {
func (m _Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) {
columnTypes := make([]gorm.ColumnType, 0)
execErr := m.RunWithValue(value, func(stmt *gorm.Statement) (err error) {
var (
@@ -148,29 +140,23 @@ func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) {
return columnTypes, execErr
}
func (m Migrator) DropColumn(value interface{}, name string) error {
return m.recreateTable(value, nil, func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error) {
func (m _Migrator) DropColumn(value interface{}, name string) error {
return m.recreateTable(value, nil, func(ddl *ddl, stmt *gorm.Statement) (*ddl, []interface{}, error) {
if field := stmt.Schema.LookUpField(name); field != nil {
name = field.DBName
}
reg, err := regexp.Compile("(`|'|\"| |\\[)" + name + "(`|'|\"| |\\]) .*?,")
if err != nil {
return "", nil, err
}
createSQL := reg.ReplaceAllString(rawDDL, "")
return createSQL, nil, nil
ddl.removeColumn(name)
return ddl, nil, nil
})
}
func (m Migrator) CreateConstraint(value interface{}, name string) error {
func (m _Migrator) CreateConstraint(value interface{}, name string) error {
return m.RunWithValue(value, func(stmt *gorm.Statement) error {
constraint, chk, table := m.GuessConstraintAndTable(stmt, name)
return m.recreateTable(value, &table,
func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error) {
func(ddl *ddl, stmt *gorm.Statement) (*ddl, []interface{}, error) {
var (
constraintName string
constraintSql string
@@ -185,22 +171,16 @@ func (m Migrator) CreateConstraint(value interface{}, name string) error {
constraintSql = "CONSTRAINT ? CHECK (?)"
constraintValues = []interface{}{clause.Column{Name: chk.Name}, clause.Expr{SQL: chk.Constraint}}
} else {
return "", nil, nil
return nil, nil, nil
}
createDDL, err := parseDDL(rawDDL)
if err != nil {
return "", nil, err
}
createDDL.addConstraint(constraintName, constraintSql)
createSQL := createDDL.compile()
return createSQL, constraintValues, nil
ddl.addConstraint(constraintName, constraintSql)
return ddl, constraintValues, nil
})
})
}
func (m Migrator) DropConstraint(value interface{}, name string) error {
func (m _Migrator) DropConstraint(value interface{}, name string) error {
return m.RunWithValue(value, func(stmt *gorm.Statement) error {
constraint, chk, table := m.GuessConstraintAndTable(stmt, name)
if constraint != nil {
@@ -210,20 +190,14 @@ func (m Migrator) DropConstraint(value interface{}, name string) error {
}
return m.recreateTable(value, &table,
func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error) {
createDDL, err := parseDDL(rawDDL)
if err != nil {
return "", nil, err
}
createDDL.removeConstraint(name)
createSQL := createDDL.compile()
return createSQL, nil, nil
func(ddl *ddl, stmt *gorm.Statement) (*ddl, []interface{}, error) {
ddl.removeConstraint(name)
return ddl, nil, nil
})
})
}
func (m Migrator) HasConstraint(value interface{}, name string) bool {
func (m _Migrator) HasConstraint(value interface{}, name string) bool {
var count int64
m.RunWithValue(value, func(stmt *gorm.Statement) error {
constraint, chk, table := m.GuessConstraintAndTable(stmt, name)
@@ -244,13 +218,13 @@ func (m Migrator) HasConstraint(value interface{}, name string) bool {
return count > 0
}
func (m Migrator) CurrentDatabase() (name string) {
func (m _Migrator) CurrentDatabase() (name string) {
var null interface{}
m.DB.Raw("PRAGMA database_list").Row().Scan(&null, &name, &null)
return
}
func (m Migrator) BuildIndexOptions(opts []schema.IndexOption, stmt *gorm.Statement) (results []interface{}) {
func (m _Migrator) BuildIndexOptions(opts []schema.IndexOption, stmt *gorm.Statement) (results []interface{}) {
for _, opt := range opts {
str := stmt.Quote(opt.DBName)
if opt.Expression != "" {
@@ -269,7 +243,7 @@ func (m Migrator) BuildIndexOptions(opts []schema.IndexOption, stmt *gorm.Statem
return
}
func (m Migrator) CreateIndex(value interface{}, name string) error {
func (m _Migrator) CreateIndex(value interface{}, name string) error {
return m.RunWithValue(value, func(stmt *gorm.Statement) error {
if stmt.Schema != nil {
if idx := stmt.Schema.LookIndex(name); idx != nil {
@@ -298,7 +272,7 @@ func (m Migrator) CreateIndex(value interface{}, name string) error {
})
}
func (m Migrator) HasIndex(value interface{}, name string) bool {
func (m _Migrator) HasIndex(value interface{}, name string) bool {
var count int
m.RunWithValue(value, func(stmt *gorm.Statement) error {
if stmt.Schema != nil {
@@ -317,18 +291,21 @@ func (m Migrator) HasIndex(value interface{}, name string) bool {
return count > 0
}
func (m Migrator) RenameIndex(value interface{}, oldName, newName string) error {
func (m _Migrator) RenameIndex(value interface{}, oldName, newName string) error {
return m.RunWithValue(value, func(stmt *gorm.Statement) error {
var sql string
m.DB.Raw("SELECT sql FROM sqlite_master WHERE type = ? AND tbl_name = ? AND name = ?", "index", stmt.Table, oldName).Row().Scan(&sql)
if sql != "" {
if err := m.DropIndex(value, oldName); err != nil {
return err
}
return m.DB.Exec(strings.Replace(sql, oldName, newName, 1)).Error
}
return fmt.Errorf("failed to find index with name %v", oldName)
})
}
func (m Migrator) DropIndex(value interface{}, name string) error {
func (m _Migrator) DropIndex(value interface{}, name string) error {
return m.RunWithValue(value, func(stmt *gorm.Statement) error {
if stmt.Schema != nil {
if idx := stmt.Schema.LookIndex(name); idx != nil {
@@ -362,7 +339,7 @@ func buildConstraint(constraint *schema.Constraint) (sql string, results []inter
return
}
func (m Migrator) getRawDDL(table string) (string, error) {
func (m _Migrator) getRawDDL(table string) (string, error) {
var createSQL string
m.DB.Raw("SELECT sql FROM sqlite_master WHERE type = ? AND tbl_name = ? AND name = ?", "table", table, table).Row().Scan(&createSQL)
@@ -372,8 +349,10 @@ func (m Migrator) getRawDDL(table string) (string, error) {
return createSQL, nil
}
func (m Migrator) recreateTable(value interface{}, tablePtr *string,
getCreateSQL func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error)) error {
func (m _Migrator) recreateTable(
value interface{}, tablePtr *string,
getCreateSQL func(ddl *ddl, stmt *gorm.Statement) (sql *ddl, sqlArgs []interface{}, err error),
) error {
return m.RunWithValue(value, func(stmt *gorm.Statement) error {
table := stmt.Table
if tablePtr != nil {
@@ -385,27 +364,26 @@ func (m Migrator) recreateTable(value interface{}, tablePtr *string,
return err
}
newTableName := table + "__temp"
createSQL, sqlArgs, err := getCreateSQL(rawDDL, stmt)
originDDL, err := parseDDL(rawDDL)
if err != nil {
return err
}
if createSQL == "" {
createDDL, sqlArgs, err := getCreateSQL(originDDL.clone(), stmt)
if err != nil {
return err
}
if createDDL == nil {
return nil
}
tableReg, err := regexp.Compile("\\s*('|`|\")?\\b" + table + "\\b('|`|\")?\\s*")
if err != nil {
newTableName := table + "__temp"
if err := createDDL.renameTable(newTableName, table); err != nil {
return err
}
createSQL = tableReg.ReplaceAllString(createSQL, fmt.Sprintf(" `%v` ", newTableName))
createDDL, err := parseDDL(createSQL)
if err != nil {
return err
}
columns := createDDL.getColumns()
createSQL := createDDL.compile()
return m.DB.Transaction(func(tx *gorm.DB) error {
if err := tx.Exec(createSQL, sqlArgs...).Error; err != nil {

View File

@@ -5,7 +5,6 @@ import (
"context"
"database/sql"
"strconv"
"strings"
"gorm.io/gorm"
"gorm.io/gorm/callbacks"
@@ -14,27 +13,33 @@ import (
"gorm.io/gorm/migrator"
"gorm.io/gorm/schema"
_ "github.com/ncruces/go-sqlite3/driver"
"github.com/ncruces/go-sqlite3/driver"
)
type Dialector struct {
// Open opens a GORM dialector from a data source name.
func Open(dsn string) gorm.Dialector {
return &_Dialector{DSN: dsn}
}
// Open opens a GORM dialector from a database handle.
func OpenDB(db *sql.DB) gorm.Dialector {
return &_Dialector{Conn: db}
}
type _Dialector struct {
DSN string
Conn gorm.ConnPool
}
func Open(dsn string) gorm.Dialector {
return &Dialector{DSN: dsn}
}
func (dialector Dialector) Name() string {
func (dialector _Dialector) Name() string {
return "sqlite"
}
func (dialector Dialector) Initialize(db *gorm.DB) (err error) {
func (dialector _Dialector) Initialize(db *gorm.DB) (err error) {
if dialector.Conn != nil {
db.ConnPool = dialector.Conn
} else {
conn, err := sql.Open("sqlite3", dialector.DSN)
conn, err := driver.Open(dialector.DSN, nil)
if err != nil {
return err
}
@@ -45,11 +50,11 @@ func (dialector Dialector) Initialize(db *gorm.DB) (err error) {
if err := db.ConnPool.QueryRowContext(context.Background(), "select sqlite_version()").Scan(&version); err != nil {
return err
}
// https://www.sqlite.org/releaselog/3_35_0.html
// https://sqlite.org/releaselog/3_35_0.html
if compareVersion(version, "3.35.0") >= 0 {
callbacks.RegisterDefaultCallbacks(db, &callbacks.Config{
CreateClauses: []string{"INSERT", "VALUES", "ON CONFLICT", "RETURNING"},
UpdateClauses: []string{"UPDATE", "SET", "WHERE", "RETURNING"},
UpdateClauses: []string{"UPDATE", "SET", "FROM", "WHERE", "RETURNING"},
DeleteClauses: []string{"DELETE", "FROM", "WHERE", "RETURNING"},
LastInsertIDReversed: true,
})
@@ -65,7 +70,7 @@ func (dialector Dialector) Initialize(db *gorm.DB) (err error) {
return
}
func (dialector Dialector) ClauseBuilders() map[string]clause.ClauseBuilder {
func (dialector _Dialector) ClauseBuilders() map[string]clause.ClauseBuilder {
return map[string]clause.ClauseBuilder{
"INSERT": func(c clause.Clause, builder clause.Builder) {
if insert, ok := c.Expression.(clause.Insert); ok {
@@ -114,7 +119,7 @@ func (dialector Dialector) ClauseBuilders() map[string]clause.ClauseBuilder {
}
}
func (dialector Dialector) DefaultValueOf(field *schema.Field) clause.Expression {
func (dialector _Dialector) DefaultValueOf(field *schema.Field) clause.Expression {
if field.AutoIncrement {
return clause.Expr{SQL: "NULL"}
}
@@ -123,45 +128,78 @@ func (dialector Dialector) DefaultValueOf(field *schema.Field) clause.Expression
return clause.Expr{SQL: "DEFAULT"}
}
func (dialector Dialector) Migrator(db *gorm.DB) gorm.Migrator {
return Migrator{migrator.Migrator{Config: migrator.Config{
func (dialector _Dialector) Migrator(db *gorm.DB) gorm.Migrator {
return _Migrator{migrator.Migrator{Config: migrator.Config{
DB: db,
Dialector: dialector,
CreateIndexAfterCreateTable: true,
}}}
}
func (dialector Dialector) BindVarTo(writer clause.Writer, stmt *gorm.Statement, v interface{}) {
func (dialector _Dialector) BindVarTo(writer clause.Writer, stmt *gorm.Statement, v interface{}) {
writer.WriteByte('?')
}
func (dialector Dialector) QuoteTo(writer clause.Writer, str string) {
writer.WriteByte('`')
if strings.Contains(str, ".") {
for idx, str := range strings.Split(str, ".") {
if idx > 0 {
writer.WriteString(".`")
func (dialector _Dialector) QuoteTo(writer clause.Writer, str string) {
var (
underQuoted, selfQuoted bool
continuousBacktick int8
shiftDelimiter int8
)
for _, v := range []byte(str) {
switch v {
case '`':
continuousBacktick++
if continuousBacktick == 2 {
writer.WriteString("``")
continuousBacktick = 0
}
writer.WriteString(str)
writer.WriteByte('`')
case '.':
if continuousBacktick > 0 || !selfQuoted {
shiftDelimiter = 0
underQuoted = false
continuousBacktick = 0
writer.WriteString("`")
}
writer.WriteByte(v)
continue
default:
if shiftDelimiter-continuousBacktick <= 0 && !underQuoted {
writer.WriteString("`")
underQuoted = true
if selfQuoted = continuousBacktick > 0; selfQuoted {
continuousBacktick -= 1
}
}
for ; continuousBacktick > 0; continuousBacktick -= 1 {
writer.WriteString("``")
}
writer.WriteByte(v)
}
} else {
writer.WriteString(str)
writer.WriteByte('`')
shiftDelimiter++
}
if continuousBacktick > 0 && !selfQuoted {
writer.WriteString("``")
}
writer.WriteString("`")
}
func (dialector Dialector) Explain(sql string, vars ...interface{}) string {
func (dialector _Dialector) Explain(sql string, vars ...interface{}) string {
return logger.ExplainSQL(sql, nil, `"`, vars...)
}
func (dialector Dialector) DataTypeOf(field *schema.Field) string {
func (dialector _Dialector) DataTypeOf(field *schema.Field) string {
switch field.DataType {
case schema.Bool:
return "numeric"
case schema.Int, schema.Uint:
if field.AutoIncrement && !field.PrimaryKey {
// https://www.sqlite.org/autoinc.html
if field.AutoIncrement {
// doesn't check `PrimaryKey`, to keep backward compatibility
// https://sqlite.org/autoinc.html
return "integer PRIMARY KEY AUTOINCREMENT"
} else {
return "integer"
@@ -184,12 +222,12 @@ func (dialector Dialector) DataTypeOf(field *schema.Field) string {
return string(field.DataType)
}
func (dialectopr Dialector) SavePoint(tx *gorm.DB, name string) error {
func (dialectopr _Dialector) SavePoint(tx *gorm.DB, name string) error {
tx.Exec("SAVEPOINT " + name)
return nil
}
func (dialectopr Dialector) RollbackTo(tx *gorm.DB, name string) error {
func (dialectopr _Dialector) RollbackTo(tx *gorm.DB, name string) error {
tx.Exec("ROLLBACK TO SAVEPOINT " + name)
return nil
}

View File

@@ -6,6 +6,8 @@ import (
"gorm.io/gorm"
"github.com/ncruces/go-sqlite3"
"github.com/ncruces/go-sqlite3/driver"
_ "github.com/ncruces/go-sqlite3/embed"
)
@@ -13,22 +15,52 @@ func TestDialector(t *testing.T) {
// This is the DSN of the in-memory SQLite database for these tests.
const InMemoryDSN = "file:testdatabase?mode=memory&cache=shared"
// Custom connection with a custom function called "my_custom_function".
db, err := driver.Open(InMemoryDSN, func(conn *sqlite3.Conn) error {
return conn.CreateFunction("my_custom_function", 0, sqlite3.DETERMINISTIC,
func(ctx sqlite3.Context, arg ...sqlite3.Value) {
ctx.ResultText("my-result")
})
})
if err != nil {
t.Fatal(err)
}
rows := []struct {
description string
dialector *Dialector
dialector gorm.Dialector
openSuccess bool
query string
querySuccess bool
}{
{
description: "Default driver",
dialector: &Dialector{
DSN: InMemoryDSN,
},
description: "Default driver",
dialector: Open(InMemoryDSN),
openSuccess: true,
query: "SELECT 1",
querySuccess: true,
},
{
description: "Custom function",
dialector: Open(InMemoryDSN),
openSuccess: true,
query: "SELECT my_custom_function()",
querySuccess: false,
},
{
description: "Custom connection",
dialector: OpenDB(db),
openSuccess: true,
query: "SELECT 1",
querySuccess: true,
},
{
description: "Custom connection, custom function",
dialector: OpenDB(db),
openSuccess: true,
query: "SELECT my_custom_function()",
querySuccess: true,
},
}
for rowIndex, row := range rows {
t.Run(fmt.Sprintf("%d/%s", rowIndex, row.description), func(t *testing.T) {

View File

@@ -3,12 +3,24 @@ set -euo pipefail
cd -P -- "$(dirname -- "$0")"
go test
rm -rf gorm/ tests/
git clone --filter=blob:none --branch=v1.25.1 https://github.com/go-gorm/gorm.git
git clone --filter=blob:none https://github.com/go-gorm/gorm.git
mv gorm/tests tests
rm -rf gorm/
patch -p1 -N < tests.patch
cd tests
go mod tidy && go test
go mod edit \
-require github.com/ncruces/go-sqlite3/gormlite@v0.0.0 \
-replace github.com/ncruces/go-sqlite3/gormlite=../ \
-replace github.com/ncruces/go-sqlite3=../../ \
-droprequire gorm.io/driver/sqlite \
-dropreplace gorm.io/gorm
go mod tidy && go work use . && go test
cd ..
rm -rf tests/
go work use -r .

View File

@@ -1,51 +1,10 @@
diff --git a/tests/.gitignore b/tests/.gitignore
index 08cb523..72e8ffc 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1 +1 @@
-go.sum
+*
diff --git a/tests/go.mod b/tests/go.mod
index f47d175..84b80c2 100644
--- a/tests/go.mod
+++ b/tests/go.mod
@@ -7,13 +7,13 @@ require (
github.com/jackc/pgx/v5 v5.3.1 // indirect
github.com/jinzhu/now v1.1.5
github.com/lib/pq v1.10.8
- github.com/mattn/go-sqlite3 v1.14.16 // indirect
+ github.com/ncruces/go-sqlite3 v0.7.2
+ github.com/ncruces/go-sqlite3/gormlite v0.0.0
golang.org/x/crypto v0.8.0 // indirect
gorm.io/driver/mysql v1.5.0
gorm.io/driver/postgres v1.5.0
- gorm.io/driver/sqlite v1.5.0
gorm.io/driver/sqlserver v1.4.3
- gorm.io/gorm v1.25.0
+ gorm.io/gorm v1.25.1
)
-replace gorm.io/gorm => ../
+replace github.com/ncruces/go-sqlite3/gormlite => ../
diff --git a/tests/scanner_valuer_test.go b/tests/scanner_valuer_test.go
index 1412169..472434b 100644
--- a/tests/scanner_valuer_test.go
+++ b/tests/scanner_valuer_test.go
@@ -170,10 +170,10 @@ func (data *EncryptedData) Scan(value interface{}) error {
return errors.New("Too short")
}
- *data = b[3:]
+ *data = append((*data)[0:], b[3:]...)
return nil
} else if s, ok := value.(string); ok {
- *data = []byte(s)[3:]
+ *data = []byte(s[3:])
return nil
}
diff --git a/tests/tests_test.go b/tests/tests_test.go
index 90eb847..cd9af43 100644
--- a/tests/tests_test.go
+++ b/tests/tests_test.go
@@ -7,9 +7,11 @@ import (

View File

@@ -72,6 +72,7 @@ const (
IOERR_ROLLBACK_ATOMIC = IOERR | (31 << 8)
IOERR_DATA = IOERR | (32 << 8)
IOERR_CORRUPTFS = IOERR | (33 << 8)
IOERR_IN_PAGE = IOERR | (34 << 8)
LOCKED_SHAREDCACHE = LOCKED | (1 << 8)
LOCKED_VTAB = LOCKED | (2 << 8)
BUSY_RECOVERY = BUSY | (1 << 8)

View File

@@ -1,7 +1,6 @@
package util
import (
"fmt"
"runtime"
"strconv"
)
@@ -15,14 +14,14 @@ const (
OOMErr = ErrorString("sqlite3: out of memory")
RangeErr = ErrorString("sqlite3: index out of range")
NoNulErr = ErrorString("sqlite3: missing NUL terminator")
NoGlobalErr = ErrorString("sqlite3: could not find global: ")
NoFuncErr = ErrorString("sqlite3: could not find function: ")
BinaryErr = ErrorString("sqlite3: no SQLite binary embed/set/loaded")
NoBinaryErr = ErrorString("sqlite3: no SQLite binary embed/set/loaded")
BadBinaryErr = ErrorString("sqlite3: invalid SQLite binary embed/set/loaded")
TimeErr = ErrorString("sqlite3: invalid time value")
WhenceErr = ErrorString("sqlite3: invalid whence")
OffsetErr = ErrorString("sqlite3: invalid offset")
TailErr = ErrorString("sqlite3: multiple statements")
IsolationErr = ErrorString("sqlite3: unsupported isolation level")
ValueErr = ErrorString("sqlite3: unsupported value")
NoVFSErr = ErrorString("sqlite3: no such vfs: ")
)
@@ -34,14 +33,6 @@ func AssertErr() ErrorString {
return ErrorString(msg)
}
func Finalizer[T any](skip int) func(*T) {
msg := fmt.Sprintf("sqlite3: %T not closed", new(T))
if _, file, line, ok := runtime.Caller(skip + 1); ok && skip >= 0 {
msg += " (" + file + ":" + strconv.Itoa(line) + ")"
}
return func(*T) { panic(ErrorString(msg)) }
}
func ErrorCodeString(rc uint32) string {
switch rc {
case ABORT_ROLLBACK:

View File

@@ -10,6 +10,32 @@ import (
type i32 interface{ ~int32 | ~uint32 }
type i64 interface{ ~int64 | ~uint64 }
type funcVI[T0 i32] func(context.Context, api.Module, T0)
func (fn funcVI[T0]) Call(ctx context.Context, mod api.Module, stack []uint64) {
fn(ctx, mod, T0(stack[0]))
}
func ExportFuncVI[T0 i32](mod wazero.HostModuleBuilder, name string, fn func(context.Context, api.Module, T0)) {
mod.NewFunctionBuilder().
WithGoModuleFunction(funcVI[T0](fn),
[]api.ValueType{api.ValueTypeI32}, nil).
Export(name)
}
type funcVIII[T0, T1, T2 i32] func(context.Context, api.Module, T0, T1, T2)
func (fn funcVIII[T0, T1, T2]) Call(ctx context.Context, mod api.Module, stack []uint64) {
fn(ctx, mod, T0(stack[0]), T1(stack[1]), T2(stack[2]))
}
func ExportFuncVIII[T0, T1, T2 i32](mod wazero.HostModuleBuilder, name string, fn func(context.Context, api.Module, T0, T1, T2)) {
mod.NewFunctionBuilder().
WithGoModuleFunction(funcVIII[T0, T1, T2](fn),
[]api.ValueType{api.ValueTypeI32, api.ValueTypeI32, api.ValueTypeI32}, nil).
Export(name)
}
type funcII[TR, T0 i32] func(context.Context, api.Module, T0) TR
func (fn funcII[TR, T0]) Call(ctx context.Context, mod api.Module, stack []uint64) {

75
internal/util/handle.go Normal file
View File

@@ -0,0 +1,75 @@
package util
import (
"context"
"io"
"github.com/tetratelabs/wazero/experimental"
)
type handleKey struct{}
type handleState struct {
handles []any
empty int
}
func NewContext(ctx context.Context) context.Context {
state := new(handleState)
ctx = experimental.WithCloseNotifier(ctx, state)
ctx = context.WithValue(ctx, handleKey{}, state)
return ctx
}
func (s *handleState) CloseNotify(ctx context.Context, exitCode uint32) {
for _, h := range s.handles {
if c, ok := h.(io.Closer); ok {
c.Close()
}
}
s.handles = nil
s.empty = 0
}
func GetHandle(ctx context.Context, id uint32) any {
if id == 0 {
return nil
}
s := ctx.Value(handleKey{}).(*handleState)
return s.handles[^id]
}
func DelHandle(ctx context.Context, id uint32) error {
if id == 0 {
return nil
}
s := ctx.Value(handleKey{}).(*handleState)
a := s.handles[^id]
s.handles[^id] = nil
s.empty++
if c, ok := a.(io.Closer); ok {
return c.Close()
}
return nil
}
func AddHandle(ctx context.Context, a any) (id uint32) {
if a == nil {
panic(NilErr)
}
s := ctx.Value(handleKey{}).(*handleState)
// Find an empty slot.
if s.empty > cap(s.handles)-len(s.handles) {
for id, h := range s.handles {
if h == nil {
s.empty--
s.handles[id] = a
return ^uint32(id)
}
}
}
// Add a new slot.
s.handles = append(s.handles, a)
return -uint32(len(s.handles))
}

View File

@@ -14,6 +14,9 @@ func View(mod api.Module, ptr uint32, size uint64) []byte {
if size > math.MaxUint32 {
panic(RangeErr)
}
if size == 0 {
return nil
}
buf, ok := mod.Memory().Read(ptr, uint32(size))
if !ok {
panic(RangeErr)
@@ -21,6 +24,17 @@ func View(mod api.Module, ptr uint32, size uint64) []byte {
return buf
}
func ReadUint8(mod api.Module, ptr uint32) uint8 {
if ptr == 0 {
panic(NilErr)
}
v, ok := mod.Memory().ReadByte(ptr)
if !ok {
panic(RangeErr)
}
return v
}
func ReadUint32(mod api.Module, ptr uint32) uint32 {
if ptr == 0 {
panic(NilErr)
@@ -32,6 +46,16 @@ func ReadUint32(mod api.Module, ptr uint32) uint32 {
return v
}
func WriteUint8(mod api.Module, ptr uint32, v uint8) {
if ptr == 0 {
panic(NilErr)
}
ok := mod.Memory().WriteByte(ptr, v)
if !ok {
panic(RangeErr)
}
}
func WriteUint32(mod api.Module, ptr uint32, v uint32) {
if ptr == 0 {
panic(NilErr)

View File

@@ -28,6 +28,20 @@ func TestView_overflow(t *testing.T) {
t.Error("want panic")
}
func TestReadUint8_nil(t *testing.T) {
defer func() { _ = recover() }()
mock := wazerotest.NewModule(wazerotest.NewFixedMemory(wazerotest.PageSize))
ReadUint8(mock, 0)
t.Error("want panic")
}
func TestReadUint8_range(t *testing.T) {
defer func() { _ = recover() }()
mock := wazerotest.NewModule(wazerotest.NewFixedMemory(wazerotest.PageSize))
ReadUint8(mock, wazerotest.PageSize)
t.Error("want panic")
}
func TestReadUint32_nil(t *testing.T) {
defer func() { _ = recover() }()
mock := wazerotest.NewModule(wazerotest.NewFixedMemory(wazerotest.PageSize))
@@ -56,6 +70,20 @@ func TestReadUint64_range(t *testing.T) {
t.Error("want panic")
}
func TestWriteUint8_nil(t *testing.T) {
defer func() { _ = recover() }()
mock := wazerotest.NewModule(wazerotest.NewFixedMemory(wazerotest.PageSize))
WriteUint8(mock, 0, 1)
t.Error("want panic")
}
func TestWriteUint8_range(t *testing.T) {
defer func() { _ = recover() }()
mock := wazerotest.NewModule(wazerotest.NewFixedMemory(wazerotest.PageSize))
WriteUint8(mock, wazerotest.PageSize, 1)
t.Error("want panic")
}
func TestWriteUint32_nil(t *testing.T) {
defer func() { _ = recover() }()
mock := wazerotest.NewModule(wazerotest.NewFixedMemory(wazerotest.PageSize))

46
json.go Normal file
View File

@@ -0,0 +1,46 @@
package sqlite3
import (
"encoding/json"
"strconv"
"time"
"unsafe"
"github.com/ncruces/go-sqlite3/internal/util"
)
// JSON returns a value that can be used as an argument to
// [database/sql.DB.Exec], [database/sql.Row.Scan] and similar methods to
// store value as JSON, or decode JSON into value.
func JSON(value any) any {
return jsonValue{value}
}
type jsonValue struct{ any }
func (j jsonValue) JSON() any { return j.any }
func (j jsonValue) Scan(value any) error {
var buf []byte
switch v := value.(type) {
case []byte:
buf = v
case string:
buf = unsafe.Slice(unsafe.StringData(v), len(v))
case int64:
buf = strconv.AppendInt(nil, v, 10)
case float64:
buf = strconv.AppendFloat(nil, v, 'g', -1, 64)
case time.Time:
buf = append(buf, '"')
buf = v.AppendFormat(buf, time.RFC3339Nano)
buf = append(buf, '"')
case nil:
buf = append(buf, "null"...)
default:
panic(util.AssertErr())
}
return json.Unmarshal(buf, j.any)
}

352
module.go
View File

@@ -1,352 +0,0 @@
// Package sqlite3 wraps the C SQLite API.
package sqlite3
import (
"context"
"io"
"math"
"os"
"sync"
"github.com/ncruces/go-sqlite3/internal/util"
"github.com/ncruces/go-sqlite3/vfs"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
)
// Configure SQLite WASM.
//
// Importing package embed initializes these
// with an appropriate build of SQLite:
//
// import _ "github.com/ncruces/go-sqlite3/embed"
var (
Binary []byte // WASM binary to load.
Path string // Path to load the binary from.
)
var sqlite3 struct {
runtime wazero.Runtime
compiled wazero.CompiledModule
err error
once sync.Once
}
func instantiateModule() (*module, error) {
ctx := context.Background()
sqlite3.once.Do(compileModule)
if sqlite3.err != nil {
return nil, sqlite3.err
}
cfg := wazero.NewModuleConfig()
mod, err := sqlite3.runtime.InstantiateModule(ctx, sqlite3.compiled, cfg)
if err != nil {
return nil, err
}
return newModule(mod)
}
func compileModule() {
ctx := context.Background()
sqlite3.runtime = wazero.NewRuntime(ctx)
env := vfs.ExportHostFunctions(sqlite3.runtime.NewHostModuleBuilder("env"))
_, sqlite3.err = env.Instantiate(ctx)
if sqlite3.err != nil {
return
}
bin := Binary
if bin == nil && Path != "" {
bin, sqlite3.err = os.ReadFile(Path)
if sqlite3.err != nil {
return
}
}
if bin == nil {
sqlite3.err = util.BinaryErr
return
}
sqlite3.compiled, sqlite3.err = sqlite3.runtime.CompileModule(ctx, bin)
}
type module struct {
ctx context.Context
mod api.Module
vfs io.Closer
api sqliteAPI
arg [8]uint64
}
func newModule(mod api.Module) (m *module, err error) {
m = new(module)
m.mod = mod
m.ctx, m.vfs = vfs.NewContext(context.Background())
getFun := func(name string) api.Function {
f := mod.ExportedFunction(name)
if f == nil {
err = util.NoFuncErr + util.ErrorString(name)
return nil
}
return f
}
getVal := func(name string) uint32 {
g := mod.ExportedGlobal(name)
if g == nil {
err = util.NoGlobalErr + util.ErrorString(name)
return 0
}
return util.ReadUint32(mod, uint32(g.Get()))
}
m.api = sqliteAPI{
free: getFun("free"),
malloc: getFun("malloc"),
destructor: getVal("malloc_destructor"),
errcode: getFun("sqlite3_errcode"),
errstr: getFun("sqlite3_errstr"),
errmsg: getFun("sqlite3_errmsg"),
erroff: getFun("sqlite3_error_offset"),
open: getFun("sqlite3_open_v2"),
close: getFun("sqlite3_close"),
closeZombie: getFun("sqlite3_close_v2"),
prepare: getFun("sqlite3_prepare_v3"),
finalize: getFun("sqlite3_finalize"),
reset: getFun("sqlite3_reset"),
step: getFun("sqlite3_step"),
exec: getFun("sqlite3_exec"),
clearBindings: getFun("sqlite3_clear_bindings"),
bindCount: getFun("sqlite3_bind_parameter_count"),
bindIndex: getFun("sqlite3_bind_parameter_index"),
bindName: getFun("sqlite3_bind_parameter_name"),
bindNull: getFun("sqlite3_bind_null"),
bindInteger: getFun("sqlite3_bind_int64"),
bindFloat: getFun("sqlite3_bind_double"),
bindText: getFun("sqlite3_bind_text64"),
bindBlob: getFun("sqlite3_bind_blob64"),
bindZeroBlob: getFun("sqlite3_bind_zeroblob64"),
columnCount: getFun("sqlite3_column_count"),
columnName: getFun("sqlite3_column_name"),
columnType: getFun("sqlite3_column_type"),
columnInteger: getFun("sqlite3_column_int64"),
columnFloat: getFun("sqlite3_column_double"),
columnText: getFun("sqlite3_column_text"),
columnBlob: getFun("sqlite3_column_blob"),
columnBytes: getFun("sqlite3_column_bytes"),
blobOpen: getFun("sqlite3_blob_open"),
blobClose: getFun("sqlite3_blob_close"),
blobReopen: getFun("sqlite3_blob_reopen"),
blobBytes: getFun("sqlite3_blob_bytes"),
blobRead: getFun("sqlite3_blob_read"),
blobWrite: getFun("sqlite3_blob_write"),
backupInit: getFun("sqlite3_backup_init"),
backupStep: getFun("sqlite3_backup_step"),
backupFinish: getFun("sqlite3_backup_finish"),
backupRemaining: getFun("sqlite3_backup_remaining"),
backupPageCount: getFun("sqlite3_backup_pagecount"),
changes: getFun("sqlite3_changes64"),
lastRowid: getFun("sqlite3_last_insert_rowid"),
autocommit: getFun("sqlite3_get_autocommit"),
}
if err != nil {
return nil, err
}
return m, nil
}
func (m *module) close() error {
err := m.mod.Close(m.ctx)
m.vfs.Close()
return err
}
func (m *module) error(rc uint64, handle uint32, sql ...string) error {
if rc == _OK {
return nil
}
err := Error{code: rc}
if err.Code() == NOMEM || err.ExtendedCode() == IOERR_NOMEM {
panic(util.OOMErr)
}
if r := m.call(m.api.errstr, rc); r != 0 {
err.str = util.ReadString(m.mod, uint32(r), _MAX_STRING)
}
if r := m.call(m.api.errmsg, uint64(handle)); r != 0 {
err.msg = util.ReadString(m.mod, uint32(r), _MAX_STRING)
}
if sql != nil {
if r := m.call(m.api.erroff, uint64(handle)); r != math.MaxUint32 {
err.sql = sql[0][r:]
}
}
switch err.msg {
case err.str, "not an error":
err.msg = ""
}
return &err
}
func (m *module) call(fn api.Function, params ...uint64) uint64 {
copy(m.arg[:], params)
err := fn.CallWithStack(m.ctx, m.arg[:])
if err != nil {
// The module closed or panicked; release resources.
m.vfs.Close()
panic(err)
}
return m.arg[0]
}
func (m *module) free(ptr uint32) {
if ptr == 0 {
return
}
m.call(m.api.free, uint64(ptr))
}
func (m *module) new(size uint64) uint32 {
if size > _MAX_ALLOCATION_SIZE {
panic(util.OOMErr)
}
ptr := uint32(m.call(m.api.malloc, size))
if ptr == 0 && size != 0 {
panic(util.OOMErr)
}
return ptr
}
func (m *module) newBytes(b []byte) uint32 {
if b == nil {
return 0
}
ptr := m.new(uint64(len(b)))
util.WriteBytes(m.mod, ptr, b)
return ptr
}
func (m *module) newString(s string) uint32 {
ptr := m.new(uint64(len(s) + 1))
util.WriteString(m.mod, ptr, s)
return ptr
}
func (m *module) newArena(size uint64) arena {
return arena{
m: m,
base: m.new(size),
size: uint32(size),
}
}
type arena struct {
m *module
ptrs []uint32
base uint32
next uint32
size uint32
}
func (a *arena) free() {
if a.m == nil {
return
}
a.reset()
a.m.free(a.base)
a.m = nil
}
func (a *arena) reset() {
for _, ptr := range a.ptrs {
a.m.free(ptr)
}
a.ptrs = nil
a.next = 0
}
func (a *arena) new(size uint64) uint32 {
if size <= uint64(a.size-a.next) {
ptr := a.base + a.next
a.next += uint32(size)
return ptr
}
ptr := a.m.new(size)
a.ptrs = append(a.ptrs, ptr)
return ptr
}
func (a *arena) bytes(b []byte) uint32 {
if b == nil {
return 0
}
ptr := a.new(uint64(len(b)))
util.WriteBytes(a.m.mod, ptr, b)
return ptr
}
func (a *arena) string(s string) uint32 {
ptr := a.new(uint64(len(s) + 1))
util.WriteString(a.m.mod, ptr, s)
return ptr
}
type sqliteAPI struct {
free api.Function
malloc api.Function
errcode api.Function
errstr api.Function
errmsg api.Function
erroff api.Function
open api.Function
close api.Function
closeZombie api.Function
prepare api.Function
finalize api.Function
reset api.Function
step api.Function
exec api.Function
clearBindings api.Function
bindNull api.Function
bindCount api.Function
bindIndex api.Function
bindName api.Function
bindInteger api.Function
bindFloat api.Function
bindText api.Function
bindBlob api.Function
bindZeroBlob api.Function
columnCount api.Function
columnName api.Function
columnType api.Function
columnInteger api.Function
columnFloat api.Function
columnText api.Function
columnBlob api.Function
columnBytes api.Function
blobOpen api.Function
blobClose api.Function
blobReopen api.Function
blobBytes api.Function
blobRead api.Function
blobWrite api.Function
backupInit api.Function
backupStep api.Function
backupFinish api.Function
backupRemaining api.Function
backupPageCount api.Function
changes api.Function
lastRowid api.Function
autocommit api.Function
destructor uint32
}

14
pointer.go Normal file
View File

@@ -0,0 +1,14 @@
package sqlite3
// Pointer returns a pointer to a value
// that can be used as an argument to
// [database/sql.DB.Exec] and similar methods.
//
// https://sqlite.org/bindptr.html
func Pointer[T any](val T) any {
return pointer[T]{val}
}
type pointer[T any] struct{ val T }
func (p pointer[T]) Pointer() any { return p.val }

112
quote.go Normal file
View File

@@ -0,0 +1,112 @@
package sqlite3
import (
"bytes"
"math"
"strconv"
"strings"
"time"
"unsafe"
"github.com/ncruces/go-sqlite3/internal/util"
)
// Quote escapes and quotes a value
// making it safe to embed in SQL text.
func Quote(value any) string {
switch v := value.(type) {
case nil:
return "NULL"
case bool:
if v {
return "1"
} else {
return "0"
}
case int:
return strconv.Itoa(v)
case int64:
return strconv.FormatInt(v, 10)
case float64:
switch {
case math.IsNaN(v):
return "NULL"
case math.IsInf(v, 1):
return "9.0e999"
case math.IsInf(v, -1):
return "-9.0e999"
}
return strconv.FormatFloat(v, 'g', -1, 64)
case time.Time:
return "'" + v.Format(time.RFC3339Nano) + "'"
case string:
if strings.IndexByte(v, 0) >= 0 {
break
}
buf := make([]byte, 2+len(v)+strings.Count(v, "'"))
buf[0] = '\''
i := 1
for _, b := range []byte(v) {
if b == '\'' {
buf[i] = b
i += 1
}
buf[i] = b
i += 1
}
buf[i] = '\''
return unsafe.String(&buf[0], len(buf))
case []byte:
buf := make([]byte, 3+2*len(v))
buf[0] = 'x'
buf[1] = '\''
i := 2
for _, b := range v {
const hex = "0123456789ABCDEF"
buf[i+0] = hex[b/16]
buf[i+1] = hex[b%16]
i += 2
}
buf[i] = '\''
return unsafe.String(&buf[0], len(buf))
case ZeroBlob:
if v > ZeroBlob(1e9-3)/2 {
break
}
buf := bytes.Repeat([]byte("0"), int(3+2*int64(v)))
buf[0] = 'x'
buf[1] = '\''
buf[len(buf)-1] = '\''
return unsafe.String(&buf[0], len(buf))
}
panic(util.ValueErr)
}
// QuoteIdentifier escapes and quotes an identifier
// making it safe to embed in SQL text.
func QuoteIdentifier(id string) string {
if strings.IndexByte(id, 0) >= 0 {
panic(util.ValueErr)
}
buf := make([]byte, 2+len(id)+strings.Count(id, `"`))
buf[0] = '"'
i := 1
for _, b := range []byte(id) {
if b == '"' {
buf[i] = b
i += 1
}
buf[i] = b
i += 1
}
buf[i] = '"'
return unsafe.String(&buf[0], len(buf))
}

301
sqlite.go Normal file
View File

@@ -0,0 +1,301 @@
// Package sqlite3 wraps the C SQLite API.
package sqlite3
import (
"context"
"math"
"os"
"sync"
"github.com/ncruces/go-sqlite3/internal/util"
"github.com/ncruces/go-sqlite3/vfs"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
)
// Configure SQLite WASM.
//
// Importing package embed initializes these
// with an appropriate build of SQLite:
//
// import _ "github.com/ncruces/go-sqlite3/embed"
var (
Binary []byte // WASM binary to load.
Path string // Path to load the binary from.
RuntimeConfig wazero.RuntimeConfig
)
var instance struct {
runtime wazero.Runtime
compiled wazero.CompiledModule
err error
once sync.Once
}
func compileSQLite() {
if RuntimeConfig == nil {
RuntimeConfig = wazero.NewRuntimeConfig()
}
ctx := context.Background()
instance.runtime = wazero.NewRuntimeWithConfig(ctx, RuntimeConfig)
env := instance.runtime.NewHostModuleBuilder("env")
env = vfs.ExportHostFunctions(env)
env = exportCallbacks(env)
_, instance.err = env.Instantiate(ctx)
if instance.err != nil {
return
}
bin := Binary
if bin == nil && Path != "" {
bin, instance.err = os.ReadFile(Path)
if instance.err != nil {
return
}
}
if bin == nil {
instance.err = util.NoBinaryErr
return
}
instance.compiled, instance.err = instance.runtime.CompileModule(ctx, bin)
}
type sqlite struct {
ctx context.Context
mod api.Module
funcs [8]api.Function
stack [8]uint64
freer uint32
}
func instantiateSQLite() (sqlt *sqlite, err error) {
instance.once.Do(compileSQLite)
if instance.err != nil {
return nil, instance.err
}
sqlt = new(sqlite)
sqlt.ctx = util.NewContext(context.Background())
sqlt.mod, err = instance.runtime.InstantiateModule(sqlt.ctx,
instance.compiled, wazero.NewModuleConfig())
if err != nil {
return nil, err
}
global := sqlt.mod.ExportedGlobal("malloc_destructor")
if global == nil {
return nil, util.BadBinaryErr
}
sqlt.freer = util.ReadUint32(sqlt.mod, uint32(global.Get()))
if err != nil {
return nil, err
}
return sqlt, nil
}
func (sqlt *sqlite) close() error {
return sqlt.mod.Close(sqlt.ctx)
}
func (sqlt *sqlite) error(rc uint64, handle uint32, sql ...string) error {
if rc == _OK {
return nil
}
err := Error{code: rc}
if err.Code() == NOMEM || err.ExtendedCode() == IOERR_NOMEM {
panic(util.OOMErr)
}
if r := sqlt.call("sqlite3_errstr", rc); r != 0 {
err.str = util.ReadString(sqlt.mod, uint32(r), _MAX_NAME)
}
if handle != 0 {
if r := sqlt.call("sqlite3_errmsg", uint64(handle)); r != 0 {
err.msg = util.ReadString(sqlt.mod, uint32(r), _MAX_NAME)
}
if sql != nil {
if r := sqlt.call("sqlite3_error_offset", uint64(handle)); r != math.MaxUint32 {
err.sql = sql[0][r:]
}
}
}
switch err.msg {
case err.str, "not an error":
err.msg = ""
}
return &err
}
func (sqlt *sqlite) getfn(name string) (api.Function, uint32) {
// https://cr.yp.to/cdb/cdb.txt
hash := func(s string) uint32 {
var hash uint32 = 5381
for _, b := range []byte(s) {
hash = (hash<<5 + hash) ^ uint32(b)
}
return hash
}(name) % uint32(len(sqlt.funcs))
fn := sqlt.funcs[hash]
if fn == nil || name != fn.Definition().Name() {
fn = sqlt.mod.ExportedFunction(name)
} else {
sqlt.funcs[hash] = nil
}
return fn, hash
}
func (sqlt *sqlite) call(name string, params ...uint64) uint64 {
copy(sqlt.stack[:], params)
fn, hash := sqlt.getfn(name)
err := fn.CallWithStack(sqlt.ctx, sqlt.stack[:])
if err != nil {
panic(err)
}
sqlt.funcs[hash] = fn
return sqlt.stack[0]
}
func (sqlt *sqlite) free(ptr uint32) {
if ptr == 0 {
return
}
sqlt.call("free", uint64(ptr))
}
func (sqlt *sqlite) new(size uint64) uint32 {
if size > _MAX_ALLOCATION_SIZE {
panic(util.OOMErr)
}
ptr := uint32(sqlt.call("malloc", size))
if ptr == 0 && size != 0 {
panic(util.OOMErr)
}
return ptr
}
func (sqlt *sqlite) newBytes(b []byte) uint32 {
if (*[0]byte)(b) == nil {
return 0
}
ptr := sqlt.new(uint64(len(b)))
util.WriteBytes(sqlt.mod, ptr, b)
return ptr
}
func (sqlt *sqlite) newString(s string) uint32 {
ptr := sqlt.new(uint64(len(s) + 1))
util.WriteString(sqlt.mod, ptr, s)
return ptr
}
func (sqlt *sqlite) newArena(size uint64) arena {
return arena{
sqlt: sqlt,
size: uint32(size),
base: sqlt.new(size),
}
}
type arena struct {
sqlt *sqlite
ptrs []uint32
base uint32
next uint32
size uint32
}
func (a *arena) free() {
if a.sqlt == nil {
return
}
for _, ptr := range a.ptrs {
a.sqlt.free(ptr)
}
a.sqlt.free(a.base)
a.sqlt = nil
}
func (a *arena) mark() (reset func()) {
ptrs := len(a.ptrs)
next := a.next
return func() {
for _, ptr := range a.ptrs[ptrs:] {
a.sqlt.free(ptr)
}
a.ptrs = a.ptrs[:ptrs]
a.next = next
}
}
func (a *arena) new(size uint64) uint32 {
if size <= uint64(a.size-a.next) {
ptr := a.base + a.next
a.next += uint32(size)
return ptr
}
ptr := a.sqlt.new(size)
a.ptrs = append(a.ptrs, ptr)
return ptr
}
func (a *arena) bytes(b []byte) uint32 {
if b == nil {
return 0
}
ptr := a.new(uint64(len(b)))
util.WriteBytes(a.sqlt.mod, ptr, b)
return ptr
}
func (a *arena) string(s string) uint32 {
ptr := a.new(uint64(len(s) + 1))
util.WriteString(a.sqlt.mod, ptr, s)
return ptr
}
func exportCallbacks(env wazero.HostModuleBuilder) wazero.HostModuleBuilder {
util.ExportFuncII(env, "go_progress", progressCallback)
util.ExportFuncVI(env, "go_destroy", destroyCallback)
util.ExportFuncVIII(env, "go_func", funcCallback)
util.ExportFuncVIII(env, "go_step", stepCallback)
util.ExportFuncVI(env, "go_final", finalCallback)
util.ExportFuncVI(env, "go_value", valueCallback)
util.ExportFuncVIII(env, "go_inverse", inverseCallback)
util.ExportFuncIIIIII(env, "go_compare", compareCallback)
util.ExportFuncIIIIII(env, "go_vtab_create", vtabModuleCallback(0))
util.ExportFuncIIIIII(env, "go_vtab_connect", vtabModuleCallback(1))
util.ExportFuncII(env, "go_vtab_disconnect", vtabDisconnectCallback)
util.ExportFuncII(env, "go_vtab_destroy", vtabDestroyCallback)
util.ExportFuncIII(env, "go_vtab_best_index", vtabBestIndexCallback)
util.ExportFuncIIIII(env, "go_vtab_update", vtabUpdateCallback)
util.ExportFuncIII(env, "go_vtab_rename", vtabRenameCallback)
util.ExportFuncIIIII(env, "go_vtab_find_function", vtabFindFuncCallback)
util.ExportFuncII(env, "go_vtab_begin", vtabBeginCallback)
util.ExportFuncII(env, "go_vtab_sync", vtabSyncCallback)
util.ExportFuncII(env, "go_vtab_commit", vtabCommitCallback)
util.ExportFuncII(env, "go_vtab_rollback", vtabRollbackCallback)
util.ExportFuncIII(env, "go_vtab_savepoint", vtabSavepointCallback)
util.ExportFuncIII(env, "go_vtab_release", vtabReleaseCallback)
util.ExportFuncIII(env, "go_vtab_rollback_to", vtabRollbackToCallback)
util.ExportFuncIIIIII(env, "go_vtab_integrity", vtabIntegrityCallback)
util.ExportFuncIII(env, "go_cur_open", cursorOpenCallback)
util.ExportFuncII(env, "go_cur_close", cursorCloseCallback)
util.ExportFuncIIIIII(env, "go_cur_filter", cursorFilterCallback)
util.ExportFuncII(env, "go_cur_next", cursorNextCallback)
util.ExportFuncII(env, "go_cur_eof", cursorEOFCallback)
util.ExportFuncIIII(env, "go_cur_column", cursorColumnCallback)
util.ExportFuncIII(env, "go_cur_rowid", cursorRowIDCallback)
return env
}

1
sqlite3/.gitignore vendored
View File

@@ -1,3 +1,4 @@
ext/
sqlite3.c
sqlite3.h
sqlite3ext.h

View File

@@ -1,20 +0,0 @@
--- sqlite3.c.orig
+++ sqlite3.c
@@ -60425,7 +60425,7 @@
int rc = SQLITE_OK; /* Return code */
int tempFile = 0; /* True for temp files (incl. in-memory files) */
int memDb = 0; /* True if this is an in-memory file */
-#ifndef SQLITE_OMIT_DESERIALIZE
+#if 1
int memJM = 0; /* Memory journal mode */
#else
# define memJM 0
@@ -60628,7 +60628,7 @@
int fout = 0; /* VFS flags returned by xOpen() */
rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout);
assert( !memDb );
-#ifndef SQLITE_OMIT_DESERIALIZE
+#if 1
pPager->memVfs = memJM = (fout&SQLITE_OPEN_MEMORY)!=0;
#endif
readOnly = (fout&SQLITE_OPEN_READONLY)!=0;

View File

@@ -3,32 +3,33 @@ set -euo pipefail
cd -P -- "$(dirname -- "$0")"
curl -#OL "https://sqlite.org/2023/sqlite-amalgamation-3420000.zip"
curl -#OL "https://sqlite.org/2023/sqlite-amalgamation-3440200.zip"
unzip -d . sqlite-amalgamation-*.zip
mv sqlite-amalgamation-*/sqlite3* .
rm -rf sqlite-amalgamation-*
patch < vfs_find.patch
patch < deserialize.patch
cat *.patch | patch --no-backup-if-mismatch
mkdir -p ext/
cd ext/
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/ext/misc/decimal.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/ext/misc/uint.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/ext/misc/uuid.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/ext/misc/base64.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/ext/misc/regexp.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/ext/misc/series.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.44.2/ext/misc/decimal.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.44.2/ext/misc/uint.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.44.2/ext/misc/uuid.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.44.2/ext/misc/base64.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.44.2/ext/misc/regexp.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.44.2/ext/misc/series.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.44.2/ext/misc/anycollseq.c"
cd ~-
cd ../vfs/tests/mptest/testdata/
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/mptest/mptest.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/mptest/config01.test"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/mptest/config02.test"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/mptest/crash01.test"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/mptest/crash02.subtest"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/mptest/multiwrite01.test"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.44.2/mptest/mptest.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.44.2/mptest/config01.test"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.44.2/mptest/config02.test"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.44.2/mptest/crash01.test"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.44.2/mptest/crash02.subtest"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.44.2/mptest/multiwrite01.test"
cd ~-
cd ../vfs/tests/speedtest1/testdata/
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/test/speedtest1.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.44.2/test/speedtest1.c"
cd ~-

View File

@@ -1 +0,0 @@
*.c

44
sqlite3/func.c Normal file
View File

@@ -0,0 +1,44 @@
#include <stddef.h>
#include "include.h"
#include "sqlite3.h"
void go_func(sqlite3_context *, int, sqlite3_value **);
void go_step(sqlite3_context *, int, sqlite3_value **);
void go_final(sqlite3_context *);
void go_value(sqlite3_context *);
void go_inverse(sqlite3_context *, int, sqlite3_value **);
int go_compare(go_handle, int, const void *, int, const void *);
int sqlite3_create_collation_go(sqlite3 *db, const char *name, go_handle app) {
int rc = sqlite3_create_collation_v2(db, name, SQLITE_UTF8, app, go_compare,
go_destroy);
if (rc) go_destroy(app);
return rc;
}
int sqlite3_create_function_go(sqlite3 *db, const char *name, int argc,
int flags, go_handle app) {
return sqlite3_create_function_v2(db, name, argc, SQLITE_UTF8 | flags, app,
go_func, /*step=*/NULL, /*final=*/NULL,
go_destroy);
}
int sqlite3_create_aggregate_function_go(sqlite3 *db, const char *name,
int argc, int flags, go_handle app) {
return sqlite3_create_window_function(db, name, argc, SQLITE_UTF8 | flags,
app, go_step, go_final, /*value=*/NULL,
/*inverse=*/NULL, go_destroy);
}
int sqlite3_create_window_function_go(sqlite3 *db, const char *name, int argc,
int flags, go_handle app) {
return sqlite3_create_window_function(db, name, argc, SQLITE_UTF8 | flags,
app, go_step, go_final, go_value,
go_inverse, go_destroy);
}
void sqlite3_set_auxdata_go(sqlite3_context *ctx, int i, go_handle aux) {
sqlite3_set_auxdata(ctx, i, aux, go_destroy);
}

12
sqlite3/include.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include <assert.h>
#include <stddef.h>
// https://github.com/JuliaLang/julia/blob/v1.9.4/src/julia.h#L67-L68
#define container_of(ptr, type, member) \
((type *)((char *)(ptr)-offsetof(type, member)))
typedef void *go_handle;
void go_destroy(go_handle);
static_assert(sizeof(go_handle) == 4, "Unexpected size");

34
sqlite3/isoweek.patch Normal file
View File

@@ -0,0 +1,34 @@
# ISO week date specifiers.
# https://sqlite.org/forum/forumpost/73d99e4497e8e6a7
--- sqlite3.c.orig
+++ sqlite3.c
@@ -1373,6 +1373,29 @@ static void strftimeFunc(
sqlite3_str_appendchar(&sRes, 1, c);
break;
}
+ case 'V': /* Fall thru */
+ case 'G': {
+ DateTime y = x;
+ computeJD(&y);
+ y.validYMD = 0;
+ /* Adjust date to Thursday this week:
+ The number in parentheses is 0 for Monday, 3 for Thursday */
+ y.iJD += (3 - (((y.iJD+43200000)/86400000) % 7))*86400000;
+ computeYMD(&y);
+ if( cf=='G' ){
+ sqlite3_str_appendf(&sRes,"%04d",y.Y);
+ }else{
+ int nDay; /* Number of days since 1st day of year */
+ i64 tJD = y.iJD;
+ y.validJD = 0;
+ y.M = 1;
+ y.D = 1;
+ computeJD(&y);
+ nDay = (int)((tJD-y.iJD+43200000)/86400000);
+ sqlite3_str_appendf(&sRes,"%02d",nDay/7+1);
+ }
+ break;
+ }
case 'Y': {
sqlite3_str_appendf(&sRes,"%04d",x.Y);
break;

View File

@@ -0,0 +1,14 @@
# Use exclusive locking mode for WAL databases with v1 VFSes.
--- sqlite3.c.orig
+++ sqlite3.c
@@ -63210,7 +63210,9 @@
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);
+ if( pMethods->iVersion>=2 && pMethods->xShmMap ) return 1;
+ pPager->exclusiveMode = 1;
+ return 1;
}
/*

View File

@@ -1,20 +1,22 @@
#include <stdbool.h>
#include <stddef.h>
// Configuration
#include "sqlite_cfg.h"
// Amalgamation
#include "sqlite3.c"
// VFS
#include "vfs.c"
// Extensions
#include "ext/anycollseq.c"
#include "ext/base64.c"
#include "ext/decimal.c"
#include "ext/regexp.c"
#include "ext/series.c"
#include "ext/uint.c"
#include "ext/uuid.c"
// Bindings
#include "func.c"
#include "pointer.c"
#include "progress.c"
#include "time.c"
#include "vfs.c"
#include "vtab.c"
sqlite3_destructor_type malloc_destructor = &free;
__attribute__((constructor)) void init() {
sqlite3_initialize();
@@ -25,4 +27,4 @@ __attribute__((constructor)) void init() {
sqlite3_auto_extension((void (*)(void))sqlite3_uint_init);
sqlite3_auto_extension((void (*)(void))sqlite3_uuid_init);
sqlite3_auto_extension((void (*)(void))sqlite3_time_init);
}
}

17
sqlite3/pointer.c Normal file
View File

@@ -0,0 +1,17 @@
#include "include.h"
#include "sqlite3.h"
#define GO_POINTER_TYPE "github.com/ncruces/go-sqlite3.Pointer"
int sqlite3_bind_pointer_go(sqlite3_stmt *stmt, int i, go_handle app) {
return sqlite3_bind_pointer(stmt, i, app, GO_POINTER_TYPE, go_destroy);
}
void sqlite3_result_pointer_go(sqlite3_context *ctx, go_handle app) {
sqlite3_result_pointer(ctx, app, GO_POINTER_TYPE, go_destroy);
}
go_handle sqlite3_value_pointer_go(sqlite3_value *val) {
return sqlite3_value_pointer(val, GO_POINTER_TYPE);
}

9
sqlite3/progress.c Normal file
View File

@@ -0,0 +1,9 @@
#include <stddef.h>
#include "sqlite3.h"
int go_progress(void *);
void sqlite3_progress_handler_go(sqlite3 *db, int n) {
sqlite3_progress_handler(db, n, go_progress, /*arg=*/NULL);
}

View File

@@ -5,12 +5,28 @@
#define SQLITE_OS_OTHER 1
#define SQLITE_BYTEORDER 1234
#define HAVE_INT8_T 1
#define HAVE_INT16_T 1
#define HAVE_INT32_T 1
#define HAVE_INT64_T 1
#define HAVE_UINT8_T 1
#define HAVE_UINT16_T 1
#define HAVE_UINT32_T 1
#define HAVE_UINT64_T 1
#define HAVE_STDINT_H 1
#define HAVE_INTTYPES_H 1
#define HAVE_LOG2 1
#define HAVE_LOG10 1
#define HAVE_ISNAN 1
#define HAVE_USLEEP 1
#define HAVE_NANOSLEEP 1
#define HAVE_GMTIME_R 1
#define HAVE_LOCALTIME_S 1
#define HAVE_MALLOC_H 1
#define HAVE_MALLOC_USABLE_SIZE 1
// Recommended Options
@@ -21,27 +37,32 @@
#define SQLITE_DEFAULT_WAL_SYNCHRONOUS 1
#define SQLITE_LIKE_DOESNT_MATCH_BLOBS
#define SQLITE_MAX_EXPR_DEPTH 0
#define SQLITE_OMIT_DECLTYPE
#define SQLITE_USE_ALLOCA
#define SQLITE_OMIT_DEPRECATED
#define SQLITE_OMIT_PROGRESS_CALLBACK
#define SQLITE_OMIT_SHARED_CACHE
#define SQLITE_OMIT_AUTOINIT
#define SQLITE_USE_ALLOCA
// #define SQLITE_OMIT_DECLTYPE
// #define SQLITE_OMIT_PROGRESS_CALLBACK
// Other Options
#define SQLITE_ALLOW_URI_AUTHORITY
#define SQLITE_ENABLE_BATCH_ATOMIC_WRITE
#define SQLITE_TRUSTED_SCHEMA 0
#define SQLITE_DEFAULT_FOREIGN_KEYS 1
#define SQLITE_ENABLE_ATOMIC_WRITE
#define SQLITE_OMIT_DESERIALIZE
#define SQLITE_ENABLE_BATCH_ATOMIC_WRITE
// Because WASM does not support shared memory,
// SQLite disables WAL for WASM builds.
// We set the default locking mode to EXCLUSIVE instead.
// https://www.sqlite.org/wal.html#noshm
// We patch SQLite to use exclusive locking mode instead.
// https://sqlite.org/wal.html#noshm
#undef SQLITE_OMIT_WAL
#ifndef SQLITE_DEFAULT_LOCKING_MODE
#define SQLITE_DEFAULT_LOCKING_MODE 1
#endif
// We have our own memdb VFS.
// To avoid interactions between the two,
// omit sqlite3_serialize/sqlite3_deserialize,
// which we also don't wrap.
#define SQLITE_OMIT_DESERIALIZE
// Amalgamated Extensions
@@ -54,6 +75,8 @@
#define SQLITE_ENABLE_RTREE 1
#define SQLITE_ENABLE_GEOPOLY 1
#define SQLITE_SOUNDEX
// Session Extension
// #define SQLITE_ENABLE_SESSION
// #define SQLITE_ENABLE_PREUPDATE_HOOK

View File

@@ -1,3 +1,4 @@
#include <stddef.h>
#include <string.h>
#include "sqlite3.h"
@@ -26,7 +27,63 @@ static int time_collation(void *pArg, int nKey1, const void *pKey1, int nKey2,
return rc;
}
static void json_time_func(sqlite3_context *context, int argc,
sqlite3_value **argv) {
DateTime x;
if (isDate(context, argc, argv, &x)) return;
if (x.tzSet && x.tz) {
x.iJD += x.tz * 60000;
if (!validJulianDay(x.iJD)) return;
x.validYMD = 0;
x.validHMS = 0;
}
computeYMD_HMS(&x);
sqlite3 *db = sqlite3_context_db_handle(context);
sqlite3_str *res = sqlite3_str_new(db);
sqlite3_str_appendf(res, "%04d-%02d-%02dT%02d:%02d:%02d", //
x.Y, x.M, x.D, //
x.h, x.m, (int)(x.iJD / 1000 % 60));
if (x.useSubsec) {
int rem = x.iJD % 1000;
if (rem) {
sqlite3_str_appendchar(res, 1, '.');
sqlite3_str_appendchar(res, 1, '0' + rem / 100);
if ((rem %= 100)) {
sqlite3_str_appendchar(res, 1, '0' + rem / 10);
if ((rem %= 10)) {
sqlite3_str_appendchar(res, 1, '0' + rem);
}
}
}
}
if (x.tz) {
sqlite3_str_appendf(res, "%+03d:%02d", x.tz / 60, abs(x.tz) % 60);
} else {
sqlite3_str_appendchar(res, 1, 'Z');
}
int rc = sqlite3_str_errcode(res);
if (rc) {
sqlite3_result_error_code(context, rc);
return;
}
int n = sqlite3_str_length(res);
sqlite3_result_text(context, sqlite3_str_finish(res), n, sqlite3_free);
}
int sqlite3_time_init(sqlite3 *db, char **pzErrMsg,
const sqlite3_api_routines *pApi) {
return sqlite3_create_collation(db, "time", SQLITE_UTF8, 0, time_collation);
sqlite3_create_collation_v2(db, "time", SQLITE_UTF8, /*arg=*/NULL,
time_collation,
/*destroy=*/NULL);
sqlite3_create_function_v2(
db, "json_time", /*nArg=*/-1,
SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS, /*arg=*/NULL,
json_time_func, /*step=*/NULL, /*final=*/NULL, /*destroy=*/NULL);
return SQLITE_OK;
}

45
sqlite3/timezone.patch Normal file
View File

@@ -0,0 +1,45 @@
# Set UTC timezone, compute local offset.
--- sqlite3.c.orig
+++ sqlite3.c
@@ -340,6 +340,7 @@ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
p->iJD = sqlite3StmtCurrentTime(context);
if( p->iJD>0 ){
p->validJD = 1;
+ p->tzSet = 1;
return 0;
}else{
return 1;
@@ -355,6 +356,7 @@ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
static void setRawDateNumber(DateTime *p, double r){
p->s = r;
p->rawS = 1;
+ p->tzSet = 1;
if( r>=0.0 && r<5373484.5 ){
p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
p->validJD = 1;
@@ -731,7 +733,16 @@ static int parseModifier(
** show local time.
*/
if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){
- rc = toLocaltime(p, pCtx);
+ if( p->tzSet!=0 || p->tz==0 ) {
+ rc = toLocaltime(p, pCtx);
+ i64 iOrigJD = p->iJD;
+ p->tzSet = 0;
+ computeJD(p);
+ p->tz = (p->iJD-iOrigJD)/60000;
+ if( abs(p->tz)>= 900 ) p->tz = 0;
+ } else {
+ rc = 0;
+ }
}
break;
}
@@ -781,6 +792,7 @@ static int parseModifier(
p->validJD = 1;
p->tzSet = 1;
}
+ p->tz = 0;
rc = SQLITE_OK;
}
#endif

View File

@@ -1,5 +1,8 @@
#include <stdbool.h>
#include <stddef.h>
#include <time.h>
#include "include.h"
#include "sqlite3.h"
int go_localtime(struct tm *, sqlite3_int64);
@@ -7,7 +10,6 @@ int go_vfs_find(const char *zVfsName);
int go_randomness(sqlite3_vfs *, int nByte, char *zOut);
int go_sleep(sqlite3_vfs *, int microseconds);
int go_current_time(sqlite3_vfs *, double *);
int go_current_time_64(sqlite3_vfs *, sqlite3_int64 *);
int go_open(sqlite3_vfs *, sqlite3_filename zName, sqlite3_file *, int flags,
@@ -58,7 +60,7 @@ static int go_open_wrapper(sqlite3_vfs *vfs, sqlite3_filename zName,
struct go_file {
sqlite3_file base;
int handle;
go_handle handle;
};
int sqlite3_os_init() {
@@ -75,63 +77,59 @@ int sqlite3_os_init() {
.xRandomness = go_randomness,
.xSleep = go_sleep,
.xCurrentTime = go_current_time,
.xCurrentTimeInt64 = go_current_time_64,
};
return sqlite3_vfs_register(&os_vfs, /*default=*/true);
}
sqlite3_destructor_type malloc_destructor = &free;
int localtime_s(struct tm *const pTm, time_t const *const pTime) {
return go_localtime(pTm, (sqlite3_int64)*pTime);
}
sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName) {
if (zVfsName) {
if (zVfsName && go_vfs_find(zVfsName)) {
static sqlite3_vfs *go_vfs_list;
sqlite3_vfs *found = NULL;
for (sqlite3_vfs **next = &go_vfs_list; *next;) {
sqlite3_vfs *it = *next;
for (sqlite3_vfs *it = go_vfs_list; it; it = it->pNext) {
if (!strcmp(zVfsName, it->zName)) {
return it;
}
}
for (sqlite3_vfs **ptr = &go_vfs_list; *ptr;) {
sqlite3_vfs *it = *ptr;
if (go_vfs_find(it->zName)) {
if (!strcmp(zVfsName, it->zName)) found = it;
next = &it->pNext;
ptr = &it->pNext;
} else {
*next = it->pNext;
*ptr = it->pNext;
free(it);
}
}
if (found) {
return found;
}
if (go_vfs_find(zVfsName)) {
sqlite3_vfs *prev = go_vfs_list;
go_vfs_list = malloc(sizeof(sqlite3_vfs) + strlen(zVfsName) + 1);
char *name = (char *)(go_vfs_list + 1);
strcpy(name, zVfsName);
*go_vfs_list = (sqlite3_vfs){
.iVersion = 2,
.szOsFile = sizeof(struct go_file),
.mxPathname = 512,
.zName = name,
.pNext = prev,
.xOpen = go_open_wrapper,
.xDelete = go_delete,
.xAccess = go_access,
.xFullPathname = go_full_pathname,
sqlite3_vfs *head = go_vfs_list;
go_vfs_list = malloc(sizeof(sqlite3_vfs) + strlen(zVfsName) + 1);
char *name = (char *)(go_vfs_list + 1);
strcpy(name, zVfsName);
*go_vfs_list = (sqlite3_vfs){
.iVersion = 2,
.szOsFile = sizeof(struct go_file),
.mxPathname = 512,
.zName = name,
.pNext = head,
.xRandomness = go_randomness,
.xSleep = go_sleep,
.xCurrentTime = go_current_time,
.xCurrentTimeInt64 = go_current_time_64,
};
return go_vfs_list;
}
.xOpen = go_open_wrapper,
.xDelete = go_delete,
.xAccess = go_access,
.xFullPathname = go_full_pathname,
.xRandomness = go_randomness,
.xSleep = go_sleep,
.xCurrentTimeInt64 = go_current_time_64,
};
return go_vfs_list;
}
return sqlite3_vfs_find_orig(zVfsName);
}
static_assert(offsetof(struct go_file, handle) == 4, "Unexpected offset");
static_assert(offsetof(sqlite3_vfs, zName) == 16, "Unexpected offset");
static_assert(offsetof(sqlite3, u1.isInterrupted) == 280, "Unexpected offset");
static_assert(offsetof(struct go_file, handle) == 4, "Unexpected offset");

View File

@@ -1,3 +1,4 @@
# Wrap sqlite3_vfs_find.
--- sqlite3.c.orig
+++ sqlite3.c
@@ -25394,7 +25394,7 @@

230
sqlite3/vtab.c Normal file
View File

@@ -0,0 +1,230 @@
#include <stddef.h>
#include "include.h"
#include "sqlite3.h"
#define SQLITE_VTAB_CREATOR_GO /******/ 0x01
#define SQLITE_VTAB_DESTROYER_GO /****/ 0x02
#define SQLITE_VTAB_UPDATER_GO /******/ 0x04
#define SQLITE_VTAB_RENAMER_GO /******/ 0x08
#define SQLITE_VTAB_OVERLOADER_GO /***/ 0x10
#define SQLITE_VTAB_CHECKER_GO /******/ 0x20
#define SQLITE_VTAB_TX_GO /***********/ 0x40
#define SQLITE_VTAB_SAVEPOINTER_GO /**/ 0x80
int go_vtab_create(sqlite3_module *, int argc, const char *const *argv,
sqlite3_vtab **, char **pzErr);
int go_vtab_connect(sqlite3_module *, int argc, const char *const *argv,
sqlite3_vtab **, char **pzErr);
int go_vtab_disconnect(sqlite3_vtab *);
int go_vtab_destroy(sqlite3_vtab *);
int go_vtab_best_index(sqlite3_vtab *, sqlite3_index_info *);
int go_cur_open(sqlite3_vtab *, sqlite3_vtab_cursor **);
int go_cur_close(sqlite3_vtab_cursor *);
int go_cur_filter(sqlite3_vtab_cursor *, int idxNum, const char *idxStr,
int argc, sqlite3_value **argv);
int go_cur_next(sqlite3_vtab_cursor *);
int go_cur_eof(sqlite3_vtab_cursor *);
int go_cur_column(sqlite3_vtab_cursor *, sqlite3_context *, int);
int go_cur_rowid(sqlite3_vtab_cursor *, sqlite3_int64 *pRowid);
int go_vtab_update(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *);
int go_vtab_rename(sqlite3_vtab *, const char *zNew);
int go_vtab_find_function(sqlite3_vtab *, int nArg, const char *zName,
go_handle *pxFunc);
int go_vtab_begin(sqlite3_vtab *);
int go_vtab_sync(sqlite3_vtab *);
int go_vtab_commit(sqlite3_vtab *);
int go_vtab_rollback(sqlite3_vtab *);
int go_vtab_savepoint(sqlite3_vtab *, int);
int go_vtab_release(sqlite3_vtab *, int);
int go_vtab_rollback_to(sqlite3_vtab *, int);
int go_vtab_integrity(sqlite3_vtab *, const char *zSchema, const char *zTabName,
int mFlags, char **pzErr);
struct go_module {
go_handle handle;
sqlite3_module base;
};
struct go_vtab {
go_handle handle;
sqlite3_vtab base;
};
struct go_cursor {
go_handle handle;
sqlite3_vtab_cursor base;
};
static void go_mod_destroy(void *pAux) {
struct go_module *mod = pAux;
void *handle = mod->handle;
free(mod);
go_destroy(handle);
}
static int go_vtab_create_wrapper(sqlite3 *db, void *pAux, int argc,
const char *const *argv,
sqlite3_vtab **ppVTab, char **pzErr) {
struct go_vtab *vtab = calloc(1, sizeof(struct go_vtab));
if (vtab == NULL) return SQLITE_NOMEM;
*ppVTab = &vtab->base;
struct go_module *mod = pAux;
int rc = go_vtab_create(&mod->base, argc, argv, ppVTab, pzErr);
if (rc) {
if (*pzErr) *pzErr = sqlite3_mprintf("%s", *pzErr);
free(vtab);
}
return rc;
}
static int go_vtab_connect_wrapper(sqlite3 *db, void *pAux, int argc,
const char *const *argv,
sqlite3_vtab **ppVTab, char **pzErr) {
struct go_vtab *vtab = calloc(1, sizeof(struct go_vtab));
if (vtab == NULL) return SQLITE_NOMEM;
*ppVTab = &vtab->base;
struct go_module *mod = pAux;
int rc = go_vtab_connect(&mod->base, argc, argv, ppVTab, pzErr);
if (rc) {
free(vtab);
if (*pzErr) *pzErr = sqlite3_mprintf("%s", *pzErr);
}
return rc;
}
static int go_vtab_disconnect_wrapper(sqlite3_vtab *pVTab) {
struct go_vtab *vtab = container_of(pVTab, struct go_vtab, base);
int rc = go_vtab_disconnect(pVTab);
free(vtab);
return rc;
}
static int go_vtab_destroy_wrapper(sqlite3_vtab *pVTab) {
struct go_vtab *vtab = container_of(pVTab, struct go_vtab, base);
int rc = go_vtab_destroy(pVTab);
free(vtab);
return rc;
}
static int go_cur_open_wrapper(sqlite3_vtab *pVTab,
sqlite3_vtab_cursor **ppCursor) {
struct go_cursor *cur = calloc(1, sizeof(struct go_cursor));
if (cur == NULL) return SQLITE_NOMEM;
*ppCursor = &cur->base;
int rc = go_cur_open(pVTab, ppCursor);
if (rc) free(cur);
return rc;
}
static int go_cur_close_wrapper(sqlite3_vtab_cursor *pCursor) {
struct go_cursor *cur = container_of(pCursor, struct go_cursor, base);
int rc = go_cur_close(pCursor);
free(cur);
return rc;
}
static int go_vtab_find_function_wrapper(
sqlite3_vtab *pVTab, int nArg, const char *zName,
void (**pxFunc)(sqlite3_context *, int, sqlite3_value **), void **ppArg) {
struct go_vtab *vtab = container_of(pVTab, struct go_vtab, base);
go_handle handle;
int rc = go_vtab_find_function(pVTab, nArg, zName, &handle);
if (rc) {
*pxFunc = go_func;
*ppArg = handle;
}
return rc;
}
static int go_vtab_integrity_wrapper(sqlite3_vtab *pVTab, const char *zSchema,
const char *zTabName, int mFlags,
char **pzErr) {
int rc = go_vtab_integrity(pVTab, zSchema, zTabName, mFlags, pzErr);
if (rc && *pzErr) *pzErr = sqlite3_mprintf("%s", *pzErr);
return rc;
}
int sqlite3_create_module_go(sqlite3 *db, const char *zName, int flags,
go_handle handle) {
struct go_module *mod = malloc(sizeof(struct go_module));
if (mod == NULL) {
go_destroy(handle);
return SQLITE_NOMEM;
}
mod->handle = handle;
mod->base = (sqlite3_module){
.iVersion = 4,
.xConnect = go_vtab_connect_wrapper,
.xDisconnect = go_vtab_disconnect_wrapper,
.xBestIndex = go_vtab_best_index,
.xOpen = go_cur_open_wrapper,
.xClose = go_cur_close_wrapper,
.xFilter = go_cur_filter,
.xNext = go_cur_next,
.xEof = go_cur_eof,
.xColumn = go_cur_column,
.xRowid = go_cur_rowid,
};
if (flags & SQLITE_VTAB_CREATOR_GO) {
mod->base.xCreate = go_vtab_create_wrapper;
}
if (flags & SQLITE_VTAB_DESTROYER_GO) {
mod->base.xDestroy = go_vtab_destroy_wrapper;
}
if (flags & SQLITE_VTAB_UPDATER_GO) {
mod->base.xUpdate = go_vtab_update;
}
if (flags & SQLITE_VTAB_RENAMER_GO) {
mod->base.xRename = go_vtab_rename;
}
if (flags & SQLITE_VTAB_OVERLOADER_GO) {
mod->base.xFindFunction = go_vtab_find_function_wrapper;
}
if (flags & SQLITE_VTAB_CHECKER_GO) {
mod->base.xIntegrity = go_vtab_integrity_wrapper;
}
if (flags & SQLITE_VTAB_TX_GO) {
mod->base.xBegin = go_vtab_begin;
mod->base.xSync = go_vtab_sync;
mod->base.xCommit = go_vtab_commit;
mod->base.xRollback = go_vtab_rollback;
}
if (flags & SQLITE_VTAB_SAVEPOINTER_GO) {
mod->base.xSavepoint = go_vtab_savepoint;
mod->base.xRelease = go_vtab_release;
mod->base.xRollbackTo = go_vtab_rollback_to;
}
if (mod->base.xCreate && !mod->base.xDestroy) {
mod->base.xDestroy = mod->base.xDisconnect;
}
if (mod->base.xDestroy && !mod->base.xCreate) {
mod->base.xCreate = mod->base.xConnect;
}
return sqlite3_create_module_v2(db, zName, &mod->base, mod, go_mod_destroy);
}
int sqlite3_vtab_config_go(sqlite3 *db, int op, int constraint) {
return sqlite3_vtab_config(db, op, constraint);
}
static_assert(offsetof(struct go_module, base) == 4, "Unexpected offset");
static_assert(offsetof(struct go_vtab, base) == 4, "Unexpected offset");
static_assert(offsetof(struct go_cursor, base) == 4, "Unexpected offset");
static_assert(sizeof(struct sqlite3_index_info) == 72, "Unexpected size");
static_assert(sizeof(struct sqlite3_index_orderby) == 8, "Unexpected size");
static_assert(sizeof(struct sqlite3_index_constraint) == 12, "Unexpected size");
static_assert(sizeof(struct sqlite3_index_constraint_usage) == 8,
"Unexpected size");

View File

@@ -3,6 +3,7 @@ package sqlite3
import (
"bytes"
"math"
"os"
"testing"
"github.com/ncruces/go-sqlite3/internal/util"
@@ -12,67 +13,73 @@ func init() {
Path = "./embed/sqlite3.wasm"
}
func TestConn_error_OOM(t *testing.T) {
func Test_sqlite_error_OOM(t *testing.T) {
t.Parallel()
m, err := instantiateModule()
sqlite, err := instantiateSQLite()
if err != nil {
t.Fatal(err)
}
defer m.close()
defer sqlite.close()
defer func() { _ = recover() }()
m.error(uint64(NOMEM), 0)
sqlite.error(uint64(NOMEM), 0)
t.Error("want panic")
}
func TestConn_call_closed(t *testing.T) {
func Test_sqlite_call_closed(t *testing.T) {
t.Parallel()
m, err := instantiateModule()
sqlite, err := instantiateSQLite()
if err != nil {
t.Fatal(err)
}
m.close()
sqlite.close()
defer func() { _ = recover() }()
m.call(m.api.free)
sqlite.call("free")
t.Error("want panic")
}
func TestConn_new(t *testing.T) {
func Test_sqlite_new(t *testing.T) {
t.Parallel()
m, err := instantiateModule()
sqlite, err := instantiateSQLite()
if err != nil {
t.Fatal(err)
}
defer m.close()
defer sqlite.close()
t.Run("MaxUint32", func(t *testing.T) {
defer func() { _ = recover() }()
m.new(math.MaxUint32)
sqlite.new(math.MaxUint32)
t.Error("want panic")
})
t.Run("_MAX_ALLOCATION_SIZE", func(t *testing.T) {
if testing.Short() {
t.Skip("skipping in short mode")
}
if os.Getenv("CI") != "" {
t.Skip("skipping in CI")
}
defer func() { _ = recover() }()
m.new(_MAX_ALLOCATION_SIZE)
m.new(_MAX_ALLOCATION_SIZE)
sqlite.new(_MAX_ALLOCATION_SIZE)
sqlite.new(_MAX_ALLOCATION_SIZE)
t.Error("want panic")
})
}
func TestConn_newArena(t *testing.T) {
func Test_sqlite_newArena(t *testing.T) {
t.Parallel()
m, err := instantiateModule()
sqlite, err := instantiateSQLite()
if err != nil {
t.Fatal(err)
}
defer m.close()
defer sqlite.close()
arena := m.newArena(16)
arena := sqlite.newArena(16)
defer arena.free()
const title = "Lorem ipsum"
@@ -80,7 +87,7 @@ func TestConn_newArena(t *testing.T) {
if ptr == 0 {
t.Fatalf("got nullptr")
}
if got := util.ReadString(m.mod, ptr, math.MaxUint32); got != title {
if got := util.ReadString(sqlite.mod, ptr, math.MaxUint32); got != title {
t.Errorf("got %q, want %q", got, title)
}
@@ -89,7 +96,7 @@ func TestConn_newArena(t *testing.T) {
if ptr == 0 {
t.Fatalf("got nullptr")
}
if got := util.ReadString(m.mod, ptr, math.MaxUint32); got != body {
if got := util.ReadString(sqlite.mod, ptr, math.MaxUint32); got != body {
t.Errorf("got %q, want %q", got, body)
}
@@ -101,121 +108,130 @@ func TestConn_newArena(t *testing.T) {
if ptr == 0 {
t.Fatalf("got nullptr")
}
if got := util.View(m.mod, ptr, uint64(len(title))); string(got) != title {
if got := util.View(sqlite.mod, ptr, uint64(len(title))); string(got) != title {
t.Errorf("got %q, want %q", got, title)
}
arena.free()
}
func TestConn_newBytes(t *testing.T) {
func Test_sqlite_newBytes(t *testing.T) {
t.Parallel()
m, err := instantiateModule()
sqlite, err := instantiateSQLite()
if err != nil {
t.Fatal(err)
}
defer m.close()
defer sqlite.close()
ptr := m.newBytes(nil)
ptr := sqlite.newBytes(nil)
if ptr != 0 {
t.Errorf("got %#x, want nullptr", ptr)
}
buf := []byte("sqlite3")
ptr = m.newBytes(buf)
ptr = sqlite.newBytes(buf)
if ptr == 0 {
t.Fatal("got nullptr, want a pointer")
}
want := buf
if got := util.View(m.mod, ptr, uint64(len(want))); !bytes.Equal(got, want) {
if got := util.View(sqlite.mod, ptr, uint64(len(want))); !bytes.Equal(got, want) {
t.Errorf("got %q, want %q", got, want)
}
ptr = sqlite.newBytes(buf[:0])
if ptr == 0 {
t.Fatal("got nullptr, want a pointer")
}
if got := util.View(sqlite.mod, ptr, 0); got != nil {
t.Errorf("got %q, want nil", got)
}
}
func TestConn_newString(t *testing.T) {
func Test_sqlite_newString(t *testing.T) {
t.Parallel()
m, err := instantiateModule()
sqlite, err := instantiateSQLite()
if err != nil {
t.Fatal(err)
}
defer m.close()
defer sqlite.close()
ptr := m.newString("")
ptr := sqlite.newString("")
if ptr == 0 {
t.Error("got nullptr, want a pointer")
}
str := "sqlite3\000sqlite3"
ptr = m.newString(str)
ptr = sqlite.newString(str)
if ptr == 0 {
t.Fatal("got nullptr, want a pointer")
}
want := str + "\000"
if got := util.View(m.mod, ptr, uint64(len(want))); string(got) != want {
if got := util.View(sqlite.mod, ptr, uint64(len(want))); string(got) != want {
t.Errorf("got %q, want %q", got, want)
}
}
func TestConn_getString(t *testing.T) {
func Test_sqlite_getString(t *testing.T) {
t.Parallel()
m, err := instantiateModule()
sqlite, err := instantiateSQLite()
if err != nil {
t.Fatal(err)
}
defer m.close()
defer sqlite.close()
ptr := m.newString("")
ptr := sqlite.newString("")
if ptr == 0 {
t.Error("got nullptr, want a pointer")
}
str := "sqlite3" + "\000 drop this"
ptr = m.newString(str)
ptr = sqlite.newString(str)
if ptr == 0 {
t.Fatal("got nullptr, want a pointer")
}
want := "sqlite3"
if got := util.ReadString(m.mod, ptr, math.MaxUint32); got != want {
if got := util.ReadString(sqlite.mod, ptr, math.MaxUint32); got != want {
t.Errorf("got %q, want %q", got, want)
}
if got := util.ReadString(m.mod, ptr, 0); got != "" {
if got := util.ReadString(sqlite.mod, ptr, 0); got != "" {
t.Errorf("got %q, want empty", got)
}
func() {
defer func() { _ = recover() }()
util.ReadString(m.mod, ptr, uint32(len(want)/2))
util.ReadString(sqlite.mod, ptr, uint32(len(want)/2))
t.Error("want panic")
}()
func() {
defer func() { _ = recover() }()
util.ReadString(m.mod, 0, math.MaxUint32)
util.ReadString(sqlite.mod, 0, math.MaxUint32)
t.Error("want panic")
}()
}
func TestConn_free(t *testing.T) {
func Test_sqlite_free(t *testing.T) {
t.Parallel()
m, err := instantiateModule()
sqlite, err := instantiateSQLite()
if err != nil {
t.Fatal(err)
}
defer m.close()
defer sqlite.close()
m.free(0)
sqlite.free(0)
ptr := m.new(1)
ptr := sqlite.new(1)
if ptr == 0 {
t.Error("got nullptr, want a pointer")
}
m.free(ptr)
sqlite.free(ptr)
}

319
stmt.go
View File

@@ -1,7 +1,9 @@
package sqlite3
import (
"encoding/json"
"math"
"strconv"
"time"
"github.com/ncruces/go-sqlite3/internal/util"
@@ -9,7 +11,7 @@ import (
// Stmt is a prepared statement object.
//
// https://www.sqlite.org/c3ref/stmt.html
// https://sqlite.org/c3ref/stmt.html
type Stmt struct {
c *Conn
err error
@@ -20,33 +22,49 @@ type Stmt struct {
//
// It is safe to close a nil, zero or closed Stmt.
//
// https://www.sqlite.org/c3ref/finalize.html
// https://sqlite.org/c3ref/finalize.html
func (s *Stmt) Close() error {
if s == nil || s.handle == 0 {
return nil
}
r := s.c.call(s.c.api.finalize, uint64(s.handle))
r := s.c.call("sqlite3_finalize", uint64(s.handle))
s.handle = 0
return s.c.error(r)
}
// Conn returns the database connection to which the prepared statement belongs.
//
// https://sqlite.org/c3ref/db_handle.html
func (s *Stmt) Conn() *Conn {
return s.c
}
// ReadOnly returns true if and only if the statement
// makes no direct changes to the content of the database file.
//
// https://sqlite.org/c3ref/stmt_readonly.html
func (s *Stmt) ReadOnly() bool {
r := s.c.call("sqlite3_stmt_readonly", uint64(s.handle))
return r != 0
}
// Reset resets the prepared statement object.
//
// https://www.sqlite.org/c3ref/reset.html
// https://sqlite.org/c3ref/reset.html
func (s *Stmt) Reset() error {
r := s.c.call(s.c.api.reset, uint64(s.handle))
r := s.c.call("sqlite3_reset", uint64(s.handle))
s.err = nil
return s.c.error(r)
}
// ClearBindings resets all bindings on the prepared statement.
// Busy determines if a prepared statement has been reset.
//
// https://www.sqlite.org/c3ref/clear_bindings.html
func (s *Stmt) ClearBindings() error {
r := s.c.call(s.c.api.clearBindings, uint64(s.handle))
return s.c.error(r)
// https://sqlite.org/c3ref/stmt_busy.html
func (s *Stmt) Busy() bool {
r := s.c.call("sqlite3_stmt_busy", uint64(s.handle))
return r != 0
}
// Step evaluates the SQL statement.
@@ -57,16 +75,17 @@ func (s *Stmt) ClearBindings() error {
// If an error has occurred, Step returns false;
// call [Stmt.Err] or [Stmt.Reset] to get the error.
//
// https://www.sqlite.org/c3ref/step.html
// https://sqlite.org/c3ref/step.html
func (s *Stmt) Step() bool {
s.c.checkInterrupt()
r := s.c.call(s.c.api.step, uint64(s.handle))
if r == _ROW {
return true
}
if r == _DONE {
r := s.c.call("sqlite3_step", uint64(s.handle))
switch r {
case _ROW:
s.err = nil
} else {
return true
case _DONE:
s.err = nil
default:
s.err = s.c.error(r)
}
return false
@@ -75,7 +94,7 @@ func (s *Stmt) Step() bool {
// Err gets the last error occurred during [Stmt.Step].
// Err returns nil after [Stmt.Reset] is called.
//
// https://www.sqlite.org/c3ref/step.html
// https://sqlite.org/c3ref/step.html
func (s *Stmt) Err() error {
return s.err
}
@@ -88,11 +107,32 @@ func (s *Stmt) Exec() error {
return s.Reset()
}
// Status monitors the performance characteristics of prepared statements.
//
// https://sqlite.org/c3ref/stmt_status.html
func (s *Stmt) Status(op StmtStatus, reset bool) int {
var i uint64
if reset {
i = 1
}
r := s.c.call("sqlite3_stmt_status", uint64(s.handle),
uint64(op), i)
return int(r)
}
// ClearBindings resets all bindings on the prepared statement.
//
// https://sqlite.org/c3ref/clear_bindings.html
func (s *Stmt) ClearBindings() error {
r := s.c.call("sqlite3_clear_bindings", uint64(s.handle))
return s.c.error(r)
}
// BindCount returns the number of SQL parameters in the prepared statement.
//
// https://www.sqlite.org/c3ref/bind_parameter_count.html
// https://sqlite.org/c3ref/bind_parameter_count.html
func (s *Stmt) BindCount() int {
r := s.c.call(s.c.api.bindCount,
r := s.c.call("sqlite3_bind_parameter_count",
uint64(s.handle))
return int(r)
}
@@ -100,11 +140,11 @@ func (s *Stmt) BindCount() int {
// BindIndex returns the index of a parameter in the prepared statement
// given its name.
//
// https://www.sqlite.org/c3ref/bind_parameter_index.html
// https://sqlite.org/c3ref/bind_parameter_index.html
func (s *Stmt) BindIndex(name string) int {
defer s.c.arena.reset()
defer s.c.arena.mark()()
namePtr := s.c.arena.string(name)
r := s.c.call(s.c.api.bindIndex,
r := s.c.call("sqlite3_bind_parameter_index",
uint64(s.handle), uint64(namePtr))
return int(r)
}
@@ -112,16 +152,16 @@ func (s *Stmt) BindIndex(name string) int {
// BindName returns the name of a parameter in the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
// https://www.sqlite.org/c3ref/bind_parameter_name.html
// https://sqlite.org/c3ref/bind_parameter_name.html
func (s *Stmt) BindName(param int) string {
r := s.c.call(s.c.api.bindName,
r := s.c.call("sqlite3_bind_parameter_name",
uint64(s.handle), uint64(param))
ptr := uint32(r)
if ptr == 0 {
return ""
}
return util.ReadString(s.c.mod, ptr, _MAX_STRING)
return util.ReadString(s.c.mod, ptr, _MAX_NAME)
}
// BindBool binds a bool to the prepared statement.
@@ -129,18 +169,19 @@ func (s *Stmt) BindName(param int) string {
// SQLite does not have a separate boolean storage class.
// Instead, boolean values are stored as integers 0 (false) and 1 (true).
//
// https://www.sqlite.org/c3ref/bind_blob.html
// https://sqlite.org/c3ref/bind_blob.html
func (s *Stmt) BindBool(param int, value bool) error {
var i int64
if value {
return s.BindInt64(param, 1)
i = 1
}
return s.BindInt64(param, 0)
return s.BindInt64(param, i)
}
// BindInt binds an int to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
// https://www.sqlite.org/c3ref/bind_blob.html
// https://sqlite.org/c3ref/bind_blob.html
func (s *Stmt) BindInt(param int, value int) error {
return s.BindInt64(param, int64(value))
}
@@ -148,9 +189,9 @@ func (s *Stmt) BindInt(param int, value int) error {
// BindInt64 binds an int64 to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
// https://www.sqlite.org/c3ref/bind_blob.html
// https://sqlite.org/c3ref/bind_blob.html
func (s *Stmt) BindInt64(param int, value int64) error {
r := s.c.call(s.c.api.bindInteger,
r := s.c.call("sqlite3_bind_int64",
uint64(s.handle), uint64(param), uint64(value))
return s.c.error(r)
}
@@ -158,9 +199,9 @@ func (s *Stmt) BindInt64(param int, value int64) error {
// BindFloat binds a float64 to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
// https://www.sqlite.org/c3ref/bind_blob.html
// https://sqlite.org/c3ref/bind_blob.html
func (s *Stmt) BindFloat(param int, value float64) error {
r := s.c.call(s.c.api.bindFloat,
r := s.c.call("sqlite3_bind_double",
uint64(s.handle), uint64(param), math.Float64bits(value))
return s.c.error(r)
}
@@ -168,13 +209,32 @@ func (s *Stmt) BindFloat(param int, value float64) error {
// BindText binds a string to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
// https://www.sqlite.org/c3ref/bind_blob.html
// https://sqlite.org/c3ref/bind_blob.html
func (s *Stmt) BindText(param int, value string) error {
if len(value) > _MAX_LENGTH {
return TOOBIG
}
ptr := s.c.newString(value)
r := s.c.call(s.c.api.bindText,
r := s.c.call("sqlite3_bind_text64",
uint64(s.handle), uint64(param),
uint64(ptr), uint64(len(value)),
uint64(s.c.api.destructor), _UTF8)
uint64(s.c.freer), _UTF8)
return s.c.error(r)
}
// BindRawText binds a []byte to the prepared statement as text.
// The leftmost SQL parameter has an index of 1.
//
// https://sqlite.org/c3ref/bind_blob.html
func (s *Stmt) BindRawText(param int, value []byte) error {
if len(value) > _MAX_LENGTH {
return TOOBIG
}
ptr := s.c.newBytes(value)
r := s.c.call("sqlite3_bind_text64",
uint64(s.handle), uint64(param),
uint64(ptr), uint64(len(value)),
uint64(s.c.freer), _UTF8)
return s.c.error(r)
}
@@ -182,22 +242,25 @@ func (s *Stmt) BindText(param int, value string) error {
// The leftmost SQL parameter has an index of 1.
// Binding a nil slice is the same as calling [Stmt.BindNull].
//
// https://www.sqlite.org/c3ref/bind_blob.html
// https://sqlite.org/c3ref/bind_blob.html
func (s *Stmt) BindBlob(param int, value []byte) error {
if len(value) > _MAX_LENGTH {
return TOOBIG
}
ptr := s.c.newBytes(value)
r := s.c.call(s.c.api.bindBlob,
r := s.c.call("sqlite3_bind_blob64",
uint64(s.handle), uint64(param),
uint64(ptr), uint64(len(value)),
uint64(s.c.api.destructor))
uint64(s.c.freer))
return s.c.error(r)
}
// BindZeroBlob binds a zero-filled, length n BLOB to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
// https://www.sqlite.org/c3ref/bind_blob.html
// https://sqlite.org/c3ref/bind_blob.html
func (s *Stmt) BindZeroBlob(param int, n int64) error {
r := s.c.call(s.c.api.bindZeroBlob,
r := s.c.call("sqlite3_bind_zeroblob64",
uint64(s.handle), uint64(param), uint64(n))
return s.c.error(r)
}
@@ -205,9 +268,9 @@ func (s *Stmt) BindZeroBlob(param int, n int64) error {
// BindNull binds a NULL to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
// https://www.sqlite.org/c3ref/bind_blob.html
// https://sqlite.org/c3ref/bind_blob.html
func (s *Stmt) BindNull(param int) error {
r := s.c.call(s.c.api.bindNull,
r := s.c.call("sqlite3_bind_null",
uint64(s.handle), uint64(param))
return s.c.error(r)
}
@@ -215,7 +278,7 @@ func (s *Stmt) BindNull(param int) error {
// BindTime binds a [time.Time] to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
// https://www.sqlite.org/c3ref/bind_blob.html
// https://sqlite.org/c3ref/bind_blob.html
func (s *Stmt) BindTime(param int, value time.Time, format TimeFormat) error {
if format == TimeFormatDefault {
return s.bindRFC3339Nano(param, value)
@@ -234,24 +297,62 @@ func (s *Stmt) BindTime(param int, value time.Time, format TimeFormat) error {
}
func (s *Stmt) bindRFC3339Nano(param int, value time.Time) error {
const maxlen = uint64(len(time.RFC3339Nano))
const maxlen = uint64(len(time.RFC3339Nano)) + 5
ptr := s.c.new(maxlen)
buf := util.View(s.c.mod, ptr, maxlen)
buf = value.AppendFormat(buf[:0], time.RFC3339Nano)
r := s.c.call(s.c.api.bindText,
r := s.c.call("sqlite3_bind_text64",
uint64(s.handle), uint64(param),
uint64(ptr), uint64(len(buf)),
uint64(s.c.api.destructor), _UTF8)
uint64(s.c.freer), _UTF8)
return s.c.error(r)
}
// BindPointer binds a NULL to the prepared statement, just like [Stmt.BindNull],
// but it also associates ptr with that NULL value such that it can be retrieved
// within an application-defined SQL function using [Value.Pointer].
// The leftmost SQL parameter has an index of 1.
//
// https://sqlite.org/c3ref/bind_blob.html
func (s *Stmt) BindPointer(param int, ptr any) error {
valPtr := util.AddHandle(s.c.ctx, ptr)
r := s.c.call("sqlite3_bind_pointer_go",
uint64(s.handle), uint64(param), uint64(valPtr))
return s.c.error(r)
}
// BindJSON binds the JSON encoding of value to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
// https://sqlite.org/c3ref/bind_blob.html
func (s *Stmt) BindJSON(param int, value any) error {
data, err := json.Marshal(value)
if err != nil {
return err
}
return s.BindRawText(param, data)
}
// BindValue binds a copy of value to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
// https://sqlite.org/c3ref/bind_blob.html
func (s *Stmt) BindValue(param int, value Value) error {
if value.sqlite != s.c.sqlite {
return MISUSE
}
r := s.c.call("sqlite3_bind_value",
uint64(s.handle), uint64(param), uint64(value.handle))
return s.c.error(r)
}
// ColumnCount returns the number of columns in a result set.
//
// https://www.sqlite.org/c3ref/column_count.html
// https://sqlite.org/c3ref/column_count.html
func (s *Stmt) ColumnCount() int {
r := s.c.call(s.c.api.columnCount,
r := s.c.call("sqlite3_column_count",
uint64(s.handle))
return int(r)
}
@@ -259,35 +360,48 @@ func (s *Stmt) ColumnCount() int {
// ColumnName returns the name of the result column.
// The leftmost column of the result set has the index 0.
//
// https://www.sqlite.org/c3ref/column_name.html
// https://sqlite.org/c3ref/column_name.html
func (s *Stmt) ColumnName(col int) string {
r := s.c.call(s.c.api.columnName,
r := s.c.call("sqlite3_column_name",
uint64(s.handle), uint64(col))
ptr := uint32(r)
if ptr == 0 {
panic(util.OOMErr)
}
return util.ReadString(s.c.mod, ptr, _MAX_STRING)
return util.ReadString(s.c.mod, ptr, _MAX_NAME)
}
// ColumnType returns the initial [Datatype] of the result column.
// The leftmost column of the result set has the index 0.
//
// https://www.sqlite.org/c3ref/column_blob.html
// https://sqlite.org/c3ref/column_blob.html
func (s *Stmt) ColumnType(col int) Datatype {
r := s.c.call(s.c.api.columnType,
r := s.c.call("sqlite3_column_type",
uint64(s.handle), uint64(col))
return Datatype(r)
}
// ColumnDeclType returns the declared datatype of the result column.
// The leftmost column of the result set has the index 0.
//
// https://sqlite.org/c3ref/column_decltype.html
func (s *Stmt) ColumnDeclType(col int) string {
r := s.c.call("sqlite3_column_decltype",
uint64(s.handle), uint64(col))
if r == 0 {
return ""
}
return util.ReadString(s.c.mod, uint32(r), _MAX_NAME)
}
// ColumnBool returns the value of the result column as a bool.
// The leftmost column of the result set has the index 0.
// SQLite does not have a separate boolean storage class.
// Instead, boolean values are retrieved as integers,
// with 0 converted to false and any other value to true.
//
// https://www.sqlite.org/c3ref/column_blob.html
// https://sqlite.org/c3ref/column_blob.html
func (s *Stmt) ColumnBool(col int) bool {
if i := s.ColumnInt64(col); i != 0 {
return true
@@ -298,7 +412,7 @@ func (s *Stmt) ColumnBool(col int) bool {
// ColumnInt returns the value of the result column as an int.
// The leftmost column of the result set has the index 0.
//
// https://www.sqlite.org/c3ref/column_blob.html
// https://sqlite.org/c3ref/column_blob.html
func (s *Stmt) ColumnInt(col int) int {
return int(s.ColumnInt64(col))
}
@@ -306,9 +420,9 @@ func (s *Stmt) ColumnInt(col int) int {
// ColumnInt64 returns the value of the result column as an int64.
// The leftmost column of the result set has the index 0.
//
// https://www.sqlite.org/c3ref/column_blob.html
// https://sqlite.org/c3ref/column_blob.html
func (s *Stmt) ColumnInt64(col int) int64 {
r := s.c.call(s.c.api.columnInteger,
r := s.c.call("sqlite3_column_int64",
uint64(s.handle), uint64(col))
return int64(r)
}
@@ -316,9 +430,9 @@ func (s *Stmt) ColumnInt64(col int) int64 {
// ColumnFloat returns the value of the result column as a float64.
// The leftmost column of the result set has the index 0.
//
// https://www.sqlite.org/c3ref/column_blob.html
// https://sqlite.org/c3ref/column_blob.html
func (s *Stmt) ColumnFloat(col int) float64 {
r := s.c.call(s.c.api.columnFloat,
r := s.c.call("sqlite3_column_double",
uint64(s.handle), uint64(col))
return math.Float64frombits(r)
}
@@ -326,7 +440,7 @@ func (s *Stmt) ColumnFloat(col int) float64 {
// ColumnTime returns the value of the result column as a [time.Time].
// The leftmost column of the result set has the index 0.
//
// https://www.sqlite.org/c3ref/column_blob.html
// https://sqlite.org/c3ref/column_blob.html
func (s *Stmt) ColumnTime(col int, format TimeFormat) time.Time {
var v any
switch s.ColumnType(col) {
@@ -351,7 +465,7 @@ func (s *Stmt) ColumnTime(col int, format TimeFormat) time.Time {
// ColumnText returns the value of the result column as a string.
// The leftmost column of the result set has the index 0.
//
// https://www.sqlite.org/c3ref/column_blob.html
// https://sqlite.org/c3ref/column_blob.html
func (s *Stmt) ColumnText(col int) string {
return string(s.ColumnRawText(col))
}
@@ -360,7 +474,7 @@ func (s *Stmt) ColumnText(col int) string {
// the value of the result column as a []byte.
// The leftmost column of the result set has the index 0.
//
// https://www.sqlite.org/c3ref/column_blob.html
// https://sqlite.org/c3ref/column_blob.html
func (s *Stmt) ColumnBlob(col int, buf []byte) []byte {
return append(buf, s.ColumnRawBlob(col)...)
}
@@ -370,22 +484,11 @@ func (s *Stmt) ColumnBlob(col int, buf []byte) []byte {
// subsequent calls to [Stmt] methods.
// The leftmost column of the result set has the index 0.
//
// https://www.sqlite.org/c3ref/column_blob.html
// https://sqlite.org/c3ref/column_blob.html
func (s *Stmt) ColumnRawText(col int) []byte {
r := s.c.call(s.c.api.columnText,
r := s.c.call("sqlite3_column_text",
uint64(s.handle), uint64(col))
ptr := uint32(r)
if ptr == 0 {
r = s.c.call(s.c.api.errcode, uint64(s.c.handle))
s.err = s.c.error(r)
return nil
}
r = s.c.call(s.c.api.columnBytes,
uint64(s.handle), uint64(col))
return util.View(s.c.mod, ptr, r)
return s.columnRawBytes(col, uint32(r))
}
// ColumnRawBlob returns the value of the result column as a []byte.
@@ -393,35 +496,59 @@ func (s *Stmt) ColumnRawText(col int) []byte {
// subsequent calls to [Stmt] methods.
// The leftmost column of the result set has the index 0.
//
// https://www.sqlite.org/c3ref/column_blob.html
// https://sqlite.org/c3ref/column_blob.html
func (s *Stmt) ColumnRawBlob(col int) []byte {
r := s.c.call(s.c.api.columnBlob,
r := s.c.call("sqlite3_column_blob",
uint64(s.handle), uint64(col))
return s.columnRawBytes(col, uint32(r))
}
ptr := uint32(r)
func (s *Stmt) columnRawBytes(col int, ptr uint32) []byte {
if ptr == 0 {
r = s.c.call(s.c.api.errcode, uint64(s.c.handle))
r := s.c.call("sqlite3_errcode", uint64(s.c.handle))
s.err = s.c.error(r)
return nil
}
r = s.c.call(s.c.api.columnBytes,
r := s.c.call("sqlite3_column_bytes",
uint64(s.handle), uint64(col))
return util.View(s.c.mod, ptr, r)
}
// Return true if stmt is an empty SQL statement.
// This is used as an optimization.
// It's OK to always return false here.
func emptyStatement(stmt string) bool {
for _, b := range []byte(stmt) {
switch b {
case ' ', '\n', '\r', '\t', '\v', '\f':
case ';':
default:
return false
}
// ColumnJSON parses the JSON-encoded value of the result column
// and stores it in the value pointed to by ptr.
// The leftmost column of the result set has the index 0.
//
// https://sqlite.org/c3ref/column_blob.html
func (s *Stmt) ColumnJSON(col int, ptr any) error {
var data []byte
switch s.ColumnType(col) {
case NULL:
data = append(data, "null"...)
case TEXT:
data = s.ColumnRawText(col)
case BLOB:
data = s.ColumnRawBlob(col)
case INTEGER:
data = strconv.AppendInt(nil, s.ColumnInt64(col), 10)
case FLOAT:
data = strconv.AppendFloat(nil, s.ColumnFloat(col), 'g', -1, 64)
default:
panic(util.AssertErr())
}
return json.Unmarshal(data, ptr)
}
// ColumnValue returns the unprotected value of the result column.
// The leftmost column of the result set has the index 0.
//
// https://sqlite.org/c3ref/column_blob.html
func (s *Stmt) ColumnValue(col int) Value {
r := s.c.call("sqlite3_column_value",
uint64(s.handle), uint64(col))
return Value{
unprot: true,
sqlite: s.c.sqlite,
handle: uint32(r),
}
return true
}

Some files were not shown because too many files have changed in this diff Show More