feat: ✨ Added Sqlite reader
This commit is contained in:
32
vendor/modernc.org/sqlite/AUTHORS
generated
vendored
Normal file
32
vendor/modernc.org/sqlite/AUTHORS
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
# This file lists authors for copyright purposes. This file is distinct from
|
||||
# the CONTRIBUTORS files. See the latter for an explanation.
|
||||
#
|
||||
# Names should be added to this file as:
|
||||
# Name or Organization <email address>
|
||||
#
|
||||
# The email address is not required for organizations.
|
||||
#
|
||||
# Please keep the list sorted.
|
||||
|
||||
Angus Dippenaar <angusdippenaar@gmail.com>
|
||||
Artyom Pervukhin <github@artyom.dev>
|
||||
Dan Kortschak <dan@kortschak.io>
|
||||
Dan Peterson <danp@danp.net>
|
||||
David Walton <david@davidwalton.com>
|
||||
Davsk Ltd Co <skinner.david@gmail.com>
|
||||
FerretDB Inc.
|
||||
Harald Albrecht <thediveo@gmx.eu>
|
||||
Jaap Aarts <jaap.aarts1@gmail.com>
|
||||
Jan Mercl <0xjnml@gmail.com>
|
||||
Josh Bleecher Snyder <josharian@gmail.com>
|
||||
Josh Klein <josh.klein@outlook.com>
|
||||
Logan Snow <logansnow@protonmail.com>
|
||||
Michael Hoffmann <mhoffm@posteo.de>
|
||||
Michael Rykov <mrykov@gmail.com>
|
||||
Morgan Bazalgette <morgan@howl.moe>
|
||||
Ross Light <ross@zombiezen.com>
|
||||
Saed SayedAhmed <saadmtsa@gmail.com>
|
||||
Steffen Butzer <steffen(dot)butzer@outlook.com>
|
||||
Toni Spets <toni.spets@beeper.com>
|
||||
W. Michael Petullo <mike@flyn.org>
|
||||
SUSE LLC <moio@suse.com>
|
||||
104
vendor/modernc.org/sqlite/CHANGELOG.md
generated
vendored
Normal file
104
vendor/modernc.org/sqlite/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
# Changelog
|
||||
|
||||
- 2026-01-19 v1.44.3: Resolves [issue 243](https://gitlab.com/cznic/sqlite/-/issues/243).
|
||||
|
||||
- 2026-01-18 v1.44.2: Upgrade to [SQLite 3.51.2](https://sqlite.org/releaselog/3_51_2.html).
|
||||
|
||||
- 2026-01-13 v1.44.0: Upgrade to SQLite 3.51.1.
|
||||
|
||||
- 2025-10-10 v1.39.1: Upgrade to SQLite 3.50.4.
|
||||
|
||||
- 2025-06-09 v1.38.0: Upgrade to SQLite 3.50.1.
|
||||
|
||||
- 2025-02-26 v1.36.0: Upgrade to SQLite 3.49.0.
|
||||
|
||||
- 2024-11-16 v1.34.0: Implement ResetSession and IsValid methods in connection
|
||||
|
||||
- 2024-07-22 v1.31.0: Support windows/386.
|
||||
|
||||
- 2024-06-04 v1.30.0: Upgrade to SQLite 3.46.0, release notes at
|
||||
https://sqlite.org/releaselog/3_46_0.html.
|
||||
|
||||
- 2024-02-13 v1.29.0: Upgrade to SQLite 3.45.1, release notes at
|
||||
https://sqlite.org/releaselog/3_45_1.html.
|
||||
|
||||
- 2023-12-14: v1.28.0: Add (*Driver).RegisterConnectionHook,
|
||||
ConnectionHookFn, ExecQuerierContext, RegisterConnectionHook.
|
||||
|
||||
- 2023-08-03 v1.25.0: enable SQLITE_ENABLE_DBSTAT_VTAB.
|
||||
|
||||
- 2023-07-11 v1.24.0: Add
|
||||
(*conn).{Serialize,Deserialize,NewBackup,NewRestore} methods, add Backup
|
||||
type.
|
||||
|
||||
- 2023-06-01 v1.23.0: Allow registering aggregate functions.
|
||||
|
||||
- 2023-04-22 v1.22.0: Support linux/s390x.
|
||||
|
||||
- 2023-02-23 v1.21.0: Upgrade to SQLite 3.41.0, release notes at
|
||||
https://sqlite.org/releaselog/3_41_0.html.
|
||||
|
||||
- 2022-11-28 v1.20.0: Support linux/ppc64le.
|
||||
|
||||
- 2022-09-16 v1.19.0: Support frebsd/arm64.
|
||||
|
||||
- 2022-07-26 v1.18.0: Add support for Go fs.FS based SQLite virtual
|
||||
filesystems, see function New in modernc.org/sqlite/vfs and/or TestVFS in
|
||||
all_test.go
|
||||
|
||||
- 2022-04-24 v1.17.0: Support windows/arm64.
|
||||
|
||||
- 2022-04-04 v1.16.0: Support scalar application defined functions written
|
||||
in Go. See https://www.sqlite.org/appfunc.html
|
||||
|
||||
- 2022-03-13 v1.15.0: Support linux/riscv64.
|
||||
|
||||
- 2021-11-13 v1.14.0: Support windows/amd64. This target had previously
|
||||
only experimental status because of a now resolved memory leak.
|
||||
|
||||
- 2021-09-07 v1.13.0: Support freebsd/amd64.
|
||||
|
||||
- 2021-06-23 v1.11.0: Upgrade to use sqlite 3.36.0, release notes at
|
||||
https://www.sqlite.org/releaselog/3_36_0.html.
|
||||
|
||||
- 2021-05-06 v1.10.6: Fixes a memory corruption issue
|
||||
(https://gitlab.com/cznic/sqlite/-/issues/53). Versions since v1.8.6 were
|
||||
affected and should be updated to v1.10.6.
|
||||
|
||||
- 2021-03-14 v1.10.0: Update to use sqlite 3.35.0, release notes at
|
||||
https://www.sqlite.org/releaselog/3_35_0.html.
|
||||
|
||||
- 2021-03-11 v1.9.0: Support darwin/arm64.
|
||||
|
||||
- 2021-01-08 v1.8.0: Support darwin/amd64.
|
||||
|
||||
- 2020-09-13 v1.7.0: Support linux/arm and linux/arm64.
|
||||
|
||||
- 2020-09-08 v1.6.0: Support linux/386.
|
||||
|
||||
- 2020-09-03 v1.5.0: This project is now completely CGo-free, including
|
||||
the Tcl tests.
|
||||
|
||||
- 2020-08-26 v1.4.0: First stable release for linux/amd64. The
|
||||
database/sql driver and its tests are CGo free. Tests of the translated
|
||||
sqlite3.c library still require CGo.
|
||||
|
||||
- 2020-07-26 v1.4.0-beta1: The project has reached beta status while
|
||||
supporting linux/amd64 only at the moment. The 'extraquick' Tcl testsuite
|
||||
reports
|
||||
|
||||
- 2019-12-28 v1.2.0-alpha.3: Third alpha fixes issue #19.
|
||||
|
||||
- 2019-12-26 v1.1.0-alpha.2: Second alpha release adds support for
|
||||
accessing a database concurrently by multiple goroutines and/or processes.
|
||||
v1.1.0 is now considered feature-complete. Next planed release should be a
|
||||
beta with a proper test suite.
|
||||
|
||||
- 2019-12-18 v1.1.0-alpha.1: First alpha release using the new cc/v3,
|
||||
gocc, qbe toolchain. Some primitive tests pass on linux_{amd64,386}. Not
|
||||
yet safe for concurrent access by multiple goroutines. Next alpha release
|
||||
is planed to arrive before the end of this year.
|
||||
|
||||
- 2017-06-10: Windows/Intel no more uses the VM (thanks Steffen Butzer).
|
||||
|
||||
- 2017-06-05 Linux/Intel no more uses the VM (cznic/virtual).
|
||||
45
vendor/modernc.org/sqlite/CONTRIBUTORS
generated
vendored
Normal file
45
vendor/modernc.org/sqlite/CONTRIBUTORS
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
# This file lists people who contributed code to this repository. The AUTHORS
|
||||
# file lists the copyright holders; this file lists people.
|
||||
#
|
||||
# Names should be added to this file like so:
|
||||
# Name <email address>
|
||||
#
|
||||
# Please keep the list sorted.
|
||||
|
||||
Alexander Menzhinsky <amenzhinsky@gmail.com>
|
||||
Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
|
||||
Angus Dippenaar <angusdippenaar@gmail.com>
|
||||
Artyom Pervukhin <github@artyom.dev>
|
||||
Adrian Witas <adrianwit@gmail.com>
|
||||
Dan Kortschak <dan@kortschak.io>
|
||||
Dan Peterson <danp@danp.net>
|
||||
David Skinner <skinner.david@gmail.com>
|
||||
David Walton <david@davidwalton.com>
|
||||
Elle Mouton <elle.mouton@gmail.com>
|
||||
FlyingOnion <731677080@qq.com>
|
||||
Gleb Sakhnov <gleb.sakhnov@gmail.com>
|
||||
Guénaël Muller <inkey@inkey-art.net>
|
||||
Harald Albrecht <thediveo@gmx.eu>
|
||||
Jaap Aarts <jaap.aarts1@gmail.com>
|
||||
Jan Mercl <0xjnml@gmail.com>
|
||||
Josh Bleecher Snyder <josharian@gmail.com>
|
||||
Josh Klein <josh.klein@outlook.com>
|
||||
Kim <grufwub@gmail.com>
|
||||
Logan Snow <logansnow@protonmail.com>
|
||||
Mario Salgado <mariozalgo@gmail.com>
|
||||
Mark Summerfield <mark@qtrac.eu>
|
||||
Matthew Gabeler-Lee <fastcat@gmail.com>
|
||||
Michael Hoffmann <mhoffm@posteo.de>
|
||||
Michael Rykov <mrykov@gmail.com>
|
||||
Morgan Bazalgette <morgan@howl.moe>
|
||||
Romain Le Disez <r.gitlab@ledisez.net>
|
||||
Ross Light <ross@zombiezen.com>
|
||||
Saed SayedAhmed <saadmtsa@gmail.com>
|
||||
Sean McGivern <sean@mcgivern.me.uk>
|
||||
Steffen Butzer <steffen(dot)butzer@outlook.com>
|
||||
Toni Spets <toni.spets@beeper.com>
|
||||
W. Michael Petullo <mike@flyn.org>
|
||||
Walter Wanderley <walterwanderley@gmail.com>
|
||||
Yaacov Akiba Slama <ya@slamail.org>
|
||||
Prathyush PV <prathyush.pv@temporal.io>
|
||||
SUSE LLC <legal@suse.de>
|
||||
6
vendor/modernc.org/sqlite/HACKING.md
generated
vendored
Normal file
6
vendor/modernc.org/sqlite/HACKING.md
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
Please do not tag commits unless all builders at
|
||||
https://modern-c.appspot.com/-/builder/?importpath=modernc.org%2fsqlite are
|
||||
happy.
|
||||
|
||||
Since 2024-03-12 it should be no more necessary to manually tag releases at
|
||||
all as the repo is now set to be tagged automatically.
|
||||
26
vendor/modernc.org/sqlite/LICENSE
generated
vendored
Normal file
26
vendor/modernc.org/sqlite/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
Copyright (c) 2017 The Sqlite Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
86
vendor/modernc.org/sqlite/Makefile
generated
vendored
Normal file
86
vendor/modernc.org/sqlite/Makefile
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
# Copyright 2024 The Sqlite Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
.PHONY: all build_all_targets clean edit editor test vendor work
|
||||
|
||||
all: editor
|
||||
golint 2>&1
|
||||
staticcheck 2>&1
|
||||
|
||||
build_all_targets:
|
||||
GOOS=darwin GOARCH=amd64 go test -c -o /dev/null
|
||||
GOOS=darwin GOARCH=amd64 go build -v ./...
|
||||
GOOS=darwin GOARCH=arm64 go test -c -o /dev/null
|
||||
GOOS=darwin GOARCH=arm64 go build -v ./...
|
||||
GOOS=freebsd GOARCH=amd64 go test -c -o /dev/null
|
||||
GOOS=freebsd GOARCH=amd64 go build -v ./...
|
||||
# GOOS=freebsd GOARCH=386 go test -c -o /dev/null
|
||||
# GOOS=freebsd GOARCH=386 go build -v ./...
|
||||
# GOOS=freebsd GOARCH=arm go test -c -o /dev/null
|
||||
# GOOS=freebsd GOARCH=arm go build -v ./...
|
||||
GOOS=freebsd GOARCH=arm64 go test -c -o /dev/null
|
||||
GOOS=freebsd GOARCH=arm64 go build -v ./...
|
||||
GOOS=linux GOARCH=386 go test -c -o /dev/null
|
||||
GOOS=linux GOARCH=386 go build -v ./...
|
||||
GOOS=linux GOARCH=amd64 go test -c -o /dev/null
|
||||
GOOS=linux GOARCH=amd64 go build -v ./...
|
||||
GOOS=linux GOARCH=arm go test -c -o /dev/null
|
||||
GOOS=linux GOARCH=arm go build -v ./...
|
||||
GOOS=linux GOARCH=arm64 go test -c -o /dev/null
|
||||
GOOS=linux GOARCH=arm64 go build -v ./...
|
||||
GOOS=linux GOARCH=loong64 go test -c -o /dev/null
|
||||
GOOS=linux GOARCH=loong64 go build -v ./...
|
||||
GOOS=linux GOARCH=ppc64le go test -c -o /dev/null
|
||||
GOOS=linux GOARCH=ppc64le go build -v ./...
|
||||
GOOS=linux GOARCH=riscv64 go test -c -o /dev/null
|
||||
GOOS=linux GOARCH=riscv64 go build -v ./...
|
||||
GOOS=linux GOARCH=s390x go test -c -o /dev/null
|
||||
GOOS=linux GOARCH=s390x go build -v ./...
|
||||
# GOOS=netbsd GOARCH=amd64 go test -c -o /dev/null
|
||||
# GOOS=netbsd GOARCH=amd64 go build -v ./...
|
||||
GOOS=openbsd GOARCH=amd64 go test -c -o /dev/null
|
||||
GOOS=openbsd GOARCH=amd64 go build -v ./...
|
||||
GOOS=openbsd GOARCH=arm64 go test -c -o /dev/null
|
||||
GOOS=openbsd GOARCH=arm64 go build -v ./...
|
||||
GOOS=windows GOARCH=386 go test -c -o /dev/null
|
||||
GOOS=windows GOARCH=386 go build -v ./...
|
||||
GOOS=windows GOARCH=amd64 go test -c -o /dev/null
|
||||
GOOS=windows GOARCH=amd64 go build -v ./...
|
||||
GOOS=windows GOARCH=arm64 go test -c -o /dev/null
|
||||
GOOS=windows GOARCH=arm64 go build -v ./...
|
||||
echo done
|
||||
|
||||
clean:
|
||||
rm -f log-* cpu.test mem.test *.out go.work*
|
||||
go clean
|
||||
|
||||
edit:
|
||||
@if [ -f "Session.vim" ]; then gvim -S & else gvim -p Makefile go.mod builder.json all_test.go & fi
|
||||
|
||||
editor:
|
||||
go test -c -o /dev/null
|
||||
go build -v -o /dev/null ./...
|
||||
cd vendor_libsqlite3 && go build -o /dev/null main.go
|
||||
|
||||
test:
|
||||
go test -v -timeout 24h
|
||||
|
||||
vendor:
|
||||
cd vendor_libsqlite3 && go build -o ../vendor main.go
|
||||
./vendor
|
||||
rm -f vendor
|
||||
make build_all_targets
|
||||
make build_all_targets
|
||||
|
||||
work:
|
||||
rm -f go.work*
|
||||
go work init
|
||||
go work use .
|
||||
go work use ../cc/v4
|
||||
go work use ../ccgo/v3
|
||||
go work use ../ccgo/v4
|
||||
go work use ../libc
|
||||
go work use ../libtcl8.6
|
||||
go work use ../libsqlite3
|
||||
go work use ../libz
|
||||
62
vendor/modernc.org/sqlite/README.md
generated
vendored
Normal file
62
vendor/modernc.org/sqlite/README.md
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
## Important: Repository Mirroring
|
||||
|
||||
**This project is primarily developed on GitLab.** The repository you are currently viewing might be a mirror. Please review the guidelines below based on where you are viewing this:
|
||||
|
||||
| Platform | Role | Contributing Guidelines |
|
||||
| :--- | :--- | :--- |
|
||||
| **GitLab** | **Primary Source** | This is the canonical repository (`cznic/sqlite`). CI pipelines and main development happen here. |
|
||||
| **GitHub** | **Mirror** | This is a mirror (`modernc-org/sqlite`). We **do accept** Issues and Pull Requests here for your convenience! <br> *Note: PRs submitted here will be manually merged into the GitLab source, so please allow extra time for processing.* |
|
||||
|
||||
[](https://pkg.go.dev/modernc.org/sqlite)
|
||||
[](https://liberapay.com/jnml/donate)
|
||||
[](https://liberapay.com/jnml/donate)
|
||||
[](https://liberapay.com/jnml/donate)
|
||||
|
||||
---
|
||||
|
||||

|
||||
[Github Sponsors Account](https://github.com/sponsors/j-modernc-org) / j-modernc-org
|
||||
|
||||
### Enterprise Infrastructure Tier Sponsor
|
||||
|
||||
 [Tailscale](https://tailscale.com/)
|
||||
|
||||
### Startup / Small Business Tier Sponsor
|
||||
|
||||
 [October Swimmer](https://www.octoberswimmer.com/)
|
||||
|
||||
---
|
||||
|
||||
 [The SQLite Drivers Benchmarks Game]
|
||||
|
||||
[The SQLite Drivers Benchmarks Game]: https://pkg.go.dev/modernc.org/sqlite-bench#readme-tl-dr-scorecard
|
||||
|
||||
---
|
||||
|
||||
Virtual Tables (vtab)
|
||||
---------------------
|
||||
|
||||
The driver exposes a Go API to implement SQLite virtual table modules in pure Go via the `modernc.org/sqlite/vtab` package. This lets you back SQL tables with arbitrary data sources (e.g., vector indexes, CSV files, remote APIs) and integrate with SQLite’s planner.
|
||||
|
||||
- Register: `vtab.RegisterModule(db, name, module)`. Registration applies to new connections only.
|
||||
- Schema declaration: Call `ctx.Declare("CREATE TABLE <name>(<cols...>)")` within `Create` or `Connect`. The driver does not auto-declare schemas, enabling dynamic schemas.
|
||||
- Module arguments: `args []string` passed to `Create/Connect` are configuration parsed from `USING module(...)`. They are not treated as columns unless your module chooses to.
|
||||
- Planning (BestIndex):
|
||||
- Inspect `info.Constraints` (with `Column`, `Op`, `Usable`, 0-based `ArgIndex`, and `Omit`), `info.OrderBy`, and `info.ColUsed` (bitmask of referenced columns).
|
||||
- Set `ArgIndex` (0-based) to populate `Filter`’s `vals` in the chosen order; set `Omit` to ask SQLite not to re-check a constraint you fully handle.
|
||||
- Execution: `Cursor.Filter(idxNum, idxStr, vals)` receives arguments in the order implied by `ArgIndex`.
|
||||
- Operators: Common SQLite operators map to `ConstraintOp` (EQ/NE/GT/GE/LT/LE/MATCH/IS/ISNOT/ISNULL/ISNOTNULL/LIKE/GLOB/REGEXP/FUNCTION/LIMIT/OFFSET). Unknown operators map to `OpUnknown`.
|
||||
- Errors: Returning an error from vtab methods surfaces a descriptive message to SQLite (e.g., `zErrMsg` for xCreate/xConnect/xBestIndex/xFilter; `sqlite3_result_error` for xColumn).
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
- Vector search (sqlite-vec style):
|
||||
- `CREATE VIRTUAL TABLE vec_docs USING vec(dim=128, metric="cosine")`
|
||||
- Module reads args (e.g., `dim`, `metric`), calls `ctx.Declare("CREATE TABLE vec_docs(id, embedding, content HIDDEN)")`, and implements search via `BestIndex`/`Filter`.
|
||||
|
||||
- CSV loader:
|
||||
- `CREATE VIRTUAL TABLE csv_users USING csv(filename="/tmp/users.csv", delimiter=",", header=true)`
|
||||
- Module reads the file header to compute columns, declares them via `ctx.Declare("CREATE TABLE csv_users(name, email, ...)")`, and streams rows via a cursor.
|
||||
|
||||
See `vtab` package docs for full API details.
|
||||
25
vendor/modernc.org/sqlite/SQLITE-LICENSE
generated
vendored
Normal file
25
vendor/modernc.org/sqlite/SQLITE-LICENSE
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
SQLite Is Public Domain
|
||||
|
||||
All of the code and documentation in SQLite has been dedicated to the public
|
||||
domain by the authors. All code authors, and representatives of the companies
|
||||
they work for, have signed affidavits dedicating their contributions to the
|
||||
public domain and originals of those signed affidavits are stored in a firesafe
|
||||
at the main offices of Hwaci. Anyone is free to copy, modify, publish, use,
|
||||
compile, sell, or distribute the original SQLite code, either in source code
|
||||
form or as a compiled binary, for any purpose, commercial or non-commercial,
|
||||
and by any means.
|
||||
|
||||
The previous paragraph applies to the deliverable code and documentation in
|
||||
SQLite - those parts of the SQLite library that you actually bundle and ship
|
||||
with a larger application. Some scripts used as part of the build process (for
|
||||
example the "configure" scripts generated by autoconf) might fall under other
|
||||
open-source licenses. Nothing from these build scripts ever reaches the final
|
||||
deliverable SQLite library, however, and so the licenses associated with those
|
||||
scripts should not be a factor in assessing your rights to copy and use the
|
||||
SQLite library.
|
||||
|
||||
All of the deliverable code in SQLite has been written from scratch. No code
|
||||
has been taken from other projects or from the open internet. Every line of
|
||||
code can be traced back to its original author, and all of those authors have
|
||||
public domain dedications on file. So the SQLite code base is clean and is
|
||||
uncontaminated with licensed code from other projects.
|
||||
65
vendor/modernc.org/sqlite/backup.go
generated
vendored
Normal file
65
vendor/modernc.org/sqlite/backup.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright 2025 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite // import "modernc.org/sqlite"
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
|
||||
sqlite3 "modernc.org/sqlite/lib"
|
||||
)
|
||||
|
||||
// Backup object is used to manage progress and cleanup an online backup. It
|
||||
// is returned by NewBackup or NewRestore.
|
||||
type Backup struct {
|
||||
srcConn *conn // source database connection
|
||||
dstConn *conn // destination database connection
|
||||
pBackup uintptr // sqlite3_backup object pointer
|
||||
}
|
||||
|
||||
// Step will copy up to n pages between the source and destination databases
|
||||
// specified by the backup object. If n is negative, all remaining source
|
||||
// pages are copied.
|
||||
// If it successfully copies n pages and there are still more pages to be
|
||||
// copied, then the function returns true with no error. If it successfully
|
||||
// finishes copying all pages from source to destination, then it returns
|
||||
// false with no error. If an error occurs while running, then an error is
|
||||
// returned.
|
||||
func (b *Backup) Step(n int32) (bool, error) {
|
||||
rc := sqlite3.Xsqlite3_backup_step(b.srcConn.tls, b.pBackup, n)
|
||||
if rc == sqlite3.SQLITE_OK {
|
||||
return true, nil
|
||||
} else if rc == sqlite3.SQLITE_DONE {
|
||||
return false, nil
|
||||
} else {
|
||||
return false, b.srcConn.errstr(rc)
|
||||
}
|
||||
}
|
||||
|
||||
// Finish releases all resources associated with the Backup object. The Backup
|
||||
// object is invalid and may not be used following a call to Finish.
|
||||
func (b *Backup) Finish() error {
|
||||
rc := sqlite3.Xsqlite3_backup_finish(b.srcConn.tls, b.pBackup)
|
||||
b.dstConn.Close()
|
||||
if rc == sqlite3.SQLITE_OK {
|
||||
return nil
|
||||
} else {
|
||||
return b.srcConn.errstr(rc)
|
||||
}
|
||||
}
|
||||
|
||||
// Commit releases all resources associated with the Backup object but does not
|
||||
// close the destination database connection.
|
||||
//
|
||||
// The destination database connection is returned to the caller or an error if raised.
|
||||
// It is the responsibility of the caller to handle the connection closure.
|
||||
func (b *Backup) Commit() (driver.Conn, error) {
|
||||
rc := sqlite3.Xsqlite3_backup_finish(b.srcConn.tls, b.pBackup)
|
||||
|
||||
if rc == sqlite3.SQLITE_OK {
|
||||
return b.dstConn, nil
|
||||
} else {
|
||||
return nil, b.srcConn.errstr(rc)
|
||||
}
|
||||
}
|
||||
BIN
vendor/modernc.org/sqlite/bench.png
generated
vendored
Normal file
BIN
vendor/modernc.org/sqlite/bench.png
generated
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
6
vendor/modernc.org/sqlite/builder.json
generated
vendored
Normal file
6
vendor/modernc.org/sqlite/builder.json
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"autogen": "<none>",
|
||||
"autotag": "<none>",
|
||||
"autoupdate": "<none>",
|
||||
"test": "darwin/(amd64|arm64)|freebsd/(amd64|arm64)|linux/(386|amd64|arm|arm64|loong64|ppc64le|riscv64|s390x)|openbsd/(amd64|arm64)|windows/(amd64|arm64|386)"
|
||||
}
|
||||
1100
vendor/modernc.org/sqlite/conn.go
generated
vendored
Normal file
1100
vendor/modernc.org/sqlite/conn.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
299
vendor/modernc.org/sqlite/convert.go
generated
vendored
Normal file
299
vendor/modernc.org/sqlite/convert.go
generated
vendored
Normal file
@@ -0,0 +1,299 @@
|
||||
// Extracted from Go database/sql source code
|
||||
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Type conversions for Scan.
|
||||
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
|
||||
|
||||
// convertAssign copies to dest the value in src, converting it if possible.
|
||||
// An error is returned if the copy would result in loss of information.
|
||||
// dest should be a pointer type.
|
||||
func convertAssign(dest, src interface{}) error {
|
||||
// Common cases, without reflect.
|
||||
switch s := src.(type) {
|
||||
case string:
|
||||
switch d := dest.(type) {
|
||||
case *string:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = s
|
||||
return nil
|
||||
case *[]byte:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = []byte(s)
|
||||
return nil
|
||||
case *sql.RawBytes:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = append((*d)[:0], s...)
|
||||
return nil
|
||||
}
|
||||
case []byte:
|
||||
switch d := dest.(type) {
|
||||
case *string:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = string(s)
|
||||
return nil
|
||||
case *interface{}:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = cloneBytes(s)
|
||||
return nil
|
||||
case *[]byte:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = cloneBytes(s)
|
||||
return nil
|
||||
case *sql.RawBytes:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = s
|
||||
return nil
|
||||
}
|
||||
case time.Time:
|
||||
switch d := dest.(type) {
|
||||
case *time.Time:
|
||||
*d = s
|
||||
return nil
|
||||
case *string:
|
||||
*d = s.Format(time.RFC3339Nano)
|
||||
return nil
|
||||
case *[]byte:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = []byte(s.Format(time.RFC3339Nano))
|
||||
return nil
|
||||
case *sql.RawBytes:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = s.AppendFormat((*d)[:0], time.RFC3339Nano)
|
||||
return nil
|
||||
}
|
||||
case nil:
|
||||
switch d := dest.(type) {
|
||||
case *interface{}:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = nil
|
||||
return nil
|
||||
case *[]byte:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = nil
|
||||
return nil
|
||||
case *sql.RawBytes:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = nil
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var sv reflect.Value
|
||||
|
||||
switch d := dest.(type) {
|
||||
case *string:
|
||||
sv = reflect.ValueOf(src)
|
||||
switch sv.Kind() {
|
||||
case reflect.Bool,
|
||||
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||
reflect.Float32, reflect.Float64:
|
||||
*d = asString(src)
|
||||
return nil
|
||||
}
|
||||
case *[]byte:
|
||||
sv = reflect.ValueOf(src)
|
||||
if b, ok := asBytes(nil, sv); ok {
|
||||
*d = b
|
||||
return nil
|
||||
}
|
||||
case *sql.RawBytes:
|
||||
sv = reflect.ValueOf(src)
|
||||
if b, ok := asBytes([]byte(*d)[:0], sv); ok {
|
||||
*d = sql.RawBytes(b)
|
||||
return nil
|
||||
}
|
||||
case *bool:
|
||||
bv, err := driver.Bool.ConvertValue(src)
|
||||
if err == nil {
|
||||
*d = bv.(bool)
|
||||
}
|
||||
return err
|
||||
case *interface{}:
|
||||
*d = src
|
||||
return nil
|
||||
}
|
||||
|
||||
if scanner, ok := dest.(sql.Scanner); ok {
|
||||
return scanner.Scan(src)
|
||||
}
|
||||
|
||||
dpv := reflect.ValueOf(dest)
|
||||
if dpv.Kind() != reflect.Ptr {
|
||||
return errors.New("destination not a pointer")
|
||||
}
|
||||
if dpv.IsNil() {
|
||||
return errNilPtr
|
||||
}
|
||||
|
||||
if !sv.IsValid() {
|
||||
sv = reflect.ValueOf(src)
|
||||
}
|
||||
|
||||
dv := reflect.Indirect(dpv)
|
||||
if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
|
||||
switch b := src.(type) {
|
||||
case []byte:
|
||||
dv.Set(reflect.ValueOf(cloneBytes(b)))
|
||||
default:
|
||||
dv.Set(sv)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
|
||||
dv.Set(sv.Convert(dv.Type()))
|
||||
return nil
|
||||
}
|
||||
|
||||
// The following conversions use a string value as an intermediate representation
|
||||
// to convert between various numeric types.
|
||||
//
|
||||
// This also allows scanning into user defined types such as "type Int int64".
|
||||
// For symmetry, also check for string destination types.
|
||||
switch dv.Kind() {
|
||||
case reflect.Ptr:
|
||||
if src == nil {
|
||||
dv.Set(reflect.Zero(dv.Type()))
|
||||
return nil
|
||||
}
|
||||
dv.Set(reflect.New(dv.Type().Elem()))
|
||||
return convertAssign(dv.Interface(), src)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
s := asString(src)
|
||||
i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
|
||||
if err != nil {
|
||||
err = strconvErr(err)
|
||||
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
|
||||
}
|
||||
dv.SetInt(i64)
|
||||
return nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
s := asString(src)
|
||||
u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
|
||||
if err != nil {
|
||||
err = strconvErr(err)
|
||||
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
|
||||
}
|
||||
dv.SetUint(u64)
|
||||
return nil
|
||||
case reflect.Float32, reflect.Float64:
|
||||
s := asString(src)
|
||||
f64, err := strconv.ParseFloat(s, dv.Type().Bits())
|
||||
if err != nil {
|
||||
err = strconvErr(err)
|
||||
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
|
||||
}
|
||||
dv.SetFloat(f64)
|
||||
return nil
|
||||
case reflect.String:
|
||||
switch v := src.(type) {
|
||||
case string:
|
||||
dv.SetString(v)
|
||||
return nil
|
||||
case []byte:
|
||||
dv.SetString(string(v))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
|
||||
}
|
||||
|
||||
func strconvErr(err error) error {
|
||||
if ne, ok := err.(*strconv.NumError); ok {
|
||||
return ne.Err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func cloneBytes(b []byte) []byte {
|
||||
if b == nil {
|
||||
return nil
|
||||
}
|
||||
c := make([]byte, len(b))
|
||||
copy(c, b)
|
||||
return c
|
||||
}
|
||||
|
||||
func asString(src interface{}) string {
|
||||
switch v := src.(type) {
|
||||
case string:
|
||||
return v
|
||||
case []byte:
|
||||
return string(v)
|
||||
}
|
||||
rv := reflect.ValueOf(src)
|
||||
switch rv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return strconv.FormatInt(rv.Int(), 10)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return strconv.FormatUint(rv.Uint(), 10)
|
||||
case reflect.Float64:
|
||||
return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
|
||||
case reflect.Float32:
|
||||
return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
|
||||
case reflect.Bool:
|
||||
return strconv.FormatBool(rv.Bool())
|
||||
}
|
||||
return fmt.Sprintf("%v", src)
|
||||
}
|
||||
|
||||
func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
|
||||
switch rv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return strconv.AppendInt(buf, rv.Int(), 10), true
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return strconv.AppendUint(buf, rv.Uint(), 10), true
|
||||
case reflect.Float32:
|
||||
return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
|
||||
case reflect.Float64:
|
||||
return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
|
||||
case reflect.Bool:
|
||||
return strconv.AppendBool(buf, rv.Bool()), true
|
||||
case reflect.String:
|
||||
s := rv.String()
|
||||
return append(buf, s...), true
|
||||
}
|
||||
return
|
||||
}
|
||||
56
vendor/modernc.org/sqlite/dmesg.go
generated
vendored
Normal file
56
vendor/modernc.org/sqlite/dmesg.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2023 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build sqlite.dmesg
|
||||
// +build sqlite.dmesg
|
||||
|
||||
package sqlite // import "modernc.org/sqlite"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const dmesgs = true
|
||||
|
||||
var (
|
||||
pid = fmt.Sprintf("[%v %v] ", os.Getpid(), filepath.Base(os.Args[0]))
|
||||
logf *os.File
|
||||
)
|
||||
|
||||
func init() {
|
||||
t := time.Now()
|
||||
// 01/02 03:04:05PM '06 -0700
|
||||
dn := t.Format("sqlite-dmesg-2006-01-02-03-150405")
|
||||
dn = filepath.Join(os.TempDir(), fmt.Sprintf("%s.%d", dn, os.Getpid()))
|
||||
if err := os.Mkdir(dn, 0770); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
fn := filepath.Join(dn, "dmesg.log")
|
||||
var err error
|
||||
if logf, err = os.OpenFile(fn, os.O_APPEND|os.O_CREATE|os.O_WRONLY|os.O_SYNC, 0644); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
dmesg("%v", time.Now())
|
||||
fmt.Fprintf(os.Stderr, "debug messages in %s\n", fn)
|
||||
}
|
||||
|
||||
func dmesg(s string, args ...interface{}) {
|
||||
if s == "" {
|
||||
s = strings.Repeat("%v ", len(args))
|
||||
}
|
||||
s = fmt.Sprintf(pid+s, args...)
|
||||
s += fmt.Sprintf(" (%v: %v:)", origin(3), origin(2))
|
||||
switch {
|
||||
case len(s) != 0 && s[len(s)-1] == '\n':
|
||||
fmt.Fprint(logf, s)
|
||||
default:
|
||||
fmt.Fprintln(logf, s)
|
||||
}
|
||||
}
|
||||
204
vendor/modernc.org/sqlite/doc.go
generated
vendored
Normal file
204
vendor/modernc.org/sqlite/doc.go
generated
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
// Copyright 2017 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package sqlite is a sql/database driver using a CGo-free port of the C
|
||||
// SQLite3 library.
|
||||
//
|
||||
// SQLite is an in-process implementation of a self-contained, serverless,
|
||||
// zero-configuration, transactional SQL database engine.
|
||||
//
|
||||
// # Fragile modernc.org/libc dependency
|
||||
//
|
||||
// When you import this package you should use in your go.mod file the exact
|
||||
// same version of modernc.org/libc as seen in the go.mod file of this
|
||||
// repository.
|
||||
//
|
||||
// See the discussion at https://gitlab.com/cznic/sqlite/-/issues/177 for more details.
|
||||
//
|
||||
// # Thanks
|
||||
//
|
||||
// This project is sponsored by Schleibinger Geräte Teubert u. Greim GmbH by
|
||||
// allowing one of the maintainers to work on it also in office hours.
|
||||
//
|
||||
// # Supported platforms and architectures
|
||||
//
|
||||
// These combinations of GOOS and GOARCH are currently supported
|
||||
//
|
||||
// OS Arch SQLite version
|
||||
// ------------------------------
|
||||
// darwin amd64 3.51.2
|
||||
// darwin arm64 3.51.2
|
||||
// freebsd amd64 3.51.2
|
||||
// freebsd arm64 3.51.2
|
||||
// linux 386 3.51.2
|
||||
// linux amd64 3.51.2
|
||||
// linux arm 3.51.2
|
||||
// linux arm64 3.51.2
|
||||
// linux loong64 3.51.2
|
||||
// linux ppc64le 3.51.2
|
||||
// linux riscv64 3.51.2
|
||||
// linux s390x 3.51.2
|
||||
// windows 386 3.51.2
|
||||
// windows amd64 3.51.2
|
||||
// windows arm64 3.51.2
|
||||
//
|
||||
// # Benchmarks
|
||||
//
|
||||
// [The SQLite Drivers Benchmarks Game]
|
||||
//
|
||||
// # Builders
|
||||
//
|
||||
// Builder results available at:
|
||||
//
|
||||
// https://modern-c.appspot.com/-/builder/?importpath=modernc.org%2fsqlite
|
||||
//
|
||||
//
|
||||
// # Connecting to a database
|
||||
//
|
||||
// To access a Sqlite database do something like
|
||||
//
|
||||
// import (
|
||||
// "database/sql"
|
||||
//
|
||||
// _ "modernc.org/sqlite"
|
||||
// )
|
||||
//
|
||||
// ...
|
||||
//
|
||||
//
|
||||
// db, err := sql.Open("sqlite", dsnURI)
|
||||
//
|
||||
// ...
|
||||
//
|
||||
// # Debug and development versions
|
||||
//
|
||||
// A comma separated list of options can be passed to `go generate` via the
|
||||
// environment variable GO_GENERATE. Some useful options include for example:
|
||||
//
|
||||
// -DSQLITE_DEBUG
|
||||
// -DSQLITE_MEM_DEBUG
|
||||
// -ccgo-verify-structs
|
||||
//
|
||||
// To create a debug/development version, issue for example:
|
||||
//
|
||||
// $ GO_GENERATE=-DSQLITE_DEBUG,-DSQLITE_MEM_DEBUG go generate
|
||||
//
|
||||
// Note: To run `go generate` you need to have modernc.org/ccgo/v3 installed.
|
||||
//
|
||||
// # Hacking
|
||||
//
|
||||
// This is an example of how to use the debug logs in modernc.org/libc when hunting a bug.
|
||||
//
|
||||
// 0:jnml@e5-1650:~/src/modernc.org/sqlite$ git status
|
||||
// On branch master
|
||||
// Your branch is up to date with 'origin/master'.
|
||||
//
|
||||
// nothing to commit, working tree clean
|
||||
// 0:jnml@e5-1650:~/src/modernc.org/sqlite$ git log -1
|
||||
// commit df33b8d15107f3cc777799c0fe105f74ef499e62 (HEAD -> master, tag: v1.21.1, origin/master, origin/HEAD, wips, ok)
|
||||
// Author: Jan Mercl <0xjnml@gmail.com>
|
||||
// Date: Mon Mar 27 16:18:28 2023 +0200
|
||||
//
|
||||
// upgrade to SQLite 3.41.2
|
||||
// 0:jnml@e5-1650:~/src/modernc.org/sqlite$ rm -f /tmp/libc.log ; go test -v -tags=libc.dmesg -run TestScalar ; ls -l /tmp/libc.log
|
||||
// test binary compiled for linux/amd64
|
||||
// === RUN TestScalar
|
||||
// --- PASS: TestScalar (0.09s)
|
||||
// PASS
|
||||
// ok modernc.org/sqlite 0.128s
|
||||
// -rw-r--r-- 1 jnml jnml 76 Apr 6 11:22 /tmp/libc.log
|
||||
// 0:jnml@e5-1650:~/src/modernc.org/sqlite$ cat /tmp/libc.log
|
||||
// [10723 sqlite.test] 2023-04-06 11:22:48.288066057 +0200 CEST m=+0.000707150
|
||||
// 0:jnml@e5-1650:~/src/modernc.org/sqlite$
|
||||
//
|
||||
// The /tmp/libc.log file is created as requested. No useful messages there because none are enabled in libc. Let's try to enable Xwrite as an example.
|
||||
//
|
||||
// 0:jnml@e5-1650:~/src/modernc.org/libc$ git status
|
||||
// On branch master
|
||||
// Your branch is up to date with 'origin/master'.
|
||||
//
|
||||
// Changes not staged for commit:
|
||||
// (use "git add <file>..." to update what will be committed)
|
||||
// (use "git restore <file>..." to discard changes in working directory)
|
||||
// modified: libc_linux.go
|
||||
//
|
||||
// no changes added to commit (use "git add" and/or "git commit -a")
|
||||
// 0:jnml@e5-1650:~/src/modernc.org/libc$ git log -1
|
||||
// commit 1e22c18cf2de8aa86d5b19b165f354f99c70479c (HEAD -> master, tag: v1.22.3, origin/master, origin/HEAD)
|
||||
// Author: Jan Mercl <0xjnml@gmail.com>
|
||||
// Date: Wed Feb 22 20:27:45 2023 +0100
|
||||
//
|
||||
// support sqlite 3.41 on linux targets
|
||||
// 0:jnml@e5-1650:~/src/modernc.org/libc$ git diff
|
||||
// diff --git a/libc_linux.go b/libc_linux.go
|
||||
// index 1c2f482..ac1f08d 100644
|
||||
// --- a/libc_linux.go
|
||||
// +++ b/libc_linux.go
|
||||
// @@ -332,19 +332,19 @@ func Xwrite(t *TLS, fd int32, buf uintptr, count types.Size_t) types.Ssize_t {
|
||||
// var n uintptr
|
||||
// switch n, _, err = unix.Syscall(unix.SYS_WRITE, uintptr(fd), buf, uintptr(count)); err {
|
||||
// case 0:
|
||||
// - // if dmesgs {
|
||||
// - // // dmesg("%v: %d %#x: %#x\n%s", origin(1), fd, count, n, hex.Dump(GoBytes(buf, int(n))))
|
||||
// - // dmesg("%v: %d %#x: %#x", origin(1), fd, count, n)
|
||||
// - // }
|
||||
// + if dmesgs {
|
||||
// + // dmesg("%v: %d %#x: %#x\n%s", origin(1), fd, count, n, hex.Dump(GoBytes(buf, int(n))))
|
||||
// + dmesg("%v: %d %#x: %#x", origin(1), fd, count, n)
|
||||
// + }
|
||||
// return types.Ssize_t(n)
|
||||
// case errno.EAGAIN:
|
||||
// // nop
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// - // if dmesgs {
|
||||
// - // dmesg("%v: fd %v, count %#x: %v", origin(1), fd, count, err)
|
||||
// - // }
|
||||
// + if dmesgs {
|
||||
// + dmesg("%v: fd %v, count %#x: %v", origin(1), fd, count, err)
|
||||
// + }
|
||||
// t.setErrno(err)
|
||||
// return -1
|
||||
// }
|
||||
// 0:jnml@e5-1650:~/src/modernc.org/libc$
|
||||
//
|
||||
// We need to tell the Go build system to use our local, patched/debug libc:
|
||||
//
|
||||
// 0:jnml@e5-1650:~/src/modernc.org/sqlite$ go work use $(go env GOPATH)/src/modernc.org/libc
|
||||
// 0:jnml@e5-1650:~/src/modernc.org/sqlite$ go work use .
|
||||
//
|
||||
// And run the test again:
|
||||
//
|
||||
// 0:jnml@e5-1650:~/src/modernc.org/sqlite$ rm -f /tmp/libc.log ; go test -v -tags=libc.dmesg -run TestScalar ; ls -l /tmp/libc.log
|
||||
// test binary compiled for linux/amd64
|
||||
// === RUN TestScalar
|
||||
// --- PASS: TestScalar (0.26s)
|
||||
// PASS
|
||||
// ok modernc.org/sqlite 0.285s
|
||||
// -rw-r--r-- 1 jnml jnml 918 Apr 6 11:29 /tmp/libc.log
|
||||
// 0:jnml@e5-1650:~/src/modernc.org/sqlite$ cat /tmp/libc.log
|
||||
// [11910 sqlite.test] 2023-04-06 11:29:13.143589542 +0200 CEST m=+0.000689270
|
||||
// [11910 sqlite.test] libc_linux.go:337:Xwrite: 8 0x200: 0x200
|
||||
// [11910 sqlite.test] libc_linux.go:337:Xwrite: 8 0xc: 0xc
|
||||
// [11910 sqlite.test] libc_linux.go:337:Xwrite: 7 0x1000: 0x1000
|
||||
// [11910 sqlite.test] libc_linux.go:337:Xwrite: 7 0x1000: 0x1000
|
||||
// [11910 sqlite.test] libc_linux.go:337:Xwrite: 8 0x200: 0x200
|
||||
// [11910 sqlite.test] libc_linux.go:337:Xwrite: 8 0x4: 0x4
|
||||
// [11910 sqlite.test] libc_linux.go:337:Xwrite: 8 0x1000: 0x1000
|
||||
// [11910 sqlite.test] libc_linux.go:337:Xwrite: 8 0x4: 0x4
|
||||
// [11910 sqlite.test] libc_linux.go:337:Xwrite: 8 0x4: 0x4
|
||||
// [11910 sqlite.test] libc_linux.go:337:Xwrite: 8 0x1000: 0x1000
|
||||
// [11910 sqlite.test] libc_linux.go:337:Xwrite: 8 0x4: 0x4
|
||||
// [11910 sqlite.test] libc_linux.go:337:Xwrite: 8 0xc: 0xc
|
||||
// [11910 sqlite.test] libc_linux.go:337:Xwrite: 7 0x1000: 0x1000
|
||||
// [11910 sqlite.test] libc_linux.go:337:Xwrite: 7 0x1000: 0x1000
|
||||
// 0:jnml@e5-1650:~/src/modernc.org/sqlite$
|
||||
//
|
||||
// # Sqlite documentation
|
||||
//
|
||||
// See https://sqlite.org/docs.html
|
||||
//
|
||||
// [The SQLite Drivers Benchmarks Game]: https://pkg.go.dev/modernc.org/sqlite-bench#readme-tl-dr-scorecard
|
||||
package sqlite // import "modernc.org/sqlite"
|
||||
120
vendor/modernc.org/sqlite/driver.go
generated
vendored
Normal file
120
vendor/modernc.org/sqlite/driver.go
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
// Copyright 2025 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite // import "modernc.org/sqlite"
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
|
||||
"modernc.org/sqlite/vtab"
|
||||
)
|
||||
|
||||
// Driver implements database/sql/driver.Driver.
|
||||
type Driver struct {
|
||||
// user defined functions that are added to every new connection on Open
|
||||
udfs map[string]*userDefinedFunction
|
||||
// collations that are added to every new connection on Open
|
||||
collations map[string]*collation
|
||||
// connection hooks are called after a connection is opened
|
||||
connectionHooks []ConnectionHookFn
|
||||
// modules holds registered virtual table modules that should be added to
|
||||
// every new connection on Open.
|
||||
modules map[string]vtab.Module
|
||||
}
|
||||
|
||||
var d = &Driver{
|
||||
udfs: make(map[string]*userDefinedFunction, 0),
|
||||
collations: make(map[string]*collation, 0),
|
||||
connectionHooks: make([]ConnectionHookFn, 0),
|
||||
modules: make(map[string]vtab.Module, 0),
|
||||
}
|
||||
|
||||
func newDriver() *Driver { return d }
|
||||
|
||||
// Open returns a new connection to the database. The name is a string in a
|
||||
// driver-specific format.
|
||||
//
|
||||
// Open may return a cached connection (one previously closed), but doing so is
|
||||
// unnecessary; the sql package maintains a pool of idle connections for
|
||||
// efficient re-use.
|
||||
//
|
||||
// The returned connection is only used by one goroutine at a time.
|
||||
//
|
||||
// The name may be a filename, e.g., "/tmp/mydata.sqlite", or a URI, in which
|
||||
// case it may include a '?' followed by one or more query parameters.
|
||||
// For example, "file:///tmp/mydata.sqlite?_pragma=foreign_keys(1)&_time_format=sqlite".
|
||||
// The supported query parameters are:
|
||||
//
|
||||
// _pragma: Each value will be run as a "PRAGMA ..." statement (with the PRAGMA
|
||||
// keyword added for you). May be specified more than once, '&'-separated. For more
|
||||
// information on supported PRAGMAs see: https://www.sqlite.org/pragma.html
|
||||
//
|
||||
// _time_format: The name of a format to use when writing time values to the
|
||||
// database. Currently the only supported value is "sqlite", which corresponds
|
||||
// to format 7 from https://www.sqlite.org/lang_datefunc.html#time_values,
|
||||
// including the timezone specifier. If this parameter is not specified, then
|
||||
// the default String() format will be used.
|
||||
//
|
||||
// _time_integer_format: The name of a integer format to use when writing time values.
|
||||
// By default, the time is stored as string and the format can be set with _time_format
|
||||
// parameter. If _time_integer_format is set, the time will be stored as an integer and
|
||||
// the integer value will depend on the integer format.
|
||||
// If you decide to set both _time_format and _time_integer_format, the time will be
|
||||
// converted as integer and the _time_format value will be ignored.
|
||||
// Currently the supported value are "unix","unix_milli", "unix_micro" and "unix_nano",
|
||||
// which corresponds to seconds, milliseconds, microseconds or nanoseconds
|
||||
// since unixepoch (1 January 1970 00:00:00 UTC).
|
||||
//
|
||||
// _inttotime: Enable conversion of time column (DATE, DATETIME,TIMESTAMP) from integer
|
||||
// to time if the field contain integer (int64).
|
||||
//
|
||||
// _txlock: The locking behavior to use when beginning a transaction. May be
|
||||
// "deferred" (the default), "immediate", or "exclusive" (case insensitive). See:
|
||||
// https://www.sqlite.org/lang_transaction.html#deferred_immediate_and_exclusive_transactions
|
||||
func (d *Driver) Open(name string) (conn driver.Conn, err error) {
|
||||
if dmesgs {
|
||||
defer func() {
|
||||
dmesg("name %q: (driver.Conn %p, err %v)", name, conn, err)
|
||||
}()
|
||||
}
|
||||
c, err := newConn(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, udf := range d.udfs {
|
||||
if err = c.createFunctionInternal(udf); err != nil {
|
||||
c.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
for _, coll := range d.collations {
|
||||
if err = c.createCollationInternal(coll); err != nil {
|
||||
c.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
for _, connHookFn := range d.connectionHooks {
|
||||
if err = connHookFn(c, name); err != nil {
|
||||
c.Close()
|
||||
return nil, fmt.Errorf("connection hook: %w", err)
|
||||
}
|
||||
}
|
||||
// Register any vtab modules with this connection.
|
||||
// Note: vtab module registration applies to new connections only. If a
|
||||
// module is registered after a connection has been opened, that existing
|
||||
// connection will not see the module; open a new connection to use it.
|
||||
if err := c.registerModules(); err != nil {
|
||||
c.Close()
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// RegisterConnectionHook registers a function to be called after each connection
|
||||
// is opened. This is called after all the connection has been set up.
|
||||
func (d *Driver) RegisterConnectionHook(fn ConnectionHookFn) {
|
||||
d.connectionHooks = append(d.connectionHooks, fn)
|
||||
}
|
||||
75
vendor/modernc.org/sqlite/error.go
generated
vendored
Normal file
75
vendor/modernc.org/sqlite/error.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright 2025 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite // import "modernc.org/sqlite"
|
||||
|
||||
import (
|
||||
sqlite3 "modernc.org/sqlite/lib"
|
||||
)
|
||||
|
||||
// Error represents sqlite library error code.
|
||||
type Error struct {
|
||||
msg string
|
||||
code int
|
||||
}
|
||||
|
||||
// Error implements error.
|
||||
func (e *Error) Error() string { return e.msg }
|
||||
|
||||
// Code returns the sqlite result code for this error.
|
||||
func (e *Error) Code() int { return e.code }
|
||||
|
||||
var (
|
||||
// ErrorCodeString maps Error.Code() to its string representation.
|
||||
ErrorCodeString = map[int]string{
|
||||
sqlite3.SQLITE_ABORT: "Callback routine requested an abort (SQLITE_ABORT)",
|
||||
sqlite3.SQLITE_AUTH: "Authorization denied (SQLITE_AUTH)",
|
||||
sqlite3.SQLITE_BUSY: "The database file is locked (SQLITE_BUSY)",
|
||||
sqlite3.SQLITE_CANTOPEN: "Unable to open the database file (SQLITE_CANTOPEN)",
|
||||
sqlite3.SQLITE_CONSTRAINT: "Abort due to constraint violation (SQLITE_CONSTRAINT)",
|
||||
sqlite3.SQLITE_CORRUPT: "The database disk image is malformed (SQLITE_CORRUPT)",
|
||||
sqlite3.SQLITE_DONE: "sqlite3_step() has finished executing (SQLITE_DONE)",
|
||||
sqlite3.SQLITE_EMPTY: "Internal use only (SQLITE_EMPTY)",
|
||||
sqlite3.SQLITE_ERROR: "Generic error (SQLITE_ERROR)",
|
||||
sqlite3.SQLITE_FORMAT: "Not used (SQLITE_FORMAT)",
|
||||
sqlite3.SQLITE_FULL: "Insertion failed because database is full (SQLITE_FULL)",
|
||||
sqlite3.SQLITE_INTERNAL: "Internal logic error in SQLite (SQLITE_INTERNAL)",
|
||||
sqlite3.SQLITE_INTERRUPT: "Operation terminated by sqlite3_interrupt()(SQLITE_INTERRUPT)",
|
||||
sqlite3.SQLITE_IOERR | (1 << 8): "(SQLITE_IOERR_READ)",
|
||||
sqlite3.SQLITE_IOERR | (10 << 8): "(SQLITE_IOERR_DELETE)",
|
||||
sqlite3.SQLITE_IOERR | (11 << 8): "(SQLITE_IOERR_BLOCKED)",
|
||||
sqlite3.SQLITE_IOERR | (12 << 8): "(SQLITE_IOERR_NOMEM)",
|
||||
sqlite3.SQLITE_IOERR | (13 << 8): "(SQLITE_IOERR_ACCESS)",
|
||||
sqlite3.SQLITE_IOERR | (14 << 8): "(SQLITE_IOERR_CHECKRESERVEDLOCK)",
|
||||
sqlite3.SQLITE_IOERR | (15 << 8): "(SQLITE_IOERR_LOCK)",
|
||||
sqlite3.SQLITE_IOERR | (16 << 8): "(SQLITE_IOERR_CLOSE)",
|
||||
sqlite3.SQLITE_IOERR | (17 << 8): "(SQLITE_IOERR_DIR_CLOSE)",
|
||||
sqlite3.SQLITE_IOERR | (2 << 8): "(SQLITE_IOERR_SHORT_READ)",
|
||||
sqlite3.SQLITE_IOERR | (3 << 8): "(SQLITE_IOERR_WRITE)",
|
||||
sqlite3.SQLITE_IOERR | (4 << 8): "(SQLITE_IOERR_FSYNC)",
|
||||
sqlite3.SQLITE_IOERR | (5 << 8): "(SQLITE_IOERR_DIR_FSYNC)",
|
||||
sqlite3.SQLITE_IOERR | (6 << 8): "(SQLITE_IOERR_TRUNCATE)",
|
||||
sqlite3.SQLITE_IOERR | (7 << 8): "(SQLITE_IOERR_FSTAT)",
|
||||
sqlite3.SQLITE_IOERR | (8 << 8): "(SQLITE_IOERR_UNLOCK)",
|
||||
sqlite3.SQLITE_IOERR | (9 << 8): "(SQLITE_IOERR_RDLOCK)",
|
||||
sqlite3.SQLITE_IOERR: "Some kind of disk I/O error occurred (SQLITE_IOERR)",
|
||||
sqlite3.SQLITE_LOCKED | (1 << 8): "(SQLITE_LOCKED_SHAREDCACHE)",
|
||||
sqlite3.SQLITE_LOCKED: "A table in the database is locked (SQLITE_LOCKED)",
|
||||
sqlite3.SQLITE_MISMATCH: "Data type mismatch (SQLITE_MISMATCH)",
|
||||
sqlite3.SQLITE_MISUSE: "Library used incorrectly (SQLITE_MISUSE)",
|
||||
sqlite3.SQLITE_NOLFS: "Uses OS features not supported on host (SQLITE_NOLFS)",
|
||||
sqlite3.SQLITE_NOMEM: "A malloc() failed (SQLITE_NOMEM)",
|
||||
sqlite3.SQLITE_NOTADB: "File opened that is not a database file (SQLITE_NOTADB)",
|
||||
sqlite3.SQLITE_NOTFOUND: "Unknown opcode in sqlite3_file_control() (SQLITE_NOTFOUND)",
|
||||
sqlite3.SQLITE_NOTICE: "Notifications from sqlite3_log() (SQLITE_NOTICE)",
|
||||
sqlite3.SQLITE_PERM: "Access permission denied (SQLITE_PERM)",
|
||||
sqlite3.SQLITE_PROTOCOL: "Database lock protocol error (SQLITE_PROTOCOL)",
|
||||
sqlite3.SQLITE_RANGE: "2nd parameter to sqlite3_bind out of range (SQLITE_RANGE)",
|
||||
sqlite3.SQLITE_READONLY: "Attempt to write a readonly database (SQLITE_READONLY)",
|
||||
sqlite3.SQLITE_ROW: "sqlite3_step() has another row ready (SQLITE_ROW)",
|
||||
sqlite3.SQLITE_SCHEMA: "The database schema changed (SQLITE_SCHEMA)",
|
||||
sqlite3.SQLITE_TOOBIG: "String or BLOB exceeds size limit (SQLITE_TOOBIG)",
|
||||
sqlite3.SQLITE_WARNING: "Warnings from sqlite3_log() (SQLITE_WARNING)",
|
||||
}
|
||||
)
|
||||
43
vendor/modernc.org/sqlite/fcntl.go
generated
vendored
Normal file
43
vendor/modernc.org/sqlite/fcntl.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright 2024 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite // import "modernc.org/sqlite"
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"modernc.org/libc"
|
||||
sqlite3 "modernc.org/sqlite/lib"
|
||||
)
|
||||
|
||||
// Access to sqlite3_file_control
|
||||
type FileControl interface {
|
||||
// Set or query SQLITE_FCNTL_PERSIST_WAL, returns set mode or query result
|
||||
FileControlPersistWAL(dbName string, mode int) (int, error)
|
||||
}
|
||||
|
||||
var _ FileControl = (*conn)(nil)
|
||||
|
||||
func (c *conn) FileControlPersistWAL(dbName string, mode int) (int, error) {
|
||||
pi32 := c.tls.Alloc(4)
|
||||
defer c.tls.Free(4)
|
||||
|
||||
*(*int32)(unsafe.Pointer(pi32)) = int32(mode)
|
||||
err := c.fileControl(dbName, sqlite3.SQLITE_FCNTL_PERSIST_WAL, pi32)
|
||||
return int(*(*int32)(unsafe.Pointer(pi32))), err
|
||||
}
|
||||
|
||||
func (c *conn) fileControl(dbName string, op int, pArg uintptr) error {
|
||||
zDbName, err := libc.CString(dbName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer c.free(zDbName)
|
||||
|
||||
if rc := sqlite3.Xsqlite3_file_control(c.tls, c.db, zDbName, int32(op), pArg); rc != sqlite3.SQLITE_OK {
|
||||
return c.errstr(rc)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
78
vendor/modernc.org/sqlite/issue120.diff
generated
vendored
Normal file
78
vendor/modernc.org/sqlite/issue120.diff
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
--- /home/jnml/tmp/test_syscall.c 2023-04-21 16:26:44.302689709 +0200
|
||||
+++ testdata/sqlite-src-3410200/src/test_syscall.c 2023-04-21 16:29:28.000869993 +0200
|
||||
@@ -110,15 +110,15 @@
|
||||
static int ts_fstat(int fd, struct stat *p);
|
||||
static int ts_ftruncate(int fd, off_t n);
|
||||
static int ts_fcntl(int fd, int cmd, ... );
|
||||
-static int ts_read(int fd, void *aBuf, size_t nBuf);
|
||||
-static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off);
|
||||
+static ssize_t ts_read(int fd, void *aBuf, size_t nBuf);
|
||||
+static ssize_t ts_pread(int fd, void *aBuf, size_t nBuf, off_t off);
|
||||
/* Note: pread64() and pwrite64() actually use off64_t as the type on their
|
||||
** last parameter. But that datatype is not defined on many systems
|
||||
** (ex: Mac, OpenBSD). So substitute a likely equivalent: sqlite3_uint64 */
|
||||
-static int ts_pread64(int fd, void *aBuf, size_t nBuf, sqlite3_uint64 off);
|
||||
-static int ts_write(int fd, const void *aBuf, size_t nBuf);
|
||||
-static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off);
|
||||
-static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, sqlite3_uint64 off);
|
||||
+static ssize_t ts_pread64(int fd, void *aBuf, size_t nBuf, sqlite3_uint64 off);
|
||||
+static ssize_t ts_write(int fd, const void *aBuf, size_t nBuf);
|
||||
+static ssize_t ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off);
|
||||
+static ssize_t ts_pwrite64(int fd, const void *aBuf, size_t nBuf, sqlite3_uint64 off);
|
||||
static int ts_fchmod(int fd, mode_t mode);
|
||||
static int ts_fallocate(int fd, off_t off, off_t len);
|
||||
static void *ts_mmap(void *, size_t, int, int, int, off_t);
|
||||
@@ -313,7 +313,7 @@
|
||||
/*
|
||||
** A wrapper around read().
|
||||
*/
|
||||
-static int ts_read(int fd, void *aBuf, size_t nBuf){
|
||||
+static ssize_t ts_read(int fd, void *aBuf, size_t nBuf){
|
||||
if( tsIsFailErrno("read") ){
|
||||
return -1;
|
||||
}
|
||||
@@ -323,7 +323,7 @@
|
||||
/*
|
||||
** A wrapper around pread().
|
||||
*/
|
||||
-static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off){
|
||||
+static ssize_t ts_pread(int fd, void *aBuf, size_t nBuf, off_t off){
|
||||
if( tsIsFailErrno("pread") ){
|
||||
return -1;
|
||||
}
|
||||
@@ -333,7 +333,7 @@
|
||||
/*
|
||||
** A wrapper around pread64().
|
||||
*/
|
||||
-static int ts_pread64(int fd, void *aBuf, size_t nBuf, sqlite3_uint64 off){
|
||||
+static ssize_t ts_pread64(int fd, void *aBuf, size_t nBuf, sqlite3_uint64 off){
|
||||
if( tsIsFailErrno("pread64") ){
|
||||
return -1;
|
||||
}
|
||||
@@ -343,7 +343,7 @@
|
||||
/*
|
||||
** A wrapper around write().
|
||||
*/
|
||||
-static int ts_write(int fd, const void *aBuf, size_t nBuf){
|
||||
+static ssize_t ts_write(int fd, const void *aBuf, size_t nBuf){
|
||||
if( tsIsFailErrno("write") ){
|
||||
if( tsErrno("write")==EINTR ) orig_write(fd, aBuf, nBuf/2);
|
||||
return -1;
|
||||
@@ -354,7 +354,7 @@
|
||||
/*
|
||||
** A wrapper around pwrite().
|
||||
*/
|
||||
-static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off){
|
||||
+static ssize_t ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off){
|
||||
if( tsIsFailErrno("pwrite") ){
|
||||
return -1;
|
||||
}
|
||||
@@ -364,7 +364,7 @@
|
||||
/*
|
||||
** A wrapper around pwrite64().
|
||||
*/
|
||||
-static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, sqlite3_uint64 off){
|
||||
+static ssize_t ts_pwrite64(int fd, const void *aBuf, size_t nBuf, sqlite3_uint64 off){
|
||||
if( tsIsFailErrno("pwrite64") ){
|
||||
return -1;
|
||||
}
|
||||
16
vendor/modernc.org/sqlite/lib/defs.go
generated
vendored
Normal file
16
vendor/modernc.org/sqlite/lib/defs.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2022 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite3
|
||||
|
||||
const (
|
||||
SQLITE_STATIC = uintptr(0) // ((sqlite3_destructor_type)0)
|
||||
SQLITE_TRANSIENT = ^uintptr(0) // ((sqlite3_destructor_type)-1)
|
||||
)
|
||||
|
||||
type (
|
||||
Sqlite3_index_constraint = sqlite3_index_constraint
|
||||
Sqlite3_index_orderby = sqlite3_index_orderby
|
||||
Sqlite3_index_constraint_usage = sqlite3_index_constraint_usage
|
||||
)
|
||||
20
vendor/modernc.org/sqlite/lib/hooks.go
generated
vendored
Normal file
20
vendor/modernc.org/sqlite/lib/hooks.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright 2019 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !(linux && arm64)
|
||||
|
||||
package sqlite3
|
||||
|
||||
import (
|
||||
"modernc.org/libc"
|
||||
)
|
||||
|
||||
// Format and write a message to the log if logging is enabled.
|
||||
func X__ccgo_sqlite3_log(t *libc.TLS, iErrCode int32, zFormat uintptr, va uintptr) { /* sqlite3.c:29405:17: */
|
||||
libc.X__ccgo_sqlite3_log(t, iErrCode, zFormat, va)
|
||||
}
|
||||
|
||||
func PatchIssue199() {
|
||||
// nop
|
||||
}
|
||||
30
vendor/modernc.org/sqlite/lib/hooks_linux_arm64.go
generated
vendored
Normal file
30
vendor/modernc.org/sqlite/lib/hooks_linux_arm64.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2019 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite3
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"modernc.org/libc"
|
||||
)
|
||||
|
||||
// Format and write a message to the log if logging is enabled.
|
||||
func X__ccgo_sqlite3_log(t *libc.TLS, iErrCode int32, zFormat uintptr, va uintptr) { /* sqlite3.c:29405:17: */
|
||||
libc.X__ccgo_sqlite3_log(t, iErrCode, zFormat, va)
|
||||
}
|
||||
|
||||
// https://gitlab.com/cznic/sqlite/-/issues/199
|
||||
//
|
||||
// We are currently stuck on libc@v1.55.3. Until that is resolved - fix the
|
||||
// problem at runtime.
|
||||
func PatchIssue199() {
|
||||
p := unsafe.Pointer(&_aSyscall)
|
||||
*(*uintptr)(unsafe.Add(p, 608)) = __ccgo_fp(_unixGetpagesizeIssue199)
|
||||
}
|
||||
|
||||
func _unixGetpagesizeIssue199(tls *libc.TLS) (r int32) {
|
||||
return int32(syscall.Getpagesize())
|
||||
}
|
||||
345
vendor/modernc.org/sqlite/lib/mutex.go
generated
vendored
Normal file
345
vendor/modernc.org/sqlite/lib/mutex.go
generated
vendored
Normal file
@@ -0,0 +1,345 @@
|
||||
// Copyright 2021 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !linux
|
||||
|
||||
package sqlite3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
|
||||
"modernc.org/libc"
|
||||
"modernc.org/libc/sys/types"
|
||||
)
|
||||
|
||||
func init() {
|
||||
tls := libc.NewTLS()
|
||||
if Xsqlite3_threadsafe(tls) == 0 {
|
||||
panic(fmt.Errorf("sqlite: thread safety configuration error"))
|
||||
}
|
||||
|
||||
varArgs := libc.Xmalloc(tls, types.Size_t(unsafe.Sizeof(uintptr(0))))
|
||||
if varArgs == 0 {
|
||||
panic(fmt.Errorf("cannot allocate memory"))
|
||||
}
|
||||
|
||||
// int sqlite3_config(int, ...);
|
||||
if rc := Xsqlite3_config(tls, SQLITE_CONFIG_MUTEX, libc.VaList(varArgs, uintptr(unsafe.Pointer(&mutexMethods)))); rc != SQLITE_OK {
|
||||
p := Xsqlite3_errstr(tls, rc)
|
||||
str := libc.GoString(p)
|
||||
panic(fmt.Errorf("sqlite: failed to configure mutex methods: %v", str))
|
||||
}
|
||||
|
||||
libc.Xfree(tls, varArgs)
|
||||
tls.Close()
|
||||
}
|
||||
|
||||
var (
|
||||
mutexMethods = Sqlite3_mutex_methods{
|
||||
FxMutexInit: *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS) int32 }{mutexInit})),
|
||||
FxMutexEnd: *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS) int32 }{mutexEnd})),
|
||||
FxMutexAlloc: *(*uintptr)(unsafe.Pointer(&struct {
|
||||
f func(*libc.TLS, int32) uintptr
|
||||
}{mutexAlloc})),
|
||||
FxMutexFree: *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS, uintptr) }{mutexFree})),
|
||||
FxMutexEnter: *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS, uintptr) }{mutexEnter})),
|
||||
FxMutexTry: *(*uintptr)(unsafe.Pointer(&struct {
|
||||
f func(*libc.TLS, uintptr) int32
|
||||
}{mutexTry})),
|
||||
FxMutexLeave: *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS, uintptr) }{mutexLeave})),
|
||||
FxMutexHeld: *(*uintptr)(unsafe.Pointer(&struct {
|
||||
f func(*libc.TLS, uintptr) int32
|
||||
}{mutexHeld})),
|
||||
FxMutexNotheld: *(*uintptr)(unsafe.Pointer(&struct {
|
||||
f func(*libc.TLS, uintptr) int32
|
||||
}{mutexNotheld})),
|
||||
}
|
||||
|
||||
mutexApp10 mutex
|
||||
mutexApp20 mutex
|
||||
mutexApp30 mutex
|
||||
mutexLRU0 mutex
|
||||
mutexMaster0 mutex
|
||||
mutexMem0 mutex
|
||||
mutexOpen0 mutex
|
||||
mutexPMem0 mutex
|
||||
mutexPRNG0 mutex
|
||||
mutexVFS10 mutex
|
||||
mutexVFS20 mutex
|
||||
mutexVFS30 mutex
|
||||
|
||||
mutexApp1 = uintptr(unsafe.Pointer(&mutexApp10))
|
||||
mutexApp2 = uintptr(unsafe.Pointer(&mutexApp20))
|
||||
mutexApp3 = uintptr(unsafe.Pointer(&mutexApp30))
|
||||
mutexLRU = uintptr(unsafe.Pointer(&mutexLRU0))
|
||||
mutexMaster = uintptr(unsafe.Pointer(&mutexMaster0))
|
||||
mutexMem = uintptr(unsafe.Pointer(&mutexMem0))
|
||||
mutexOpen = uintptr(unsafe.Pointer(&mutexOpen0))
|
||||
mutexPMem = uintptr(unsafe.Pointer(&mutexPMem0))
|
||||
mutexPRNG = uintptr(unsafe.Pointer(&mutexPRNG0))
|
||||
mutexVFS1 = uintptr(unsafe.Pointer(&mutexVFS10))
|
||||
mutexVFS2 = uintptr(unsafe.Pointer(&mutexVFS20))
|
||||
mutexVFS3 = uintptr(unsafe.Pointer(&mutexVFS30))
|
||||
)
|
||||
|
||||
type mutex struct {
|
||||
sync.Mutex
|
||||
cnt int32
|
||||
id int32 // tls.ID
|
||||
recursive bool
|
||||
}
|
||||
|
||||
// int (*xMutexInit)(void);
|
||||
//
|
||||
// The xMutexInit method defined by this structure is invoked as part of system
|
||||
// initialization by the sqlite3_initialize() function. The xMutexInit routine
|
||||
// is called by SQLite exactly once for each effective call to
|
||||
// sqlite3_initialize().
|
||||
//
|
||||
// The xMutexInit() method must be threadsafe. It must be harmless to invoke
|
||||
// xMutexInit() multiple times within the same process and without intervening
|
||||
// calls to xMutexEnd(). Second and subsequent calls to xMutexInit() must be
|
||||
// no-ops. xMutexInit() must not use SQLite memory allocation (sqlite3_malloc()
|
||||
// and its associates).
|
||||
//
|
||||
// If xMutexInit fails in any way, it is expected to clean up after itself
|
||||
// prior to returning.
|
||||
func mutexInit(tls *libc.TLS) int32 { return SQLITE_OK }
|
||||
|
||||
// int (*xMutexEnd)(void);
|
||||
func mutexEnd(tls *libc.TLS) int32 { return SQLITE_OK }
|
||||
|
||||
// sqlite3_mutex *(*xMutexAlloc)(int);
|
||||
//
|
||||
// The sqlite3_mutex_alloc() routine allocates a new mutex and returns a
|
||||
// pointer to it. The sqlite3_mutex_alloc() routine returns NULL if it is
|
||||
// unable to allocate the requested mutex. The argument to
|
||||
// sqlite3_mutex_alloc() must one of these integer constants:
|
||||
//
|
||||
// SQLITE_MUTEX_FAST
|
||||
// SQLITE_MUTEX_RECURSIVE
|
||||
// SQLITE_MUTEX_STATIC_MASTER
|
||||
// SQLITE_MUTEX_STATIC_MEM
|
||||
// SQLITE_MUTEX_STATIC_OPEN
|
||||
// SQLITE_MUTEX_STATIC_PRNG
|
||||
// SQLITE_MUTEX_STATIC_LRU
|
||||
// SQLITE_MUTEX_STATIC_PMEM
|
||||
// SQLITE_MUTEX_STATIC_APP1
|
||||
// SQLITE_MUTEX_STATIC_APP2
|
||||
// SQLITE_MUTEX_STATIC_APP3
|
||||
// SQLITE_MUTEX_STATIC_VFS1
|
||||
// SQLITE_MUTEX_STATIC_VFS2
|
||||
// SQLITE_MUTEX_STATIC_VFS3
|
||||
//
|
||||
// The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) cause
|
||||
// sqlite3_mutex_alloc() to create a new mutex. The new mutex is recursive when
|
||||
// SQLITE_MUTEX_RECURSIVE is used but not necessarily so when SQLITE_MUTEX_FAST
|
||||
// is used. The mutex implementation does not need to make a distinction
|
||||
// between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does not want to.
|
||||
// SQLite will only request a recursive mutex in cases where it really needs
|
||||
// one. If a faster non-recursive mutex implementation is available on the host
|
||||
// platform, the mutex subsystem might return such a mutex in response to
|
||||
// SQLITE_MUTEX_FAST.
|
||||
//
|
||||
// The other allowed parameters to sqlite3_mutex_alloc() (anything other than
|
||||
// SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return a pointer to a
|
||||
// static preexisting mutex. Nine static mutexes are used by the current
|
||||
// version of SQLite. Future versions of SQLite may add additional static
|
||||
// mutexes. Static mutexes are for internal use by SQLite only. Applications
|
||||
// that use SQLite mutexes should use only the dynamic mutexes returned by
|
||||
// SQLITE_MUTEX_FAST or SQLITE_MUTEX_RECURSIVE.
|
||||
//
|
||||
// Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST or
|
||||
// SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() returns a
|
||||
// different mutex on every call. For the static mutex types, the same mutex is
|
||||
// returned on every call that has the same type number.
|
||||
func mutexAlloc(tls *libc.TLS, typ int32) (r uintptr) {
|
||||
switch typ {
|
||||
case SQLITE_MUTEX_FAST:
|
||||
r = libc.Xcalloc(tls, 1, types.Size_t(unsafe.Sizeof(mutex{})))
|
||||
return r
|
||||
case SQLITE_MUTEX_RECURSIVE:
|
||||
r = libc.Xcalloc(tls, 1, types.Size_t(unsafe.Sizeof(mutex{})))
|
||||
(*mutex)(unsafe.Pointer(r)).recursive = true
|
||||
return r
|
||||
case SQLITE_MUTEX_STATIC_MASTER:
|
||||
return mutexMaster
|
||||
case SQLITE_MUTEX_STATIC_MEM:
|
||||
return mutexMem
|
||||
case SQLITE_MUTEX_STATIC_OPEN:
|
||||
return mutexOpen
|
||||
case SQLITE_MUTEX_STATIC_PRNG:
|
||||
return mutexPRNG
|
||||
case SQLITE_MUTEX_STATIC_LRU:
|
||||
return mutexLRU
|
||||
case SQLITE_MUTEX_STATIC_PMEM:
|
||||
return mutexPMem
|
||||
case SQLITE_MUTEX_STATIC_APP1:
|
||||
return mutexApp1
|
||||
case SQLITE_MUTEX_STATIC_APP2:
|
||||
return mutexApp2
|
||||
case SQLITE_MUTEX_STATIC_APP3:
|
||||
return mutexApp3
|
||||
case SQLITE_MUTEX_STATIC_VFS1:
|
||||
return mutexVFS1
|
||||
case SQLITE_MUTEX_STATIC_VFS2:
|
||||
return mutexVFS2
|
||||
case SQLITE_MUTEX_STATIC_VFS3:
|
||||
return mutexVFS3
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// void (*xMutexFree)(sqlite3_mutex *);
|
||||
func mutexFree(tls *libc.TLS, m uintptr) {
|
||||
libc.Xfree(tls, m)
|
||||
}
|
||||
|
||||
// The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt to enter
|
||||
// a mutex. If another thread is already within the mutex,
|
||||
// sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
|
||||
// SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK upon
|
||||
// successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can be
|
||||
// entered multiple times by the same thread. In such cases, the mutex must be
|
||||
// exited an equal number of times before another thread can enter. If the same
|
||||
// thread tries to enter any mutex other than an SQLITE_MUTEX_RECURSIVE more
|
||||
// than once, the behavior is undefined.
|
||||
//
|
||||
// If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or
|
||||
// sqlite3_mutex_leave() is a NULL pointer, then all three routines behave as
|
||||
// no-ops.
|
||||
|
||||
// void (*xMutexEnter)(sqlite3_mutex *);
|
||||
func mutexEnter(tls *libc.TLS, m uintptr) {
|
||||
if m == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Non-recursive mutex: Standard Go lock
|
||||
if !(*mutex)(unsafe.Pointer(m)).recursive {
|
||||
(*mutex)(unsafe.Pointer(m)).Lock()
|
||||
atomic.StoreInt32(&(*mutex)(unsafe.Pointer(m)).id, tls.ID)
|
||||
return
|
||||
}
|
||||
|
||||
// Recursive mutex: Check if we already own it (Fast Path)
|
||||
// We can safely read ptr.id without a lock here because if it equals tls.ID,
|
||||
// WE are the writer, so no other thread can be changing it.
|
||||
if atomic.LoadInt32(&(*mutex)(unsafe.Pointer(m)).id) == tls.ID {
|
||||
(*mutex)(unsafe.Pointer(m)).cnt++
|
||||
return
|
||||
}
|
||||
|
||||
// We don't own it. Acquire physical lock (Slow Path).
|
||||
// This blocks until the mutex is free.
|
||||
(*mutex)(unsafe.Pointer(m)).Lock()
|
||||
|
||||
// Now that we have the lock, claim ownership.
|
||||
atomic.StoreInt32(&(*mutex)(unsafe.Pointer(m)).id, tls.ID)
|
||||
(*mutex)(unsafe.Pointer(m)).cnt = 1
|
||||
}
|
||||
|
||||
// int (*xMutexTry)(sqlite3_mutex *);
|
||||
func mutexTry(tls *libc.TLS, m uintptr) int32 {
|
||||
if m == 0 {
|
||||
return SQLITE_OK
|
||||
}
|
||||
|
||||
// Non-recursive mutex
|
||||
if !(*mutex)(unsafe.Pointer(m)).recursive {
|
||||
if (*mutex)(unsafe.Pointer(m)).TryLock() {
|
||||
(*mutex)(unsafe.Pointer(m)).id = tls.ID
|
||||
return SQLITE_OK
|
||||
}
|
||||
|
||||
return SQLITE_BUSY
|
||||
}
|
||||
|
||||
// Recursive mutex: Check if we already own it (Fast Path)
|
||||
if atomic.LoadInt32(&(*mutex)(unsafe.Pointer(m)).id) == tls.ID {
|
||||
(*mutex)(unsafe.Pointer(m)).cnt++
|
||||
return SQLITE_OK
|
||||
}
|
||||
|
||||
// Try to acquire physical lock
|
||||
if (*mutex)(unsafe.Pointer(m)).TryLock() {
|
||||
atomic.StoreInt32(&(*mutex)(unsafe.Pointer(m)).id, tls.ID)
|
||||
(*mutex)(unsafe.Pointer(m)).cnt = 1
|
||||
return SQLITE_OK
|
||||
}
|
||||
|
||||
return SQLITE_BUSY
|
||||
}
|
||||
|
||||
// void (*xMutexLeave)(sqlite3_mutex *);
|
||||
func mutexLeave(tls *libc.TLS, m uintptr) {
|
||||
if m == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Non-recursive mutex
|
||||
if !(*mutex)(unsafe.Pointer(m)).recursive {
|
||||
atomic.StoreInt32(&(*mutex)(unsafe.Pointer(m)).id, 0)
|
||||
(*mutex)(unsafe.Pointer(m)).Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Recursive mutex: Decrement count
|
||||
(*mutex)(unsafe.Pointer(m)).cnt--
|
||||
|
||||
// If count reaches zero, we are fully releasing the mutex.
|
||||
if (*mutex)(unsafe.Pointer(m)).cnt == 0 {
|
||||
atomic.StoreInt32(&(*mutex)(unsafe.Pointer(m)).id, 0)
|
||||
(*mutex)(unsafe.Pointer(m)).Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines are intended
|
||||
// for use inside assert() statements. The SQLite core never uses these
|
||||
// routines except inside an assert() and applications are advised to follow
|
||||
// the lead of the core. The SQLite core only provides implementations for
|
||||
// these routines when it is compiled with the SQLITE_DEBUG flag. External
|
||||
// mutex implementations are only required to provide these routines if
|
||||
// SQLITE_DEBUG is defined and if NDEBUG is not defined.
|
||||
//
|
||||
// These routines should return true if the mutex in their argument is held or
|
||||
// not held, respectively, by the calling thread.
|
||||
//
|
||||
// The implementation is not required to provide versions of these routines
|
||||
// that actually work. If the implementation does not provide working versions
|
||||
// of these routines, it should at least provide stubs that always return true
|
||||
// so that one does not get spurious assertion failures.
|
||||
//
|
||||
// If the argument to sqlite3_mutex_held() is a NULL pointer then the routine
|
||||
// should return 1. This seems counter-intuitive since clearly the mutex cannot
|
||||
// be held if it does not exist. But the reason the mutex does not exist is
|
||||
// because the build is not using mutexes. And we do not want the assert()
|
||||
// containing the call to sqlite3_mutex_held() to fail, so a non-zero return is
|
||||
// the appropriate thing to do. The sqlite3_mutex_notheld() interface should
|
||||
// also return 1 when given a NULL pointer.
|
||||
|
||||
// int (*xMutexHeld)(sqlite3_mutex *);
|
||||
func mutexHeld(tls *libc.TLS, m uintptr) int32 {
|
||||
if m == 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// atomic.Load is required because we might be checking a mutex
|
||||
// that we do not own (and thus another thread might be writing to).
|
||||
return libc.Bool32(atomic.LoadInt32(&(*mutex)(unsafe.Pointer(m)).id) == tls.ID)
|
||||
}
|
||||
|
||||
// int (*xMutexNotheld)(sqlite3_mutex *);
|
||||
func mutexNotheld(tls *libc.TLS, m uintptr) int32 {
|
||||
if m == 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Returns True if ID is Zero (unheld) OR ID is some other thread's ID.
|
||||
return libc.Bool32(atomic.LoadInt32(&(*mutex)(unsafe.Pointer(m)).id) != tls.ID)
|
||||
}
|
||||
228964
vendor/modernc.org/sqlite/lib/sqlite_darwin_amd64.go
generated
vendored
Normal file
228964
vendor/modernc.org/sqlite/lib/sqlite_darwin_amd64.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
228537
vendor/modernc.org/sqlite/lib/sqlite_darwin_arm64.go
generated
vendored
Normal file
228537
vendor/modernc.org/sqlite/lib/sqlite_darwin_arm64.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
153539
vendor/modernc.org/sqlite/lib/sqlite_freebsd_386.go
generated
vendored
Normal file
153539
vendor/modernc.org/sqlite/lib/sqlite_freebsd_386.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
222700
vendor/modernc.org/sqlite/lib/sqlite_freebsd_amd64.go
generated
vendored
Normal file
222700
vendor/modernc.org/sqlite/lib/sqlite_freebsd_amd64.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
153633
vendor/modernc.org/sqlite/lib/sqlite_freebsd_arm.go
generated
vendored
Normal file
153633
vendor/modernc.org/sqlite/lib/sqlite_freebsd_arm.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
222713
vendor/modernc.org/sqlite/lib/sqlite_freebsd_arm64.go
generated
vendored
Normal file
222713
vendor/modernc.org/sqlite/lib/sqlite_freebsd_arm64.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
222858
vendor/modernc.org/sqlite/lib/sqlite_linux_386.go
generated
vendored
Normal file
222858
vendor/modernc.org/sqlite/lib/sqlite_linux_386.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
222871
vendor/modernc.org/sqlite/lib/sqlite_linux_amd64.go
generated
vendored
Normal file
222871
vendor/modernc.org/sqlite/lib/sqlite_linux_amd64.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
223158
vendor/modernc.org/sqlite/lib/sqlite_linux_arm.go
generated
vendored
Normal file
223158
vendor/modernc.org/sqlite/lib/sqlite_linux_arm.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
222861
vendor/modernc.org/sqlite/lib/sqlite_linux_arm64.go
generated
vendored
Normal file
222861
vendor/modernc.org/sqlite/lib/sqlite_linux_arm64.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
222960
vendor/modernc.org/sqlite/lib/sqlite_linux_loong64.go
generated
vendored
Normal file
222960
vendor/modernc.org/sqlite/lib/sqlite_linux_loong64.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
222908
vendor/modernc.org/sqlite/lib/sqlite_linux_ppc64le.go
generated
vendored
Normal file
222908
vendor/modernc.org/sqlite/lib/sqlite_linux_ppc64le.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
222836
vendor/modernc.org/sqlite/lib/sqlite_linux_riscv64.go
generated
vendored
Normal file
222836
vendor/modernc.org/sqlite/lib/sqlite_linux_riscv64.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
222808
vendor/modernc.org/sqlite/lib/sqlite_linux_s390x.go
generated
vendored
Normal file
222808
vendor/modernc.org/sqlite/lib/sqlite_linux_s390x.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
151230
vendor/modernc.org/sqlite/lib/sqlite_netbsd_amd64.go
generated
vendored
Normal file
151230
vendor/modernc.org/sqlite/lib/sqlite_netbsd_amd64.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
221978
vendor/modernc.org/sqlite/lib/sqlite_openbsd_amd64.go
generated
vendored
Normal file
221978
vendor/modernc.org/sqlite/lib/sqlite_openbsd_amd64.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
221994
vendor/modernc.org/sqlite/lib/sqlite_openbsd_arm64.go
generated
vendored
Normal file
221994
vendor/modernc.org/sqlite/lib/sqlite_openbsd_arm64.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
296206
vendor/modernc.org/sqlite/lib/sqlite_windows.go
generated
vendored
Normal file
296206
vendor/modernc.org/sqlite/lib/sqlite_windows.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
296101
vendor/modernc.org/sqlite/lib/sqlite_windows_386.go
generated
vendored
Normal file
296101
vendor/modernc.org/sqlite/lib/sqlite_windows_386.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
vendor/modernc.org/sqlite/logo.png
generated
vendored
Normal file
BIN
vendor/modernc.org/sqlite/logo.png
generated
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
23
vendor/modernc.org/sqlite/mutex.go
generated
vendored
Normal file
23
vendor/modernc.org/sqlite/mutex.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2019 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite // import "modernc.org/sqlite"
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"modernc.org/libc"
|
||||
"modernc.org/libc/sys/types"
|
||||
)
|
||||
|
||||
type mutex struct {
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func mutexAlloc(tls *libc.TLS) uintptr {
|
||||
return libc.Xcalloc(tls, 1, types.Size_t(unsafe.Sizeof(mutex{})))
|
||||
}
|
||||
|
||||
func mutexFree(tls *libc.TLS, m uintptr) { libc.Xfree(tls, m) }
|
||||
12
vendor/modernc.org/sqlite/nodmesg.go
generated
vendored
Normal file
12
vendor/modernc.org/sqlite/nodmesg.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright 2023 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !sqlite.dmesg
|
||||
// +build !sqlite.dmesg
|
||||
|
||||
package sqlite // import "modernc.org/sqlite"
|
||||
|
||||
const dmesgs = false
|
||||
|
||||
func dmesg(s string, args ...interface{}) {}
|
||||
10
vendor/modernc.org/sqlite/norlimit.go
generated
vendored
Normal file
10
vendor/modernc.org/sqlite/norlimit.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright 2021 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package sqlite // import "modernc.org/sqlite"
|
||||
|
||||
func setMaxOpenFiles(n int) error { return nil }
|
||||
227
vendor/modernc.org/sqlite/pre_update_hook.go
generated
vendored
Normal file
227
vendor/modernc.org/sqlite/pre_update_hook.go
generated
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"modernc.org/libc"
|
||||
"modernc.org/libc/sys/types"
|
||||
sqlite3 "modernc.org/sqlite/lib"
|
||||
)
|
||||
|
||||
var (
|
||||
xPreUpdateHandlers = struct {
|
||||
mu sync.RWMutex
|
||||
m map[uintptr]func(SQLitePreUpdateData)
|
||||
}{
|
||||
m: make(map[uintptr]func(SQLitePreUpdateData)),
|
||||
}
|
||||
xCommitHandlers = struct {
|
||||
mu sync.RWMutex
|
||||
m map[uintptr]CommitHookFn
|
||||
}{
|
||||
m: make(map[uintptr]CommitHookFn),
|
||||
}
|
||||
xRollbackHandlers = struct {
|
||||
mu sync.RWMutex
|
||||
m map[uintptr]RollbackHookFn
|
||||
}{
|
||||
m: make(map[uintptr]RollbackHookFn),
|
||||
}
|
||||
)
|
||||
|
||||
type PreUpdateHookFn func(SQLitePreUpdateData)
|
||||
|
||||
func (c *conn) RegisterPreUpdateHook(callback PreUpdateHookFn) {
|
||||
|
||||
if callback == nil {
|
||||
xPreUpdateHandlers.mu.Lock()
|
||||
delete(xPreUpdateHandlers.m, c.db)
|
||||
xPreUpdateHandlers.mu.Unlock()
|
||||
sqlite3.Xsqlite3_preupdate_hook(c.tls, c.db, uintptr(unsafe.Pointer(nil)), uintptr(unsafe.Pointer(nil)))
|
||||
return
|
||||
}
|
||||
xPreUpdateHandlers.mu.Lock()
|
||||
xPreUpdateHandlers.m[c.db] = callback
|
||||
xPreUpdateHandlers.mu.Unlock()
|
||||
|
||||
sqlite3.Xsqlite3_preupdate_hook(c.tls, c.db, cFuncPointer(preUpdateHookTrampoline), c.db)
|
||||
}
|
||||
|
||||
type CommitHookFn func() int32
|
||||
|
||||
func (c *conn) RegisterCommitHook(callback CommitHookFn) {
|
||||
if callback == nil {
|
||||
xCommitHandlers.mu.Lock()
|
||||
delete(xCommitHandlers.m, c.db)
|
||||
xCommitHandlers.mu.Unlock()
|
||||
sqlite3.Xsqlite3_commit_hook(c.tls, c.db, uintptr(unsafe.Pointer(nil)), uintptr(unsafe.Pointer(nil)))
|
||||
return
|
||||
}
|
||||
xCommitHandlers.mu.Lock()
|
||||
xCommitHandlers.m[c.db] = callback
|
||||
xCommitHandlers.mu.Unlock()
|
||||
sqlite3.Xsqlite3_commit_hook(c.tls, c.db, cFuncPointer(commitHookTrampoline), c.db)
|
||||
}
|
||||
|
||||
type RollbackHookFn func()
|
||||
|
||||
func (c *conn) RegisterRollbackHook(callback RollbackHookFn) {
|
||||
if callback == nil {
|
||||
xRollbackHandlers.mu.Lock()
|
||||
delete(xRollbackHandlers.m, c.db)
|
||||
xRollbackHandlers.mu.Unlock()
|
||||
sqlite3.Xsqlite3_rollback_hook(c.tls, c.db, uintptr(unsafe.Pointer(nil)), uintptr(unsafe.Pointer(nil)))
|
||||
return
|
||||
}
|
||||
xRollbackHandlers.mu.Lock()
|
||||
xRollbackHandlers.m[c.db] = callback
|
||||
xRollbackHandlers.mu.Unlock()
|
||||
sqlite3.Xsqlite3_rollback_hook(c.tls, c.db, cFuncPointer(rollbackHookTrampoline), c.db)
|
||||
}
|
||||
|
||||
type SQLitePreUpdateData struct {
|
||||
tls *libc.TLS
|
||||
pCsr uintptr
|
||||
Op int32
|
||||
DatabaseName string
|
||||
TableName string
|
||||
OldRowID int64
|
||||
NewRowID int64
|
||||
}
|
||||
|
||||
// Depth returns the source path of the write, see sqlite3_preupdate_depth()
|
||||
func (d *SQLitePreUpdateData) Depth() int {
|
||||
return int(sqlite3.Xsqlite3_preupdate_depth(d.tls, d.pCsr))
|
||||
}
|
||||
|
||||
// Count returns the number of columns in the row
|
||||
func (d *SQLitePreUpdateData) Count() int {
|
||||
return int(sqlite3.Xsqlite3_preupdate_count(d.tls, d.pCsr))
|
||||
}
|
||||
|
||||
func (d *SQLitePreUpdateData) row(dest []any, new bool) error {
|
||||
count := d.Count()
|
||||
ppValue, err := mallocValue(d.tls)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer libc.Xfree(d.tls, ppValue)
|
||||
|
||||
for i := 0; i < count && i < len(dest); i++ {
|
||||
val, err := d.value(ppValue, i, new)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = convertAssign(&dest[i], val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Old populates dest with the row data to be replaced. This works similar to
|
||||
// database/sql's Rows.Scan()
|
||||
func (d *SQLitePreUpdateData) Old(dest ...any) error {
|
||||
if d.Op == sqlite3.SQLITE_INSERT {
|
||||
return errors.New("there is no old row for INSERT operations")
|
||||
}
|
||||
return d.row(dest, false)
|
||||
}
|
||||
|
||||
// New populates dest with the replacement row data. This works similar to
|
||||
// database/sql's Rows.Scan()
|
||||
func (d *SQLitePreUpdateData) New(dest ...any) error {
|
||||
if d.Op == sqlite3.SQLITE_DELETE {
|
||||
return errors.New("there is no new row for DELETE operations")
|
||||
}
|
||||
return d.row(dest, true)
|
||||
}
|
||||
|
||||
const ptrValSize = types.Size_t(unsafe.Sizeof(&sqlite3.Sqlite3_value{}))
|
||||
|
||||
func mallocValue(tls *libc.TLS) (uintptr, error) {
|
||||
p := libc.Xmalloc(tls, ptrValSize)
|
||||
if p == 0 {
|
||||
return 0, fmt.Errorf("out of memory")
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (d *SQLitePreUpdateData) value(ppValue uintptr, i int, new bool) (any, error) {
|
||||
var src any
|
||||
if new {
|
||||
sqlite3.Xsqlite3_preupdate_new(d.tls, d.pCsr, int32(i), ppValue)
|
||||
} else {
|
||||
sqlite3.Xsqlite3_preupdate_old(d.tls, d.pCsr, int32(i), ppValue)
|
||||
}
|
||||
ptrValue := *(*uintptr)(unsafe.Pointer(ppValue))
|
||||
switch sqlite3.Xsqlite3_value_type(d.tls, ptrValue) {
|
||||
case sqlite3.SQLITE_INTEGER:
|
||||
src = int64(sqlite3.Xsqlite3_value_int64(d.tls, ptrValue))
|
||||
case sqlite3.SQLITE_FLOAT:
|
||||
src = float64(sqlite3.Xsqlite3_value_double(d.tls, ptrValue))
|
||||
case sqlite3.SQLITE_BLOB:
|
||||
size := sqlite3.Xsqlite3_value_bytes(d.tls, ptrValue)
|
||||
blobPtr := sqlite3.Xsqlite3_value_blob(d.tls, ptrValue)
|
||||
|
||||
var v []byte
|
||||
if size != 0 {
|
||||
v = make([]byte, size)
|
||||
copy(v, (*libc.RawMem)(unsafe.Pointer(blobPtr))[:size:size])
|
||||
}
|
||||
src = v
|
||||
case sqlite3.SQLITE_TEXT:
|
||||
src = libc.GoString(sqlite3.Xsqlite3_value_text(d.tls, ptrValue))
|
||||
case sqlite3.SQLITE_NULL:
|
||||
src = nil
|
||||
}
|
||||
return src, nil
|
||||
}
|
||||
|
||||
func preUpdateHookTrampoline(tls *libc.TLS, handle uintptr, pCsr uintptr, op int32, zDb uintptr, pTab uintptr, iKey1 int64, iReg int32, iBlobWrite int32) {
|
||||
xPreUpdateHandlers.mu.RLock()
|
||||
xPreUpdateHandler := xPreUpdateHandlers.m[handle]
|
||||
xPreUpdateHandlers.mu.RUnlock()
|
||||
|
||||
if xPreUpdateHandler == nil {
|
||||
return
|
||||
}
|
||||
data := SQLitePreUpdateData{
|
||||
tls: tls,
|
||||
pCsr: pCsr,
|
||||
Op: op,
|
||||
DatabaseName: libc.GoString(zDb),
|
||||
TableName: libc.GoString(pTab),
|
||||
OldRowID: iKey1,
|
||||
NewRowID: int64(iReg),
|
||||
}
|
||||
xPreUpdateHandler(data)
|
||||
}
|
||||
|
||||
func commitHookTrampoline(tls *libc.TLS, handle uintptr, pCsr uintptr) int32 {
|
||||
xCommitHandlers.mu.RLock()
|
||||
xCommitHandler := xCommitHandlers.m[handle]
|
||||
xCommitHandlers.mu.RUnlock()
|
||||
|
||||
if xCommitHandler == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return xCommitHandler()
|
||||
}
|
||||
|
||||
func rollbackHookTrampoline(tls *libc.TLS, handle uintptr, pCsr uintptr) {
|
||||
xRollbackHandlers.mu.RLock()
|
||||
xRollbackHandler := xRollbackHandlers.m[handle]
|
||||
xRollbackHandlers.mu.RUnlock()
|
||||
|
||||
if xRollbackHandler == nil {
|
||||
return
|
||||
}
|
||||
|
||||
xRollbackHandler()
|
||||
}
|
||||
42
vendor/modernc.org/sqlite/result.go
generated
vendored
Normal file
42
vendor/modernc.org/sqlite/result.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright 2025 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite // import "modernc.org/sqlite"
|
||||
|
||||
type result struct {
|
||||
lastInsertID int64
|
||||
rowsAffected int
|
||||
}
|
||||
|
||||
func newResult(c *conn) (_ *result, err error) {
|
||||
r := &result{}
|
||||
if r.rowsAffected, err = c.changes(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if r.lastInsertID, err = c.lastInsertRowID(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// LastInsertId returns the database's auto-generated ID after, for example, an
|
||||
// INSERT into a table with primary key.
|
||||
func (r *result) LastInsertId() (int64, error) {
|
||||
if r == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return r.lastInsertID, nil
|
||||
}
|
||||
|
||||
// RowsAffected returns the number of rows affected by the query.
|
||||
func (r *result) RowsAffected() (int64, error) {
|
||||
if r == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return int64(r.rowsAffected), nil
|
||||
}
|
||||
19
vendor/modernc.org/sqlite/rlimit.go
generated
vendored
Normal file
19
vendor/modernc.org/sqlite/rlimit.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2021 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build freebsd
|
||||
// +build freebsd
|
||||
|
||||
package sqlite // import "modernc.org/sqlite"
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func setMaxOpenFiles(n int64) error {
|
||||
var rLimit unix.Rlimit
|
||||
rLimit.Max = n
|
||||
rLimit.Cur = n
|
||||
return unix.Setrlimit(unix.RLIMIT_NOFILE, &rLimit)
|
||||
}
|
||||
297
vendor/modernc.org/sqlite/rows.go
generated
vendored
Normal file
297
vendor/modernc.org/sqlite/rows.go
generated
vendored
Normal file
@@ -0,0 +1,297 @@
|
||||
// Copyright 2025 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite // import "modernc.org/sqlite"
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
sqlite3 "modernc.org/sqlite/lib"
|
||||
)
|
||||
|
||||
type rows struct {
|
||||
allocs []uintptr
|
||||
c *conn
|
||||
columns []string
|
||||
pstmt uintptr
|
||||
|
||||
doStep bool
|
||||
empty bool
|
||||
reuseStmt bool // If true, Close() resets instead of finalizing
|
||||
}
|
||||
|
||||
func newRows(c *conn, pstmt uintptr, allocs []uintptr, empty bool) (r *rows, err error) {
|
||||
r = &rows{c: c, pstmt: pstmt, allocs: allocs, empty: empty}
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
r.Close()
|
||||
r = nil
|
||||
}
|
||||
}()
|
||||
|
||||
n, err := c.columnCount(pstmt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r.columns = make([]string, n)
|
||||
for i := range r.columns {
|
||||
if r.columns[i], err = r.c.columnName(pstmt, i); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Close closes the rows iterator.
|
||||
func (r *rows) Close() (err error) {
|
||||
for _, v := range r.allocs {
|
||||
r.c.free(v)
|
||||
}
|
||||
r.allocs = nil
|
||||
|
||||
if r.reuseStmt {
|
||||
// Reset the statement for reuse instead of finalizing it
|
||||
if e := r.c.reset(r.pstmt); e != nil {
|
||||
return e
|
||||
}
|
||||
return r.c.clearBindings(r.pstmt)
|
||||
}
|
||||
|
||||
return r.c.finalize(r.pstmt)
|
||||
}
|
||||
|
||||
// Columns returns the names of the columns. The number of columns of the
|
||||
// result is inferred from the length of the slice. If a particular column name
|
||||
// isn't known, an empty string should be returned for that entry.
|
||||
func (r *rows) Columns() (c []string) {
|
||||
return r.columns
|
||||
}
|
||||
|
||||
// Next is called to populate the next row of data into the provided slice. The
|
||||
// provided slice will be the same size as the Columns() are wide.
|
||||
//
|
||||
// Next should return io.EOF when there are no more rows.
|
||||
func (r *rows) Next(dest []driver.Value) (err error) {
|
||||
if r.empty {
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
rc := sqlite3.SQLITE_ROW
|
||||
if r.doStep {
|
||||
if rc, err = r.c.step(r.pstmt); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
r.doStep = true
|
||||
switch rc {
|
||||
case sqlite3.SQLITE_ROW:
|
||||
if g, e := len(dest), len(r.columns); g != e {
|
||||
return fmt.Errorf("sqlite: Next: have %v destination values, expected %v", g, e)
|
||||
}
|
||||
|
||||
for i := range dest {
|
||||
ct, err := r.c.columnType(r.pstmt, i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch ct {
|
||||
case sqlite3.SQLITE_INTEGER:
|
||||
v, err := r.c.columnInt64(r.pstmt, i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !r.c.intToTime {
|
||||
dest[i] = v
|
||||
} else {
|
||||
// Inspired by mattn/go-sqlite3:
|
||||
// https://github.com/mattn/go-sqlite3/blob/f76bae4b0044cbba8fb2c72b8e4559e8fbcffd86/sqlite3.go#L2254-L2262
|
||||
// but we put make this compatibility optional behind a DSN
|
||||
// query parameter, because this changes API behavior, so an
|
||||
// opt-in is needed.
|
||||
|
||||
switch r.ColumnTypeDatabaseTypeName(i) {
|
||||
case "DATE", "DATETIME", "TIMESTAMP":
|
||||
// Check for explicit opt-in first. This fixes the bug for micro/nano users
|
||||
// without breaking the legacy heuristic for existing users.
|
||||
switch r.c.integerTimeFormat {
|
||||
case "unix_micro":
|
||||
dest[i] = time.UnixMicro(v).UTC()
|
||||
continue
|
||||
case "unix_nano":
|
||||
dest[i] = time.Unix(0, v).UTC()
|
||||
continue
|
||||
}
|
||||
|
||||
// Legacy Heuristic (mattn/go-sqlite3 compatibility). NOTE: This heuristic
|
||||
// fails for Millisecond timestamps representing dates before Sept 9, 2001
|
||||
// (value < 1e12).
|
||||
|
||||
// Is it a seconds timestamp or a milliseconds
|
||||
// timestamp?
|
||||
if v > 1e12 || v < -1e12 {
|
||||
// Milliseconds
|
||||
dest[i] = time.UnixMilli(v).UTC()
|
||||
} else {
|
||||
// Seconds
|
||||
dest[i] = time.Unix(v, 0).UTC()
|
||||
}
|
||||
default:
|
||||
dest[i] = v
|
||||
}
|
||||
}
|
||||
case sqlite3.SQLITE_FLOAT:
|
||||
v, err := r.c.columnDouble(r.pstmt, i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dest[i] = v
|
||||
case sqlite3.SQLITE_TEXT:
|
||||
v, err := r.c.columnText(r.pstmt, i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch r.ColumnTypeDatabaseTypeName(i) {
|
||||
case "DATE", "DATETIME", "TIMESTAMP":
|
||||
dest[i], _ = r.c.parseTime(v)
|
||||
default:
|
||||
dest[i] = v
|
||||
}
|
||||
case sqlite3.SQLITE_BLOB:
|
||||
v, err := r.c.columnBlob(r.pstmt, i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dest[i] = v
|
||||
case sqlite3.SQLITE_NULL:
|
||||
dest[i] = nil
|
||||
default:
|
||||
return fmt.Errorf("internal error: rc %d", rc)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case sqlite3.SQLITE_DONE:
|
||||
return io.EOF
|
||||
default:
|
||||
return r.c.errstr(int32(rc))
|
||||
}
|
||||
}
|
||||
|
||||
// RowsColumnTypeDatabaseTypeName may be implemented by Rows. It should return
|
||||
// the database system type name without the length. Type names should be
|
||||
// uppercase. Examples of returned types: "VARCHAR", "NVARCHAR", "VARCHAR2",
|
||||
// "CHAR", "TEXT", "DECIMAL", "SMALLINT", "INT", "BIGINT", "BOOL", "[]BIGINT",
|
||||
// "JSONB", "XML", "TIMESTAMP".
|
||||
func (r *rows) ColumnTypeDatabaseTypeName(index int) string {
|
||||
return strings.ToUpper(r.c.columnDeclType(r.pstmt, index))
|
||||
}
|
||||
|
||||
// RowsColumnTypeLength may be implemented by Rows. It should return the length
|
||||
// of the column type if the column is a variable length type. If the column is
|
||||
// not a variable length type ok should return false. If length is not limited
|
||||
// other than system limits, it should return math.MaxInt64. The following are
|
||||
// examples of returned values for various types:
|
||||
//
|
||||
// TEXT (math.MaxInt64, true)
|
||||
// varchar(10) (10, true)
|
||||
// nvarchar(10) (10, true)
|
||||
// decimal (0, false)
|
||||
// int (0, false)
|
||||
// bytea(30) (30, true)
|
||||
func (r *rows) ColumnTypeLength(index int) (length int64, ok bool) {
|
||||
t, err := r.c.columnType(r.pstmt, index)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
switch t {
|
||||
case sqlite3.SQLITE_INTEGER:
|
||||
return 0, false
|
||||
case sqlite3.SQLITE_FLOAT:
|
||||
return 0, false
|
||||
case sqlite3.SQLITE_TEXT:
|
||||
return math.MaxInt64, true
|
||||
case sqlite3.SQLITE_BLOB:
|
||||
return math.MaxInt64, true
|
||||
case sqlite3.SQLITE_NULL:
|
||||
return 0, false
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
|
||||
// RowsColumnTypeNullable may be implemented by Rows. The nullable value should
|
||||
// be true if it is known the column may be null, or false if the column is
|
||||
// known to be not nullable. If the column nullability is unknown, ok should be
|
||||
// false.
|
||||
func (r *rows) ColumnTypeNullable(index int) (nullable, ok bool) {
|
||||
return true, true
|
||||
}
|
||||
|
||||
// RowsColumnTypePrecisionScale may be implemented by Rows. It should return
|
||||
// the precision and scale for decimal types. If not applicable, ok should be
|
||||
// false. The following are examples of returned values for various types:
|
||||
//
|
||||
// decimal(38, 4) (38, 4, true)
|
||||
// int (0, 0, false)
|
||||
// decimal (math.MaxInt64, math.MaxInt64, true)
|
||||
func (r *rows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) {
|
||||
return 0, 0, false
|
||||
}
|
||||
|
||||
// RowsColumnTypeScanType may be implemented by Rows. It should return the
|
||||
// value type that can be used to scan types into. For example, the database
|
||||
// column type "bigint" this should return "reflect.TypeOf(int64(0))".
|
||||
func (r *rows) ColumnTypeScanType(index int) reflect.Type {
|
||||
t, err := r.c.columnType(r.pstmt, index)
|
||||
if err != nil {
|
||||
return reflect.TypeOf("")
|
||||
}
|
||||
|
||||
switch t {
|
||||
case sqlite3.SQLITE_INTEGER:
|
||||
switch strings.ToLower(r.c.columnDeclType(r.pstmt, index)) {
|
||||
case "boolean":
|
||||
return reflect.TypeOf(false)
|
||||
case "date", "datetime", "time", "timestamp":
|
||||
return reflect.TypeOf(time.Time{})
|
||||
default:
|
||||
return reflect.TypeOf(int64(0))
|
||||
}
|
||||
case sqlite3.SQLITE_FLOAT:
|
||||
return reflect.TypeOf(float64(0))
|
||||
case sqlite3.SQLITE_TEXT:
|
||||
return reflect.TypeOf("")
|
||||
case sqlite3.SQLITE_BLOB:
|
||||
return reflect.TypeOf([]byte(nil))
|
||||
case sqlite3.SQLITE_NULL:
|
||||
return reflect.TypeOf(nil)
|
||||
default:
|
||||
return reflect.TypeOf("")
|
||||
}
|
||||
}
|
||||
|
||||
// C documentation
|
||||
//
|
||||
// int sqlite3_reset(sqlite3_stmt *pStmt);
|
||||
func (c *conn) reset(pstmt uintptr) error {
|
||||
if rc := sqlite3.Xsqlite3_reset(c.tls, pstmt); rc != sqlite3.SQLITE_OK {
|
||||
return c.errstr(rc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
19
vendor/modernc.org/sqlite/rulimit.go
generated
vendored
Normal file
19
vendor/modernc.org/sqlite/rulimit.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2021 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build linux || darwin || netbsd || openbsd
|
||||
// +build linux darwin netbsd openbsd
|
||||
|
||||
package sqlite // import "modernc.org/sqlite"
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func setMaxOpenFiles(n int64) error {
|
||||
var rLimit unix.Rlimit
|
||||
rLimit.Max = uint64(n)
|
||||
rLimit.Cur = uint64(n)
|
||||
return unix.Setrlimit(unix.RLIMIT_NOFILE, &rLimit)
|
||||
}
|
||||
883
vendor/modernc.org/sqlite/sqlite.go
generated
vendored
Normal file
883
vendor/modernc.org/sqlite/sqlite.go
generated
vendored
Normal file
@@ -0,0 +1,883 @@
|
||||
// Copyright 2017 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run generator.go -full-path-comments
|
||||
|
||||
package sqlite // import "modernc.org/sqlite"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/bits"
|
||||
"net/url"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"modernc.org/libc"
|
||||
"modernc.org/libc/sys/types"
|
||||
sqlite3 "modernc.org/sqlite/lib"
|
||||
)
|
||||
|
||||
var (
|
||||
_ driver.Conn = (*conn)(nil)
|
||||
_ driver.Driver = (*Driver)(nil)
|
||||
//lint:ignore SA1019 TODO implement ExecerContext
|
||||
_ driver.Execer = (*conn)(nil)
|
||||
//lint:ignore SA1019 TODO implement QueryerContext
|
||||
_ driver.Queryer = (*conn)(nil)
|
||||
_ driver.Result = (*result)(nil)
|
||||
_ driver.Rows = (*rows)(nil)
|
||||
_ driver.RowsColumnTypeDatabaseTypeName = (*rows)(nil)
|
||||
_ driver.RowsColumnTypeLength = (*rows)(nil)
|
||||
_ driver.RowsColumnTypeNullable = (*rows)(nil)
|
||||
_ driver.RowsColumnTypePrecisionScale = (*rows)(nil)
|
||||
_ driver.RowsColumnTypeScanType = (*rows)(nil)
|
||||
_ driver.Stmt = (*stmt)(nil)
|
||||
_ driver.Tx = (*tx)(nil)
|
||||
_ error = (*Error)(nil)
|
||||
)
|
||||
|
||||
const (
|
||||
driverName = "sqlite"
|
||||
ptrSize = unsafe.Sizeof(uintptr(0))
|
||||
sqliteLockedSharedcache = sqlite3.SQLITE_LOCKED | (1 << 8)
|
||||
)
|
||||
|
||||
func init() {
|
||||
sql.Register(driverName, newDriver())
|
||||
sqlite3.PatchIssue199() // https://gitlab.com/cznic/sqlite/-/issues/199
|
||||
|
||||
}
|
||||
|
||||
// Inspired by mattn/go-sqlite3: https://github.com/mattn/go-sqlite3/blob/ab91e934/sqlite3.go#L210-L226
|
||||
//
|
||||
// These time.Parse formats handle formats 1 through 7 listed at https://www.sqlite.org/lang_datefunc.html.
|
||||
var parseTimeFormats = []string{
|
||||
"2006-01-02 15:04:05.999999999-07:00",
|
||||
"2006-01-02T15:04:05.999999999-07:00",
|
||||
"2006-01-02 15:04:05.999999999",
|
||||
"2006-01-02T15:04:05.999999999",
|
||||
"2006-01-02 15:04",
|
||||
"2006-01-02T15:04",
|
||||
"2006-01-02",
|
||||
}
|
||||
|
||||
// interruptOnDone sets up a goroutine to interrupt the provided db when the
|
||||
// context is canceled, and returns a function the caller must defer so it
|
||||
// doesn't interrupt after the caller finishes.
|
||||
func interruptOnDone(
|
||||
ctx context.Context,
|
||||
c *conn,
|
||||
done *int32,
|
||||
) func() {
|
||||
if done == nil {
|
||||
var d int32
|
||||
done = &d
|
||||
}
|
||||
// donemu prevents a TOCTOU logical race between checking the done flag and
|
||||
// calling interrupt in the select statement below.
|
||||
var donemu sync.Mutex
|
||||
|
||||
donech := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// don't call interrupt if we were already done: it indicates that this
|
||||
// call to exec is no longer running and we would be interrupting
|
||||
// nothing, or even possibly an unrelated later call to exec.
|
||||
donemu.Lock()
|
||||
if atomic.CompareAndSwapInt32(done, 0, 1) {
|
||||
c.interrupt(c.db)
|
||||
}
|
||||
donemu.Unlock()
|
||||
case <-donech:
|
||||
}
|
||||
}()
|
||||
|
||||
// the caller is expected to defer this function
|
||||
return func() {
|
||||
// set the done flag so that a context cancellation right after the caller
|
||||
// returns doesn't trigger a call to interrupt for some other statement.
|
||||
donemu.Lock()
|
||||
atomic.StoreInt32(done, 1)
|
||||
donemu.Unlock()
|
||||
close(donech)
|
||||
}
|
||||
}
|
||||
|
||||
func getVFSName(query string) (r string, err error) {
|
||||
q, err := url.ParseQuery(query)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, v := range q["vfs"] {
|
||||
if r != "" && r != v {
|
||||
return "", fmt.Errorf("conflicting vfs query parameters: %v", q["vfs"])
|
||||
}
|
||||
|
||||
r = v
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func applyQueryParams(c *conn, query string) error {
|
||||
q, err := url.ParseQuery(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var a []string
|
||||
for _, v := range q["_pragma"] {
|
||||
a = append(a, v)
|
||||
}
|
||||
// Push 'busy_timeout' first, the rest in lexicographic order, case insenstive.
|
||||
// See https://gitlab.com/cznic/sqlite/-/issues/198#note_2233423463 for
|
||||
// discussion.
|
||||
sort.Slice(a, func(i, j int) bool {
|
||||
x, y := strings.TrimSpace(strings.ToLower(a[i])), strings.TrimSpace(strings.ToLower(a[j]))
|
||||
if strings.HasPrefix(x, "busy_timeout") {
|
||||
return true
|
||||
}
|
||||
if strings.HasPrefix(y, "busy_timeout") {
|
||||
return false
|
||||
}
|
||||
|
||||
return x < y
|
||||
})
|
||||
for _, v := range a {
|
||||
cmd := "pragma " + v
|
||||
_, err := c.exec(context.Background(), cmd, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if v := q.Get("_time_format"); v != "" {
|
||||
f, ok := writeTimeFormats[v]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown _time_format %q", v)
|
||||
}
|
||||
c.writeTimeFormat = f
|
||||
}
|
||||
if v := q.Get("_time_integer_format"); v != "" {
|
||||
switch v {
|
||||
case "unix":
|
||||
case "unix_milli":
|
||||
case "unix_micro":
|
||||
case "unix_nano":
|
||||
default:
|
||||
return fmt.Errorf("unknown _time_integer_format %q", v)
|
||||
}
|
||||
c.integerTimeFormat = v
|
||||
}
|
||||
|
||||
if v := q.Get("_txlock"); v != "" {
|
||||
lower := strings.ToLower(v)
|
||||
if lower != "deferred" && lower != "immediate" && lower != "exclusive" {
|
||||
return fmt.Errorf("unknown _txlock %q", v)
|
||||
}
|
||||
c.beginMode = v
|
||||
}
|
||||
|
||||
if v := q.Get("_inttotime"); v != "" {
|
||||
onoff, err := strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unknown _inttotime %q, must be 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False",
|
||||
v)
|
||||
}
|
||||
c.intToTime = onoff
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func unlockNotify(t *libc.TLS, ppArg uintptr, nArg int32) {
|
||||
for i := int32(0); i < nArg; i++ {
|
||||
mu := *(*uintptr)(unsafe.Pointer(ppArg))
|
||||
(*mutex)(unsafe.Pointer(mu)).Unlock()
|
||||
ppArg += ptrSize
|
||||
}
|
||||
}
|
||||
|
||||
// FunctionImpl describes an [application-defined SQL function]. If Scalar is
|
||||
// set, it is treated as a scalar function; otherwise, it is treated as an
|
||||
// aggregate function using MakeAggregate.
|
||||
//
|
||||
// [application-defined SQL function]: https://sqlite.org/appfunc.html
|
||||
type FunctionImpl struct {
|
||||
// NArgs is the required number of arguments that the function accepts.
|
||||
// If NArgs is negative, then the function is variadic.
|
||||
NArgs int32
|
||||
|
||||
// If Deterministic is true, the function must always give the same
|
||||
// output when the input parameters are the same. This enables functions
|
||||
// to be used in additional contexts like the WHERE clause of partial
|
||||
// indexes and enables additional optimizations.
|
||||
//
|
||||
// See https://sqlite.org/c3ref/c_deterministic.html#sqlitedeterministic
|
||||
// for more details.
|
||||
Deterministic bool
|
||||
|
||||
// Scalar is called when a scalar function is invoked in SQL. The
|
||||
// argument Values are not valid past the return of the function.
|
||||
Scalar func(ctx *FunctionContext, args []driver.Value) (driver.Value, error)
|
||||
|
||||
// MakeAggregate is called at the beginning of each evaluation of an
|
||||
// aggregate function.
|
||||
MakeAggregate func(ctx FunctionContext) (AggregateFunction, error)
|
||||
}
|
||||
|
||||
// An AggregateFunction is an invocation of an aggregate or window function. See
|
||||
// the documentation for [aggregate function callbacks] and [application-defined
|
||||
// window functions] for an overview.
|
||||
//
|
||||
// [aggregate function callbacks]: https://www.sqlite.org/appfunc.html#the_aggregate_function_callbacks
|
||||
// [application-defined window functions]: https://www.sqlite.org/windowfunctions.html#user_defined_aggregate_window_functions
|
||||
type AggregateFunction interface {
|
||||
// Step is called for each row of an aggregate function's SQL
|
||||
// invocation. The argument Values are not valid past the return of the
|
||||
// function.
|
||||
Step(ctx *FunctionContext, rowArgs []driver.Value) error
|
||||
|
||||
// WindowInverse is called to remove the oldest presently aggregated
|
||||
// result of Step from the current window. The arguments are those
|
||||
// passed to Step for the row being removed. The argument Values are not
|
||||
// valid past the return of the function.
|
||||
WindowInverse(ctx *FunctionContext, rowArgs []driver.Value) error
|
||||
|
||||
// WindowValue is called to get the current value of an aggregate
|
||||
// function. This is used to return the final value of the function,
|
||||
// whether it is used as a window function or not.
|
||||
WindowValue(ctx *FunctionContext) (driver.Value, error)
|
||||
|
||||
// Final is called after all of the aggregate function's input rows have
|
||||
// been stepped through. No other methods will be called on the
|
||||
// AggregateFunction after calling Final. WindowValue returns the value
|
||||
// from the function.
|
||||
Final(ctx *FunctionContext)
|
||||
}
|
||||
|
||||
type collation struct {
|
||||
zName uintptr
|
||||
pApp uintptr
|
||||
enc int32
|
||||
}
|
||||
|
||||
// RegisterCollationUtf8 makes a Go function available as a collation named zName.
|
||||
// impl receives two UTF-8 strings: left and right.
|
||||
// The result needs to be:
|
||||
//
|
||||
// - 0 if left == right
|
||||
// - 1 if left < right
|
||||
// - +1 if left > right
|
||||
//
|
||||
// impl must always return the same result given the same inputs.
|
||||
// Additionally, it must have the following properties for all strings A, B and C:
|
||||
// - if A==B, then B==A
|
||||
// - if A==B and B==C, then A==C
|
||||
// - if A<B, then B>A
|
||||
// - if A<B and B<C, then A<C.
|
||||
//
|
||||
// The new collation will be available to all new connections opened after
|
||||
// executing RegisterCollationUtf8.
|
||||
func RegisterCollationUtf8(
|
||||
zName string,
|
||||
impl func(left, right string) int,
|
||||
) error {
|
||||
return registerCollation(zName, impl, sqlite3.SQLITE_UTF8)
|
||||
}
|
||||
|
||||
// MustRegisterCollationUtf8 is like RegisterCollationUtf8 but panics on error.
|
||||
func MustRegisterCollationUtf8(
|
||||
zName string,
|
||||
impl func(left, right string) int,
|
||||
) {
|
||||
if err := RegisterCollationUtf8(zName, impl); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func registerCollation(
|
||||
zName string,
|
||||
impl func(left, right string) int,
|
||||
enc int32,
|
||||
) error {
|
||||
if _, ok := d.collations[zName]; ok {
|
||||
return fmt.Errorf("a collation %q is already registered", zName)
|
||||
}
|
||||
|
||||
// dont free, collations registered on the driver live as long as the program
|
||||
name, err := libc.CString(zName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
xCollations.mu.Lock()
|
||||
id := xCollations.ids.next()
|
||||
xCollations.m[id] = impl
|
||||
xCollations.mu.Unlock()
|
||||
|
||||
d.collations[zName] = &collation{
|
||||
zName: name,
|
||||
pApp: id,
|
||||
enc: enc,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type ExecQuerierContext interface {
|
||||
driver.ExecerContext
|
||||
driver.QueryerContext
|
||||
}
|
||||
|
||||
type HookRegisterer interface {
|
||||
RegisterPreUpdateHook(PreUpdateHookFn)
|
||||
RegisterCommitHook(CommitHookFn)
|
||||
RegisterRollbackHook(RollbackHookFn)
|
||||
}
|
||||
|
||||
// ConnectionHookFn function type for a connection hook on the Driver. Connection
|
||||
// hooks are called after the connection has been set up.
|
||||
type ConnectionHookFn func(
|
||||
conn ExecQuerierContext,
|
||||
dsn string,
|
||||
) error
|
||||
|
||||
// FunctionContext represents the context user defined functions execute in.
|
||||
// Fields and/or methods of this type may get addedd in the future.
|
||||
type FunctionContext struct {
|
||||
tls *libc.TLS
|
||||
ctx uintptr
|
||||
}
|
||||
|
||||
const sqliteValPtrSize = unsafe.Sizeof(&sqlite3.Sqlite3_value{})
|
||||
|
||||
// RegisterFunction registers a function named zFuncName with nArg arguments.
|
||||
// Passing -1 for nArg indicates the function is variadic. The FunctionImpl
|
||||
// determines whether the function is deterministic or not, and whether it is a
|
||||
// scalar function (when Scalar is defined) or an aggregate function (when
|
||||
// Scalar is not defined and MakeAggregate is defined).
|
||||
//
|
||||
// The new function will be available to all new connections opened after
|
||||
// executing RegisterFunction.
|
||||
func RegisterFunction(
|
||||
zFuncName string,
|
||||
impl *FunctionImpl,
|
||||
) error {
|
||||
return registerFunction(zFuncName, impl)
|
||||
}
|
||||
|
||||
// MustRegisterFunction is like RegisterFunction but panics on error.
|
||||
func MustRegisterFunction(
|
||||
zFuncName string,
|
||||
impl *FunctionImpl,
|
||||
) {
|
||||
if err := RegisterFunction(zFuncName, impl); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterScalarFunction registers a scalar function named zFuncName with nArg
|
||||
// arguments. Passing -1 for nArg indicates the function is variadic.
|
||||
//
|
||||
// The new function will be available to all new connections opened after
|
||||
// executing RegisterScalarFunction.
|
||||
func RegisterScalarFunction(
|
||||
zFuncName string,
|
||||
nArg int32,
|
||||
xFunc func(ctx *FunctionContext, args []driver.Value) (driver.Value, error),
|
||||
) (err error) {
|
||||
if dmesgs {
|
||||
defer func() {
|
||||
dmesg("zFuncName %q, nArg %v, xFunc %p: err %v", zFuncName, nArg, xFunc, err)
|
||||
}()
|
||||
}
|
||||
return registerFunction(zFuncName, &FunctionImpl{NArgs: nArg, Scalar: xFunc, Deterministic: false})
|
||||
}
|
||||
|
||||
// MustRegisterScalarFunction is like RegisterScalarFunction but panics on
|
||||
// error.
|
||||
func MustRegisterScalarFunction(
|
||||
zFuncName string,
|
||||
nArg int32,
|
||||
xFunc func(ctx *FunctionContext, args []driver.Value) (driver.Value, error),
|
||||
) {
|
||||
if dmesgs {
|
||||
dmesg("zFuncName %q, nArg %v, xFunc %p", zFuncName, nArg, xFunc)
|
||||
}
|
||||
if err := RegisterScalarFunction(zFuncName, nArg, xFunc); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// MustRegisterDeterministicScalarFunction is like
|
||||
// RegisterDeterministicScalarFunction but panics on error.
|
||||
func MustRegisterDeterministicScalarFunction(
|
||||
zFuncName string,
|
||||
nArg int32,
|
||||
xFunc func(ctx *FunctionContext, args []driver.Value) (driver.Value, error),
|
||||
) {
|
||||
if dmesgs {
|
||||
dmesg("zFuncName %q, nArg %v, xFunc %p", zFuncName, nArg, xFunc)
|
||||
}
|
||||
if err := RegisterDeterministicScalarFunction(zFuncName, nArg, xFunc); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterDeterministicScalarFunction registers a deterministic scalar
|
||||
// function named zFuncName with nArg arguments. Passing -1 for nArg indicates
|
||||
// the function is variadic. A deterministic function means that the function
|
||||
// always gives the same output when the input parameters are the same.
|
||||
//
|
||||
// The new function will be available to all new connections opened after
|
||||
// executing RegisterDeterministicScalarFunction.
|
||||
func RegisterDeterministicScalarFunction(
|
||||
zFuncName string,
|
||||
nArg int32,
|
||||
xFunc func(ctx *FunctionContext, args []driver.Value) (driver.Value, error),
|
||||
) (err error) {
|
||||
if dmesgs {
|
||||
defer func() {
|
||||
dmesg("zFuncName %q, nArg %v, xFunc %p: err %v", zFuncName, nArg, xFunc, err)
|
||||
}()
|
||||
}
|
||||
return registerFunction(zFuncName, &FunctionImpl{NArgs: nArg, Scalar: xFunc, Deterministic: true})
|
||||
}
|
||||
|
||||
func registerFunction(
|
||||
zFuncName string,
|
||||
impl *FunctionImpl,
|
||||
) error {
|
||||
|
||||
if _, ok := d.udfs[zFuncName]; ok {
|
||||
return fmt.Errorf("a function named %q is already registered", zFuncName)
|
||||
}
|
||||
|
||||
// dont free, functions registered on the driver live as long as the program
|
||||
name, err := libc.CString(zFuncName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var textrep int32 = sqlite3.SQLITE_UTF8
|
||||
|
||||
if impl.Deterministic {
|
||||
textrep |= sqlite3.SQLITE_DETERMINISTIC
|
||||
}
|
||||
|
||||
udf := &userDefinedFunction{
|
||||
zFuncName: name,
|
||||
nArg: impl.NArgs,
|
||||
eTextRep: textrep,
|
||||
}
|
||||
|
||||
if impl.Scalar != nil {
|
||||
xFuncs.mu.Lock()
|
||||
id := xFuncs.ids.next()
|
||||
xFuncs.m[id] = impl.Scalar
|
||||
xFuncs.mu.Unlock()
|
||||
|
||||
udf.scalar = true
|
||||
udf.pApp = id
|
||||
} else {
|
||||
xAggregateFactories.mu.Lock()
|
||||
id := xAggregateFactories.ids.next()
|
||||
xAggregateFactories.m[id] = impl.MakeAggregate
|
||||
xAggregateFactories.mu.Unlock()
|
||||
|
||||
udf.pApp = id
|
||||
}
|
||||
|
||||
d.udfs[zFuncName] = udf
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterConnectionHook registers a function to be called after each connection
|
||||
// is opened. This is called after all the connection has been set up.
|
||||
func RegisterConnectionHook(fn ConnectionHookFn) {
|
||||
d.RegisterConnectionHook(fn)
|
||||
}
|
||||
|
||||
func origin(skip int) string {
|
||||
pc, fn, fl, _ := runtime.Caller(skip)
|
||||
f := runtime.FuncForPC(pc)
|
||||
var fns string
|
||||
if f != nil {
|
||||
fns = f.Name()
|
||||
if x := strings.LastIndex(fns, "."); x > 0 {
|
||||
fns = fns[x+1:]
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%s:%d:%s", fn, fl, fns)
|
||||
}
|
||||
|
||||
func errorResultFunction(tls *libc.TLS, ctx uintptr) func(error) {
|
||||
return func(res error) {
|
||||
errmsg, cerr := libc.CString(res.Error())
|
||||
if cerr != nil {
|
||||
panic(cerr)
|
||||
}
|
||||
defer libc.Xfree(tls, errmsg)
|
||||
sqlite3.Xsqlite3_result_error(tls, ctx, errmsg, -1)
|
||||
sqlite3.Xsqlite3_result_error_code(tls, ctx, sqlite3.SQLITE_ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
func functionArgs(tls *libc.TLS, argc int32, argv uintptr) []driver.Value {
|
||||
args := make([]driver.Value, argc)
|
||||
for i := int32(0); i < argc; i++ {
|
||||
valPtr := *(*uintptr)(unsafe.Pointer(argv + uintptr(i)*sqliteValPtrSize))
|
||||
|
||||
switch valType := sqlite3.Xsqlite3_value_type(tls, valPtr); valType {
|
||||
case sqlite3.SQLITE_TEXT:
|
||||
args[i] = libc.GoString(sqlite3.Xsqlite3_value_text(tls, valPtr))
|
||||
case sqlite3.SQLITE_INTEGER:
|
||||
args[i] = sqlite3.Xsqlite3_value_int64(tls, valPtr)
|
||||
case sqlite3.SQLITE_FLOAT:
|
||||
args[i] = sqlite3.Xsqlite3_value_double(tls, valPtr)
|
||||
case sqlite3.SQLITE_NULL:
|
||||
args[i] = nil
|
||||
case sqlite3.SQLITE_BLOB:
|
||||
size := sqlite3.Xsqlite3_value_bytes(tls, valPtr)
|
||||
blobPtr := sqlite3.Xsqlite3_value_blob(tls, valPtr)
|
||||
v := make([]byte, size)
|
||||
if size != 0 {
|
||||
copy(v, (*libc.RawMem)(unsafe.Pointer(blobPtr))[:size:size])
|
||||
}
|
||||
args[i] = v
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected argument type %q passed by sqlite", valType))
|
||||
}
|
||||
}
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
func functionReturnValue(tls *libc.TLS, ctx uintptr, res driver.Value) error {
|
||||
switch resTyped := res.(type) {
|
||||
case nil:
|
||||
sqlite3.Xsqlite3_result_null(tls, ctx)
|
||||
case int64:
|
||||
sqlite3.Xsqlite3_result_int64(tls, ctx, resTyped)
|
||||
case float64:
|
||||
sqlite3.Xsqlite3_result_double(tls, ctx, resTyped)
|
||||
case bool:
|
||||
sqlite3.Xsqlite3_result_int(tls, ctx, libc.Bool32(resTyped))
|
||||
case time.Time:
|
||||
sqlite3.Xsqlite3_result_int64(tls, ctx, resTyped.Unix())
|
||||
case string:
|
||||
size := int32(len(resTyped))
|
||||
cstr, err := libc.CString(resTyped)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer libc.Xfree(tls, cstr)
|
||||
sqlite3.Xsqlite3_result_text(tls, ctx, cstr, size, sqlite3.SQLITE_TRANSIENT)
|
||||
case []byte:
|
||||
size := int32(len(resTyped))
|
||||
if size == 0 {
|
||||
sqlite3.Xsqlite3_result_zeroblob(tls, ctx, 0)
|
||||
return nil
|
||||
}
|
||||
p := libc.Xmalloc(tls, types.Size_t(size))
|
||||
if p == 0 {
|
||||
panic(fmt.Sprintf("unable to allocate space for blob: %d", size))
|
||||
}
|
||||
defer libc.Xfree(tls, p)
|
||||
copy((*libc.RawMem)(unsafe.Pointer(p))[:size:size], resTyped)
|
||||
|
||||
sqlite3.Xsqlite3_result_blob(tls, ctx, p, size, sqlite3.SQLITE_TRANSIENT)
|
||||
default:
|
||||
return fmt.Errorf("function did not return a valid driver.Value: %T", resTyped)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// The below is all taken from zombiezen.com/go/sqlite. Aggregate functions need
|
||||
// to maintain state (for instance, the count of values seen so far). We give
|
||||
// each aggregate function an ID, generated by idGen, and put that in the pApp
|
||||
// argument to sqlite3_create_function. We track this on the Go side in
|
||||
// xAggregateFactories.
|
||||
//
|
||||
// When (if) the function is called is called by a query, we call the
|
||||
// MakeAggregate factory function to set it up, and track that in
|
||||
// xAggregateContext, retrieving it via sqlite3_aggregate_context.
|
||||
//
|
||||
// We also need to ensure that, for both aggregate and scalar functions, the
|
||||
// function pointer we pass to SQLite meets certain rules on the Go side, so
|
||||
// that the pointer remains valid.
|
||||
var (
|
||||
xFuncs = struct {
|
||||
mu sync.RWMutex
|
||||
m map[uintptr]func(*FunctionContext, []driver.Value) (driver.Value, error)
|
||||
ids idGen
|
||||
}{
|
||||
m: make(map[uintptr]func(*FunctionContext, []driver.Value) (driver.Value, error)),
|
||||
}
|
||||
|
||||
xAggregateFactories = struct {
|
||||
mu sync.RWMutex
|
||||
m map[uintptr]func(FunctionContext) (AggregateFunction, error)
|
||||
ids idGen
|
||||
}{
|
||||
m: make(map[uintptr]func(FunctionContext) (AggregateFunction, error)),
|
||||
}
|
||||
|
||||
xAggregateContext = struct {
|
||||
mu sync.RWMutex
|
||||
m map[uintptr]AggregateFunction
|
||||
ids idGen
|
||||
}{
|
||||
m: make(map[uintptr]AggregateFunction),
|
||||
}
|
||||
|
||||
xCollations = struct {
|
||||
mu sync.RWMutex
|
||||
m map[uintptr]func(string, string) int
|
||||
ids idGen
|
||||
}{
|
||||
m: make(map[uintptr]func(string, string) int),
|
||||
}
|
||||
)
|
||||
|
||||
type idGen struct {
|
||||
bitset []uint64
|
||||
}
|
||||
|
||||
func (gen *idGen) next() uintptr {
|
||||
base := uintptr(1)
|
||||
for i := 0; i < len(gen.bitset); i, base = i+1, base+64 {
|
||||
b := gen.bitset[i]
|
||||
if b != 1<<64-1 {
|
||||
n := uintptr(bits.TrailingZeros64(^b))
|
||||
gen.bitset[i] |= 1 << n
|
||||
return base + n
|
||||
}
|
||||
}
|
||||
gen.bitset = append(gen.bitset, 1)
|
||||
return base
|
||||
}
|
||||
|
||||
func (gen *idGen) reclaim(id uintptr) {
|
||||
bit := id - 1
|
||||
gen.bitset[bit/64] &^= 1 << (bit % 64)
|
||||
}
|
||||
|
||||
func makeAggregate(tls *libc.TLS, ctx uintptr) (AggregateFunction, uintptr) {
|
||||
goCtx := FunctionContext{tls: tls, ctx: ctx}
|
||||
aggCtx := (*uintptr)(unsafe.Pointer(sqlite3.Xsqlite3_aggregate_context(tls, ctx, int32(ptrSize))))
|
||||
setErrorResult := errorResultFunction(tls, ctx)
|
||||
if aggCtx == nil {
|
||||
setErrorResult(errors.New("insufficient memory for aggregate"))
|
||||
return nil, 0
|
||||
}
|
||||
if *aggCtx != 0 {
|
||||
// Already created.
|
||||
xAggregateContext.mu.RLock()
|
||||
f := xAggregateContext.m[*aggCtx]
|
||||
xAggregateContext.mu.RUnlock()
|
||||
return f, *aggCtx
|
||||
}
|
||||
|
||||
factoryID := sqlite3.Xsqlite3_user_data(tls, ctx)
|
||||
xAggregateFactories.mu.RLock()
|
||||
factory := xAggregateFactories.m[factoryID]
|
||||
xAggregateFactories.mu.RUnlock()
|
||||
|
||||
f, err := factory(goCtx)
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
return nil, 0
|
||||
}
|
||||
if f == nil {
|
||||
setErrorResult(errors.New("MakeAggregate function returned nil"))
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
xAggregateContext.mu.Lock()
|
||||
*aggCtx = xAggregateContext.ids.next()
|
||||
xAggregateContext.m[*aggCtx] = f
|
||||
xAggregateContext.mu.Unlock()
|
||||
return f, *aggCtx
|
||||
}
|
||||
|
||||
// cFuncPointer converts a function defined by a function declaration to a C pointer.
|
||||
// The result of using cFuncPointer on closures is undefined.
|
||||
func cFuncPointer[T any](f T) uintptr {
|
||||
// This assumes the memory representation described in https://golang.org/s/go11func.
|
||||
//
|
||||
// cFuncPointer does its conversion by doing the following in order:
|
||||
// 1) Create a Go struct containing a pointer to a pointer to
|
||||
// the function. It is assumed that the pointer to the function will be
|
||||
// stored in the read-only data section and thus will not move.
|
||||
// 2) Convert the pointer to the Go struct to a pointer to uintptr through
|
||||
// unsafe.Pointer. This is permitted via Rule #1 of unsafe.Pointer.
|
||||
// 3) Dereference the pointer to uintptr to obtain the function value as a
|
||||
// uintptr. This is safe as long as function values are passed as pointers.
|
||||
return *(*uintptr)(unsafe.Pointer(&struct{ f T }{f}))
|
||||
}
|
||||
|
||||
func funcTrampoline(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr) {
|
||||
id := sqlite3.Xsqlite3_user_data(tls, ctx)
|
||||
xFuncs.mu.RLock()
|
||||
xFunc := xFuncs.m[id]
|
||||
xFuncs.mu.RUnlock()
|
||||
|
||||
setErrorResult := errorResultFunction(tls, ctx)
|
||||
res, err := xFunc(&FunctionContext{}, functionArgs(tls, argc, argv))
|
||||
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = functionReturnValue(tls, ctx, res)
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
}
|
||||
}
|
||||
|
||||
// sqlite3AllocCString allocates a NUL-terminated copy of s using SQLite's
|
||||
// memory allocator (sqlite3_malloc). The caller must arrange for SQLite to
|
||||
// free the returned pointer via sqlite3_free.
|
||||
func sqlite3AllocCString(tls *libc.TLS, s string) uintptr {
|
||||
n := len(s) + 1
|
||||
p := sqlite3.Xsqlite3_malloc(tls, int32(n))
|
||||
if p == 0 {
|
||||
return 0
|
||||
}
|
||||
mem := (*libc.RawMem)(unsafe.Pointer(p))[:n:n]
|
||||
copy(mem, []byte(s))
|
||||
mem[n-1] = 0
|
||||
return p
|
||||
}
|
||||
|
||||
func stepTrampoline(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr) {
|
||||
impl, _ := makeAggregate(tls, ctx)
|
||||
if impl == nil {
|
||||
return
|
||||
}
|
||||
|
||||
setErrorResult := errorResultFunction(tls, ctx)
|
||||
err := impl.Step(&FunctionContext{}, functionArgs(tls, argc, argv))
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
}
|
||||
}
|
||||
|
||||
func inverseTrampoline(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr) {
|
||||
impl, _ := makeAggregate(tls, ctx)
|
||||
if impl == nil {
|
||||
return
|
||||
}
|
||||
|
||||
setErrorResult := errorResultFunction(tls, ctx)
|
||||
err := impl.WindowInverse(&FunctionContext{}, functionArgs(tls, argc, argv))
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
}
|
||||
}
|
||||
|
||||
func valueTrampoline(tls *libc.TLS, ctx uintptr) {
|
||||
impl, _ := makeAggregate(tls, ctx)
|
||||
if impl == nil {
|
||||
return
|
||||
}
|
||||
|
||||
setErrorResult := errorResultFunction(tls, ctx)
|
||||
res, err := impl.WindowValue(&FunctionContext{})
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
} else {
|
||||
err = functionReturnValue(tls, ctx, res)
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func finalTrampoline(tls *libc.TLS, ctx uintptr) {
|
||||
impl, id := makeAggregate(tls, ctx)
|
||||
if impl == nil {
|
||||
return
|
||||
}
|
||||
|
||||
setErrorResult := errorResultFunction(tls, ctx)
|
||||
res, err := impl.WindowValue(&FunctionContext{})
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
} else {
|
||||
err = functionReturnValue(tls, ctx, res)
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
}
|
||||
}
|
||||
impl.Final(&FunctionContext{})
|
||||
|
||||
xAggregateContext.mu.Lock()
|
||||
defer xAggregateContext.mu.Unlock()
|
||||
delete(xAggregateContext.m, id)
|
||||
xAggregateContext.ids.reclaim(id)
|
||||
}
|
||||
|
||||
func collationTrampoline(tls *libc.TLS, pApp uintptr, nLeft int32, zLeft uintptr, nRight int32, zRight uintptr) int32 {
|
||||
xCollations.mu.RLock()
|
||||
xCollation := xCollations.m[pApp]
|
||||
xCollations.mu.RUnlock()
|
||||
|
||||
left := string(libc.GoBytes(zLeft, int(nLeft)))
|
||||
right := string(libc.GoBytes(zRight, int(nRight)))
|
||||
|
||||
// res is of type int, which can be 64-bit wide
|
||||
// Since we just need to know if the value is positive, negative, or zero, we can ensure it's -1, 0, +1
|
||||
res := xCollation(left, right)
|
||||
switch {
|
||||
case res < 0:
|
||||
return -1
|
||||
case res == 0:
|
||||
return 0
|
||||
case res > 0:
|
||||
return 1
|
||||
default:
|
||||
// Should never hit here, make the compiler happy
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// Limit calls sqlite3_limit, see the docs at
|
||||
// https://www.sqlite.org/c3ref/limit.html for details.
|
||||
//
|
||||
// To get a sql.Conn from a *sql.DB, use (*sql.DB).Conn(). Limits are bound to
|
||||
// the particular instance of 'c', so getting a new connection only to pass it
|
||||
// to Limit is possibly not useful above querying what are the various
|
||||
// configured default values.
|
||||
func Limit(c *sql.Conn, id int, newVal int) (r int, err error) {
|
||||
err = c.Raw(func(driverConn any) error {
|
||||
switch dc := driverConn.(type) {
|
||||
case *conn:
|
||||
r = dc.limit(id, newVal)
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("unexpected driverConn type: %T", driverConn)
|
||||
}
|
||||
})
|
||||
return r, err
|
||||
|
||||
}
|
||||
472
vendor/modernc.org/sqlite/stmt.go
generated
vendored
Normal file
472
vendor/modernc.org/sqlite/stmt.go
generated
vendored
Normal file
@@ -0,0 +1,472 @@
|
||||
// Copyright 2025 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite // import "modernc.org/sqlite"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
|
||||
"modernc.org/libc"
|
||||
sqlite3 "modernc.org/sqlite/lib"
|
||||
)
|
||||
|
||||
type stmt struct {
|
||||
c *conn
|
||||
psql uintptr
|
||||
pstmt uintptr // The cached SQLite statement handle
|
||||
}
|
||||
|
||||
func newStmt(c *conn, sql string) (*stmt, error) {
|
||||
p, err := libc.CString(sql)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := &stmt{c: c, psql: p}
|
||||
|
||||
// Attempt to prepare the statement immediately
|
||||
// We make a copy of the pointer because prepareV2 advances it
|
||||
psql := p
|
||||
pstmt, err := c.prepareV2(&psql)
|
||||
if err != nil {
|
||||
c.free(p)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check if there is trailing SQL (indicating a script/multi-statement)
|
||||
// If *psql (the tail) is 0, we consumed the whole string.
|
||||
hasTail := *(*byte)(unsafe.Pointer(psql)) != 0
|
||||
if pstmt != 0 && !hasTail {
|
||||
// Optimization: Single statement. Cache it.
|
||||
s.pstmt = pstmt
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// It is either a script (hasTail) or a comment-only string (pstmt==0).
|
||||
// For scripts: Finalize now. We will re-parse iteratively in Exec/Query
|
||||
// to handle the multiple statements correctly using the existing loop logic.
|
||||
if pstmt != 0 {
|
||||
if err := c.finalize(pstmt); err != nil {
|
||||
c.free(p)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Close closes the statement.
|
||||
//
|
||||
// As of Go 1.1, a Stmt will not be closed if it's in use by any queries.
|
||||
func (s *stmt) Close() (err error) {
|
||||
if s.pstmt != 0 {
|
||||
if e := s.c.finalize(s.pstmt); e != nil {
|
||||
err = e
|
||||
}
|
||||
s.pstmt = 0
|
||||
}
|
||||
if s.psql != 0 {
|
||||
s.c.free(s.psql)
|
||||
s.psql = 0
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Exec executes a query that doesn't return rows, such as an INSERT or UPDATE.
|
||||
//
|
||||
// Deprecated: Drivers should implement StmtExecContext instead (or
|
||||
// additionally).
|
||||
func (s *stmt) Exec(args []driver.Value) (driver.Result, error) { //TODO StmtExecContext
|
||||
return s.exec(context.Background(), toNamedValues(args))
|
||||
}
|
||||
|
||||
// toNamedValues converts []driver.Value to []driver.NamedValue
|
||||
func toNamedValues(vals []driver.Value) (r []driver.NamedValue) {
|
||||
r = make([]driver.NamedValue, len(vals))
|
||||
for i, val := range vals {
|
||||
r[i] = driver.NamedValue{Value: val, Ordinal: i + 1}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (s *stmt) exec(ctx context.Context, args []driver.NamedValue) (r driver.Result, err error) {
|
||||
var pstmt uintptr
|
||||
var done int32
|
||||
if ctx != nil {
|
||||
if ctxDone := ctx.Done(); ctxDone != nil {
|
||||
select {
|
||||
case <-ctxDone:
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
defer interruptOnDone(ctx, s.c, &done)()
|
||||
}
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if ctx != nil && atomic.LoadInt32(&done) != 0 {
|
||||
r, err = nil, ctx.Err()
|
||||
}
|
||||
if pstmt != 0 {
|
||||
// ensure stmt finalized.
|
||||
e := s.c.finalize(pstmt)
|
||||
|
||||
if err == nil && e != nil {
|
||||
// prioritize original
|
||||
// returned error.
|
||||
err = e
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// OPTIMIZED PATH: Single Cached Statement
|
||||
if s.pstmt != 0 {
|
||||
err = func() error {
|
||||
// Bind
|
||||
n, err := s.c.bindParameterCount(s.pstmt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != 0 {
|
||||
allocs, err := s.c.bind(s.pstmt, n, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Free allocations after step
|
||||
if len(allocs) != 0 {
|
||||
defer func() {
|
||||
for _, v := range allocs {
|
||||
s.c.free(v)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
// Step
|
||||
rc, err := s.c.step(s.pstmt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Handle Result
|
||||
switch rc & 0xff {
|
||||
case sqlite3.SQLITE_DONE, sqlite3.SQLITE_ROW:
|
||||
r, err = newResult(s.c)
|
||||
default:
|
||||
return s.c.errstr(int32(rc))
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
|
||||
// RESET (Crucial: Do not finalize)
|
||||
// We must reset the VM to allow reuse.
|
||||
// We also clear bindings to prevent leaking memory or state to next call.
|
||||
if resetErr := s.c.reset(s.pstmt); resetErr != nil && err == nil {
|
||||
err = resetErr
|
||||
}
|
||||
if clearErr := s.c.clearBindings(s.pstmt); clearErr != nil && err == nil {
|
||||
err = clearErr
|
||||
}
|
||||
return r, err
|
||||
}
|
||||
|
||||
// FALLBACK PATH: Multi-statement script
|
||||
for psql := s.psql; *(*byte)(unsafe.Pointer(psql)) != 0 && atomic.LoadInt32(&done) == 0; {
|
||||
if pstmt, err = s.c.prepareV2(&psql); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if pstmt == 0 {
|
||||
continue
|
||||
}
|
||||
err = func() (err error) {
|
||||
n, err := s.c.bindParameterCount(pstmt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n != 0 {
|
||||
allocs, err := s.c.bind(pstmt, n, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(allocs) != 0 {
|
||||
defer func() {
|
||||
for _, v := range allocs {
|
||||
s.c.free(v)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
rc, err := s.c.step(pstmt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch rc & 0xff {
|
||||
case sqlite3.SQLITE_DONE, sqlite3.SQLITE_ROW:
|
||||
r, err = newResult(s.c)
|
||||
default:
|
||||
return s.c.errstr(int32(rc))
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
e := s.c.finalize(pstmt)
|
||||
pstmt = 0 // done with
|
||||
|
||||
if err == nil && e != nil {
|
||||
// prioritize original
|
||||
// returned error.
|
||||
err = e
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return r, err
|
||||
}
|
||||
|
||||
// NumInput returns the number of placeholder parameters.
|
||||
//
|
||||
// If NumInput returns >= 0, the sql package will sanity check argument counts
|
||||
// from callers and return errors to the caller before the statement's Exec or
|
||||
// Query methods are called.
|
||||
//
|
||||
// NumInput may also return -1, if the driver doesn't know its number of
|
||||
// placeholders. In that case, the sql package will not sanity check Exec or
|
||||
// Query argument counts.
|
||||
func (s *stmt) NumInput() (n int) {
|
||||
return -1
|
||||
}
|
||||
|
||||
// Query executes a query that may return rows, such as a
|
||||
// SELECT.
|
||||
//
|
||||
// Deprecated: Drivers should implement StmtQueryContext instead (or
|
||||
// additionally).
|
||||
func (s *stmt) Query(args []driver.Value) (driver.Rows, error) { //TODO StmtQueryContext
|
||||
return s.query(context.Background(), toNamedValues(args))
|
||||
}
|
||||
|
||||
func (s *stmt) query(ctx context.Context, args []driver.NamedValue) (r driver.Rows, err error) {
|
||||
var pstmt uintptr
|
||||
var done int32
|
||||
if ctx != nil {
|
||||
if ctxDone := ctx.Done(); ctxDone != nil {
|
||||
select {
|
||||
case <-ctxDone:
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
defer interruptOnDone(ctx, s.c, &done)()
|
||||
}
|
||||
}
|
||||
|
||||
var allocs []uintptr
|
||||
|
||||
defer func() {
|
||||
if ctx != nil && atomic.LoadInt32(&done) != 0 {
|
||||
if r != nil {
|
||||
r.Close()
|
||||
}
|
||||
r, err = nil, ctx.Err()
|
||||
} else if r == nil && err == nil {
|
||||
r, err = newRows(s.c, pstmt, allocs, true)
|
||||
}
|
||||
|
||||
if pstmt != 0 {
|
||||
// ensure stmt finalized.
|
||||
e := s.c.finalize(pstmt)
|
||||
|
||||
if err == nil && e != nil {
|
||||
// prioritize original
|
||||
// returned error.
|
||||
err = e
|
||||
}
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
// OPTIMIZED PATH: Single Cached Statement
|
||||
if s.pstmt != 0 {
|
||||
// Bind
|
||||
n, err := s.c.bindParameterCount(s.pstmt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n != 0 {
|
||||
if allocs, err = s.c.bind(s.pstmt, n, args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Step
|
||||
rc, err := s.c.step(s.pstmt)
|
||||
if err != nil {
|
||||
// On error, we must free allocs manually because 'newRows' won't take ownership
|
||||
for _, v := range allocs {
|
||||
s.c.free(v)
|
||||
}
|
||||
s.c.reset(s.pstmt)
|
||||
s.c.clearBindings(s.pstmt)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Handle Result
|
||||
switch rc & 0xff {
|
||||
case sqlite3.SQLITE_ROW:
|
||||
// Pass reuseStmt=true
|
||||
if r, err = newRows(s.c, s.pstmt, allocs, false); err != nil {
|
||||
s.c.reset(s.pstmt)
|
||||
s.c.clearBindings(s.pstmt)
|
||||
return nil, err
|
||||
}
|
||||
r.(*rows).reuseStmt = true
|
||||
return r, nil
|
||||
|
||||
case sqlite3.SQLITE_DONE:
|
||||
// No rows. Reset immediately.
|
||||
// We still return a rows object (empty), but we can reset the stmt now
|
||||
// because the empty rows object won't call step() again.
|
||||
// However, standard newRows behavior expects a valid stmt to get columns.
|
||||
// Let's rely on newRows to read columns, then it returns.
|
||||
|
||||
// Actually, if we pass reuseStmt=true to an empty set,
|
||||
// rows.Close() will eventually reset it.
|
||||
if r, err = newRows(s.c, s.pstmt, allocs, true); err != nil {
|
||||
s.c.reset(s.pstmt)
|
||||
s.c.clearBindings(s.pstmt)
|
||||
return nil, err
|
||||
}
|
||||
r.(*rows).reuseStmt = true
|
||||
return r, nil
|
||||
|
||||
default:
|
||||
// Error case
|
||||
for _, v := range allocs {
|
||||
s.c.free(v)
|
||||
}
|
||||
s.c.reset(s.pstmt)
|
||||
s.c.clearBindings(s.pstmt)
|
||||
return nil, s.c.errstr(int32(rc))
|
||||
}
|
||||
}
|
||||
|
||||
// FALLBACK PATH: Multi-statement script
|
||||
for psql := s.psql; *(*byte)(unsafe.Pointer(psql)) != 0 && atomic.LoadInt32(&done) == 0; {
|
||||
if pstmt, err = s.c.prepareV2(&psql); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if pstmt == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
err = func() (err error) {
|
||||
n, err := s.c.bindParameterCount(pstmt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n != 0 {
|
||||
if allocs, err = s.c.bind(pstmt, n, args); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
rc, err := s.c.step(pstmt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch rc & 0xff {
|
||||
case sqlite3.SQLITE_ROW:
|
||||
if r != nil {
|
||||
r.Close()
|
||||
}
|
||||
if r, err = newRows(s.c, pstmt, allocs, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pstmt = 0
|
||||
return nil
|
||||
case sqlite3.SQLITE_DONE:
|
||||
if r == nil {
|
||||
if r, err = newRows(s.c, pstmt, allocs, true); err != nil {
|
||||
return err
|
||||
}
|
||||
pstmt = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
// nop
|
||||
default:
|
||||
return s.c.errstr(int32(rc))
|
||||
}
|
||||
|
||||
if *(*byte)(unsafe.Pointer(psql)) == 0 {
|
||||
if r != nil {
|
||||
r.Close()
|
||||
}
|
||||
if r, err = newRows(s.c, pstmt, allocs, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pstmt = 0
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
|
||||
e := s.c.finalize(pstmt)
|
||||
pstmt = 0 // done with
|
||||
|
||||
if err == nil && e != nil {
|
||||
// prioritize original
|
||||
// returned error.
|
||||
err = e
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return r, err
|
||||
}
|
||||
|
||||
// ExecContext implements driver.StmtExecContext
|
||||
func (s *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (dr driver.Result, err error) {
|
||||
if dmesgs {
|
||||
defer func() {
|
||||
dmesg("stmt %p, ctx %p, args %v: (driver.Result %p, err %v)", s, ctx, args, dr, err)
|
||||
}()
|
||||
}
|
||||
return s.exec(ctx, args)
|
||||
}
|
||||
|
||||
// QueryContext implements driver.StmtQueryContext
|
||||
func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (dr driver.Rows, err error) {
|
||||
if dmesgs {
|
||||
defer func() {
|
||||
dmesg("stmt %p, ctx %p, args %v: (driver.Rows %p, err %v)", s, ctx, args, dr, err)
|
||||
}()
|
||||
}
|
||||
return s.query(ctx, args)
|
||||
}
|
||||
|
||||
// C documentation
|
||||
//
|
||||
// int sqlite3_clear_bindings(sqlite3_stmt*);
|
||||
func (c *conn) clearBindings(pstmt uintptr) error {
|
||||
if rc := sqlite3.Xsqlite3_clear_bindings(c.tls, pstmt); rc != sqlite3.SQLITE_OK {
|
||||
return c.errstr(rc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
20
vendor/modernc.org/sqlite/tpch.sh
generated
vendored
Normal file
20
vendor/modernc.org/sqlite/tpch.sh
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
set -e
|
||||
echo "See http://www.tpc.org/tpc_documents_current_versions/pdf/tpc-h_v2.17.1.pdf for details"
|
||||
tmp=$(mktemp -d)
|
||||
cd $tmp
|
||||
echo "installing modernc.org/sqlite/tpch@latest into $tmp"
|
||||
GOBIN=$tmp go install modernc.org/sqlite/tpch@latest
|
||||
echo "generating pseudotext"
|
||||
./tpch -pseudotext
|
||||
for sf in 1 10 ; do
|
||||
for sut in sqlite3 sqlite ; do
|
||||
echo "$sut: generating a $sf GB test DB"
|
||||
time -p ./tpch -sut $sut -dbgen -sf $sf
|
||||
for q in 1 2 ; do
|
||||
echo -n "$sut: running query $q: "
|
||||
./tpch -sut $sut -q $q -sf $sf
|
||||
done
|
||||
done
|
||||
done
|
||||
cd -
|
||||
rm -rf $tmp
|
||||
62
vendor/modernc.org/sqlite/tx.go
generated
vendored
Normal file
62
vendor/modernc.org/sqlite/tx.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright 2025 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite // import "modernc.org/sqlite"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
|
||||
"modernc.org/libc"
|
||||
sqlite3 "modernc.org/sqlite/lib"
|
||||
)
|
||||
|
||||
type tx struct {
|
||||
c *conn
|
||||
}
|
||||
|
||||
func newTx(ctx context.Context, c *conn, opts driver.TxOptions) (*tx, error) {
|
||||
r := &tx{c: c}
|
||||
|
||||
sql := "begin"
|
||||
if !opts.ReadOnly && c.beginMode != "" {
|
||||
sql = "begin " + c.beginMode
|
||||
}
|
||||
|
||||
if err := r.exec(ctx, sql); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Commit implements driver.Tx.
|
||||
func (t *tx) Commit() (err error) {
|
||||
return t.exec(context.Background(), "commit")
|
||||
}
|
||||
|
||||
// Rollback implements driver.Tx.
|
||||
func (t *tx) Rollback() (err error) {
|
||||
return t.exec(context.Background(), "rollback")
|
||||
}
|
||||
|
||||
func (t *tx) exec(ctx context.Context, sql string) (err error) {
|
||||
psql, err := libc.CString(sql)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer t.c.free(psql)
|
||||
//TODO use t.conn.ExecContext() instead
|
||||
|
||||
if ctx != nil && ctx.Done() != nil {
|
||||
defer interruptOnDone(ctx, t.c, nil)()
|
||||
}
|
||||
|
||||
if rc := sqlite3.Xsqlite3_exec(t.c.tls, t.c.db, psql, 0, 0, 0); rc != sqlite3.SQLITE_OK {
|
||||
return t.c.errstr(rc)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
5
vendor/modernc.org/sqlite/unconvert.sh
generated
vendored
Normal file
5
vendor/modernc.org/sqlite/unconvert.sh
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
set -evx
|
||||
until unconvert -fastmath -all ./...
|
||||
do
|
||||
unconvert2 -fastmath -apply -all ./...
|
||||
done
|
||||
872
vendor/modernc.org/sqlite/vtab.go
generated
vendored
Normal file
872
vendor/modernc.org/sqlite/vtab.go
generated
vendored
Normal file
@@ -0,0 +1,872 @@
|
||||
// Copyright 2025 The Sqlite Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite // import "modernc.org/sqlite"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"modernc.org/libc"
|
||||
sqlite3 "modernc.org/sqlite/lib"
|
||||
"modernc.org/sqlite/vtab"
|
||||
)
|
||||
|
||||
func init() {
|
||||
vtab.SetRegisterFunc(registerModule)
|
||||
}
|
||||
|
||||
var (
|
||||
// vtabModules tracks Go virtual table modules registered via the vtab
|
||||
// package. Each module is identified by an integer ID used as pAux when
|
||||
// calling sqlite3_create_module_v2, so that trampolines can recover the
|
||||
// Go Module implementation.
|
||||
vtabModules = struct {
|
||||
mu sync.RWMutex
|
||||
m map[uintptr]*goModule
|
||||
ids idGen
|
||||
// name2id keeps stable IDs per module name to avoid unbounded growth
|
||||
// across connections.
|
||||
name2id map[string]uintptr
|
||||
}{
|
||||
m: make(map[uintptr]*goModule),
|
||||
name2id: make(map[string]uintptr),
|
||||
}
|
||||
|
||||
// nativeModules holds sqlite3_module instances for registered modules. We
|
||||
// keep them in Go memory so their addresses remain stable for the C layer.
|
||||
nativeModules = struct {
|
||||
mu sync.RWMutex
|
||||
m map[string]*sqlite3.Sqlite3_module
|
||||
}{
|
||||
m: make(map[string]*sqlite3.Sqlite3_module),
|
||||
}
|
||||
|
||||
// vtabTables maps sqlite3_vtab* (pVtab) to the corresponding Go Table.
|
||||
vtabTables = struct {
|
||||
mu sync.RWMutex
|
||||
m map[uintptr]*goTable
|
||||
}{
|
||||
m: make(map[uintptr]*goTable),
|
||||
}
|
||||
|
||||
// vtabCursors maps sqlite3_vtab_cursor* (pCursor) to the corresponding Go
|
||||
// Cursor.
|
||||
vtabCursors = struct {
|
||||
mu sync.RWMutex
|
||||
m map[uintptr]*goCursor
|
||||
}{
|
||||
m: make(map[uintptr]*goCursor),
|
||||
}
|
||||
)
|
||||
|
||||
// goModule wraps a vtab.Module implementation with its name.
|
||||
type goModule struct {
|
||||
name string
|
||||
impl vtab.Module
|
||||
}
|
||||
|
||||
// goTable wraps a vtab.Table implementation and remembers its module.
|
||||
type goTable struct {
|
||||
mod *goModule
|
||||
impl vtab.Table
|
||||
}
|
||||
|
||||
// goCursor wraps a vtab.Cursor implementation and remembers its table.
|
||||
type goCursor struct {
|
||||
table *goTable
|
||||
impl vtab.Cursor
|
||||
}
|
||||
|
||||
// Use aliases of the underlying lib types so field layouts remain correct.
|
||||
type cIndexConstraint = sqlite3.Tsqlite3_index_constraint
|
||||
type cIndexOrderBy = sqlite3.Tsqlite3_index_orderby
|
||||
type cConstraintUsage = sqlite3.Tsqlite3_index_constraint_usage
|
||||
|
||||
// registerModule is installed as the hook for vtab.RegisterModule.
|
||||
func registerModule(name string, m vtab.Module) error {
|
||||
if _, exists := d.modules[name]; exists {
|
||||
return fmt.Errorf("sqlite: module %q already registered", name)
|
||||
}
|
||||
d.modules[name] = m
|
||||
return nil
|
||||
}
|
||||
|
||||
// registerModules installs all globally registered vtab modules on this
|
||||
// connection by calling sqlite3_create_module_v2 for each one.
|
||||
func (c *conn) registerModules() error {
|
||||
for name, mod := range d.modules {
|
||||
if err := c.registerSingleModule(name, mod); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *conn) registerSingleModule(name string, m vtab.Module) error {
|
||||
// Allocate or reuse a stable ID for this module name and remember the Go implementation.
|
||||
vtabModules.mu.Lock()
|
||||
modID, ok := vtabModules.name2id[name]
|
||||
if !ok {
|
||||
modID = vtabModules.ids.next()
|
||||
vtabModules.name2id[name] = modID
|
||||
}
|
||||
vtabModules.m[modID] = &goModule{name: name, impl: m}
|
||||
vtabModules.mu.Unlock()
|
||||
|
||||
nativeModules.mu.Lock()
|
||||
defer nativeModules.mu.Unlock()
|
||||
if _, exists := nativeModules.m[name]; exists {
|
||||
// Module struct already created; nothing more to do for this connection.
|
||||
return nil
|
||||
}
|
||||
|
||||
// Build a sqlite3_module descriptor with trampolines.
|
||||
mod := &sqlite3.Sqlite3_module{}
|
||||
mod.FiVersion = 1
|
||||
mod.FxCreate = cFuncPointer(vtabCreateTrampoline)
|
||||
mod.FxConnect = cFuncPointer(vtabConnectTrampoline)
|
||||
mod.FxBestIndex = cFuncPointer(vtabBestIndexTrampoline)
|
||||
mod.FxDisconnect = cFuncPointer(vtabDisconnectTrampoline)
|
||||
mod.FxDestroy = cFuncPointer(vtabDestroyTrampoline)
|
||||
mod.FxOpen = cFuncPointer(vtabOpenTrampoline)
|
||||
mod.FxClose = cFuncPointer(vtabCloseTrampoline)
|
||||
mod.FxFilter = cFuncPointer(vtabFilterTrampoline)
|
||||
mod.FxNext = cFuncPointer(vtabNextTrampoline)
|
||||
mod.FxEof = cFuncPointer(vtabEofTrampoline)
|
||||
mod.FxColumn = cFuncPointer(vtabColumnTrampoline)
|
||||
mod.FxRowid = cFuncPointer(vtabRowidTrampoline)
|
||||
mod.FxFindFunction = cFuncPointer(vtabFindFunctionTrampoline)
|
||||
mod.FxRename = cFuncPointer(vtabRenameTrampoline)
|
||||
mod.FxUpdate = cFuncPointer(vtabUpdateTrampoline)
|
||||
mod.FxBegin = cFuncPointer(vtabBeginTrampoline)
|
||||
mod.FxSync = cFuncPointer(vtabSyncTrampoline)
|
||||
mod.FxCommit = cFuncPointer(vtabCommitTrampoline)
|
||||
mod.FxRollback = cFuncPointer(vtabRollbackTrampoline)
|
||||
mod.FxSavepoint = cFuncPointer(vtabSavepointTrampoline)
|
||||
mod.FxRelease = cFuncPointer(vtabReleaseTrampoline)
|
||||
mod.FxRollbackTo = cFuncPointer(vtabRollbackToTrampoline)
|
||||
|
||||
nativeModules.m[name] = mod
|
||||
|
||||
// Prepare C string for module name.
|
||||
zName, err := libc.CString(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer libc.Xfree(c.tls, zName)
|
||||
|
||||
// Register the module with this connection.
|
||||
if rc := sqlite3.Xsqlite3_create_module_v2(c.tls, c.db, zName, uintptr(unsafe.Pointer(mod)), modID, 0); rc != sqlite3.SQLITE_OK {
|
||||
return fmt.Errorf("create_module %q: %w", name, c.errstr(rc))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// vtabCreateTrampoline is the xCreate callback. It invokes the corresponding
|
||||
// Go vtab.Module.Create method, declares a default schema based on argv, and
|
||||
// allocates a sqlite3_vtab.
|
||||
func vtabCreateTrampoline(tls *libc.TLS, db uintptr, pAux uintptr, argc int32, argv uintptr, ppVtab uintptr, pzErr uintptr) int32 {
|
||||
gm := lookupGoModule(pAux)
|
||||
if gm == nil {
|
||||
setVtabError(tls, pzErr, fmt.Sprintf("vtab: unknown module id %d", pAux))
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
args := extractVtabArgs(tls, argc, argv)
|
||||
ctx := vtab.NewContext(func(schema string) error {
|
||||
zSchema, err := libc.CString(schema)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer libc.Xfree(tls, zSchema)
|
||||
if rc := sqlite3.Xsqlite3_declare_vtab(tls, db, zSchema); rc != sqlite3.SQLITE_OK {
|
||||
return fmt.Errorf("declare_vtab failed: rc=%d", rc)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
tbl, err := gm.impl.Create(ctx, args)
|
||||
if err != nil {
|
||||
setVtabError(tls, pzErr, err.Error())
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
sz := unsafe.Sizeof(sqlite3.Sqlite3_vtab{})
|
||||
p := sqlite3.Xsqlite3_malloc(tls, int32(sz))
|
||||
if p == 0 {
|
||||
setVtabError(tls, pzErr, "vtab: out of memory")
|
||||
return sqlite3.SQLITE_NOMEM
|
||||
}
|
||||
mem := (*libc.RawMem)(unsafe.Pointer(p))[:sz:sz]
|
||||
for i := range mem {
|
||||
mem[i] = 0
|
||||
}
|
||||
*(*uintptr)(unsafe.Pointer(ppVtab)) = p
|
||||
|
||||
gt := &goTable{mod: gm, impl: tbl}
|
||||
vtabTables.mu.Lock()
|
||||
vtabTables.m[p] = gt
|
||||
vtabTables.mu.Unlock()
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
// vtabConnectTrampoline is the xConnect callback. It mirrors
|
||||
// vtabCreateTrampoline but calls Module.Connect.
|
||||
func vtabConnectTrampoline(tls *libc.TLS, db uintptr, pAux uintptr, argc int32, argv uintptr, ppVtab uintptr, pzErr uintptr) int32 {
|
||||
gm := lookupGoModule(pAux)
|
||||
if gm == nil {
|
||||
setVtabError(tls, pzErr, fmt.Sprintf("vtab: unknown module id %d", pAux))
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
args := extractVtabArgs(tls, argc, argv)
|
||||
ctx := vtab.NewContext(func(schema string) error {
|
||||
zSchema, err := libc.CString(schema)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer libc.Xfree(tls, zSchema)
|
||||
if rc := sqlite3.Xsqlite3_declare_vtab(tls, db, zSchema); rc != sqlite3.SQLITE_OK {
|
||||
return fmt.Errorf("declare_vtab failed: rc=%d", rc)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
tbl, err := gm.impl.Connect(ctx, args)
|
||||
if err != nil {
|
||||
setVtabError(tls, pzErr, err.Error())
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
sz := unsafe.Sizeof(sqlite3.Sqlite3_vtab{})
|
||||
p := sqlite3.Xsqlite3_malloc(tls, int32(sz))
|
||||
if p == 0 {
|
||||
setVtabError(tls, pzErr, "vtab: out of memory")
|
||||
return sqlite3.SQLITE_NOMEM
|
||||
}
|
||||
mem := (*libc.RawMem)(unsafe.Pointer(p))[:sz:sz]
|
||||
for i := range mem {
|
||||
mem[i] = 0
|
||||
}
|
||||
*(*uintptr)(unsafe.Pointer(ppVtab)) = p
|
||||
|
||||
gt := &goTable{mod: gm, impl: tbl}
|
||||
vtabTables.mu.Lock()
|
||||
vtabTables.m[p] = gt
|
||||
vtabTables.mu.Unlock()
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
// vtabBestIndexTrampoline maps sqlite3_index_info to vtab.IndexInfo and
|
||||
// delegates to Table.BestIndex. It also mirrors constraint and ORDER BY
|
||||
// information into the Go structure.
|
||||
func vtabBestIndexTrampoline(tls *libc.TLS, pVtab uintptr, pInfo uintptr) int32 {
|
||||
vtabTables.mu.RLock()
|
||||
gt := vtabTables.m[pVtab]
|
||||
vtabTables.mu.RUnlock()
|
||||
if gt == nil {
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
|
||||
idx := (*sqlite3.Sqlite3_index_info)(unsafe.Pointer(pInfo))
|
||||
info := &vtab.IndexInfo{}
|
||||
|
||||
// Populate Constraints from sqlite3_index_info.aConstraint.
|
||||
if idx.FnConstraint > 0 && idx.FaConstraint != 0 {
|
||||
n := int(idx.FnConstraint)
|
||||
cs := make([]vtab.Constraint, 0, n)
|
||||
base := idx.FaConstraint
|
||||
sz := unsafe.Sizeof(cIndexConstraint{})
|
||||
for i := 0; i < n; i++ {
|
||||
c := (*cIndexConstraint)(unsafe.Pointer(base + uintptr(i)*sz))
|
||||
op := vtab.OpUnknown
|
||||
switch int32(c.Fop) {
|
||||
case sqlite3.SQLITE_INDEX_CONSTRAINT_EQ:
|
||||
op = vtab.OpEQ
|
||||
case sqlite3.SQLITE_INDEX_CONSTRAINT_GT:
|
||||
op = vtab.OpGT
|
||||
case sqlite3.SQLITE_INDEX_CONSTRAINT_LE:
|
||||
op = vtab.OpLE
|
||||
case sqlite3.SQLITE_INDEX_CONSTRAINT_LT:
|
||||
op = vtab.OpLT
|
||||
case sqlite3.SQLITE_INDEX_CONSTRAINT_GE:
|
||||
op = vtab.OpGE
|
||||
case sqlite3.SQLITE_INDEX_CONSTRAINT_MATCH:
|
||||
op = vtab.OpMATCH
|
||||
case sqlite3.SQLITE_INDEX_CONSTRAINT_NE:
|
||||
op = vtab.OpNE
|
||||
case sqlite3.SQLITE_INDEX_CONSTRAINT_IS:
|
||||
op = vtab.OpIS
|
||||
case sqlite3.SQLITE_INDEX_CONSTRAINT_ISNOT:
|
||||
op = vtab.OpISNOT
|
||||
case sqlite3.SQLITE_INDEX_CONSTRAINT_ISNULL:
|
||||
op = vtab.OpISNULL
|
||||
case sqlite3.SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
|
||||
op = vtab.OpISNOTNULL
|
||||
case sqlite3.SQLITE_INDEX_CONSTRAINT_LIKE:
|
||||
op = vtab.OpLIKE
|
||||
case sqlite3.SQLITE_INDEX_CONSTRAINT_GLOB:
|
||||
op = vtab.OpGLOB
|
||||
case sqlite3.SQLITE_INDEX_CONSTRAINT_REGEXP:
|
||||
op = vtab.OpREGEXP
|
||||
case sqlite3.SQLITE_INDEX_CONSTRAINT_FUNCTION:
|
||||
op = vtab.OpFUNCTION
|
||||
case sqlite3.SQLITE_INDEX_CONSTRAINT_LIMIT:
|
||||
op = vtab.OpLIMIT
|
||||
case sqlite3.SQLITE_INDEX_CONSTRAINT_OFFSET:
|
||||
op = vtab.OpOFFSET
|
||||
}
|
||||
cs = append(cs, vtab.Constraint{
|
||||
Column: int(c.FiColumn),
|
||||
Op: op,
|
||||
Usable: c.Fusable != 0,
|
||||
ArgIndex: -1, // 0-based; -1 means ignore
|
||||
Omit: false,
|
||||
})
|
||||
}
|
||||
info.Constraints = cs
|
||||
}
|
||||
|
||||
// Populate OrderBy from sqlite3_index_info.aOrderBy.
|
||||
if idx.FnOrderBy > 0 && idx.FaOrderBy != 0 {
|
||||
n := int(idx.FnOrderBy)
|
||||
obs := make([]vtab.OrderBy, 0, n)
|
||||
base := idx.FaOrderBy
|
||||
sz := unsafe.Sizeof(cIndexOrderBy{})
|
||||
for i := 0; i < n; i++ {
|
||||
ob := (*cIndexOrderBy)(unsafe.Pointer(base + uintptr(i)*sz))
|
||||
obs = append(obs, vtab.OrderBy{
|
||||
Column: int(ob.FiColumn),
|
||||
Desc: ob.Fdesc != 0,
|
||||
})
|
||||
}
|
||||
info.OrderBy = obs
|
||||
}
|
||||
|
||||
// Populate ColUsed and idxFlags for module visibility.
|
||||
if idx.FcolUsed != 0 {
|
||||
info.ColUsed = uint64(idx.FcolUsed)
|
||||
}
|
||||
if idx.FidxFlags != 0 {
|
||||
info.IdxFlags = int(idx.FidxFlags)
|
||||
}
|
||||
|
||||
if err := gt.impl.BestIndex(info); err != nil {
|
||||
// Report error via zErrMsg on pVtab.
|
||||
setVtabZErrMsg(tls, pVtab, err.Error())
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
|
||||
// Propagate any ArgIndex assignments back into aConstraintUsage so that
|
||||
// SQLite will populate xFilter's argv[] accordingly.
|
||||
if idx.FnConstraint > 0 && idx.FaConstraintUsage != 0 && len(info.Constraints) > 0 {
|
||||
n := int(idx.FnConstraint)
|
||||
base := idx.FaConstraintUsage
|
||||
sz := unsafe.Sizeof(cConstraintUsage{})
|
||||
for i := 0; i < n && i < len(info.Constraints); i++ {
|
||||
cu := (*cConstraintUsage)(unsafe.Pointer(base + uintptr(i)*sz))
|
||||
argIndex := info.Constraints[i].ArgIndex
|
||||
if argIndex >= 0 {
|
||||
// Go ArgIndex is 0-based; SQLite wants 1-based.
|
||||
cu.FargvIndex = int32(argIndex + 1)
|
||||
}
|
||||
if info.Constraints[i].Omit {
|
||||
cu.Fomit = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
// Guard against int32 overflow: SQLite expects idxNum as int32.
|
||||
if info.IdxNum < math.MinInt32 || info.IdxNum > math.MaxInt32 {
|
||||
setVtabZErrMsg(tls, pVtab, fmt.Sprintf("vtab: IdxNum %d out of int32 range", info.IdxNum))
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
idx.FidxNum = int32(info.IdxNum)
|
||||
if info.IdxStr != "" {
|
||||
// Allocate using SQLite allocator because needToFreeIdxStr=1 instructs
|
||||
// SQLite to free the string with sqlite3_free.
|
||||
z := sqlite3AllocCString(tls, info.IdxStr)
|
||||
if z != 0 {
|
||||
idx.FidxStr = z
|
||||
idx.FneedToFreeIdxStr = 1
|
||||
}
|
||||
}
|
||||
if info.OrderByConsumed {
|
||||
idx.ForderByConsumed = 1
|
||||
}
|
||||
if info.IdxFlags != 0 {
|
||||
idx.FidxFlags = int32(info.IdxFlags)
|
||||
}
|
||||
if info.EstimatedCost != 0 {
|
||||
idx.FestimatedCost = info.EstimatedCost
|
||||
}
|
||||
if info.EstimatedRows != 0 {
|
||||
idx.FestimatedRows = sqlite3.Sqlite3_int64(info.EstimatedRows)
|
||||
}
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
// vtabDisconnectTrampoline is xDisconnect. It frees the sqlite3_vtab and
|
||||
// calls Table.Disconnect.
|
||||
func vtabDisconnectTrampoline(tls *libc.TLS, pVtab uintptr) int32 {
|
||||
vtabTables.mu.RLock()
|
||||
gt := vtabTables.m[pVtab]
|
||||
vtabTables.mu.RUnlock()
|
||||
if gt != nil {
|
||||
_ = gt.impl.Disconnect()
|
||||
vtabTables.mu.Lock()
|
||||
delete(vtabTables.m, pVtab)
|
||||
vtabTables.mu.Unlock()
|
||||
}
|
||||
sqlite3.Xsqlite3_free(tls, pVtab)
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
// vtabDestroyTrampoline is xDestroy. Currently identical to Disconnect.
|
||||
func vtabDestroyTrampoline(tls *libc.TLS, pVtab uintptr) int32 {
|
||||
vtabTables.mu.RLock()
|
||||
gt := vtabTables.m[pVtab]
|
||||
vtabTables.mu.RUnlock()
|
||||
if gt != nil {
|
||||
_ = gt.impl.Destroy()
|
||||
vtabTables.mu.Lock()
|
||||
delete(vtabTables.m, pVtab)
|
||||
vtabTables.mu.Unlock()
|
||||
}
|
||||
sqlite3.Xsqlite3_free(tls, pVtab)
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
// vtabOpenTrampoline is xOpen. It allocates an empty sqlite3_vtab_cursor and
|
||||
// creates a Go Cursor via Table.Open.
|
||||
func vtabOpenTrampoline(tls *libc.TLS, pVtab uintptr, ppCursor uintptr) int32 {
|
||||
vtabTables.mu.RLock()
|
||||
gt := vtabTables.m[pVtab]
|
||||
vtabTables.mu.RUnlock()
|
||||
if gt == nil {
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
|
||||
curImpl, err := gt.impl.Open()
|
||||
if err != nil {
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
|
||||
sz := unsafe.Sizeof(sqlite3.Sqlite3_vtab_cursor{})
|
||||
p := sqlite3.Xsqlite3_malloc(tls, int32(sz))
|
||||
if p == 0 {
|
||||
return sqlite3.SQLITE_NOMEM
|
||||
}
|
||||
mem := (*libc.RawMem)(unsafe.Pointer(p))[:sz:sz]
|
||||
for i := range mem {
|
||||
mem[i] = 0
|
||||
}
|
||||
*(*uintptr)(unsafe.Pointer(ppCursor)) = p
|
||||
|
||||
// Link cursor back to its vtab so error reporting can set zErrMsg.
|
||||
cur := (*sqlite3.Sqlite3_vtab_cursor)(unsafe.Pointer(p))
|
||||
cur.FpVtab = pVtab
|
||||
|
||||
gc := &goCursor{table: gt, impl: curImpl}
|
||||
vtabCursors.mu.Lock()
|
||||
vtabCursors.m[p] = gc
|
||||
vtabCursors.mu.Unlock()
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
// vtabCloseTrampoline is xClose. It frees the sqlite3_vtab_cursor and calls
|
||||
// Cursor.Close.
|
||||
func vtabCloseTrampoline(tls *libc.TLS, pCursor uintptr) int32 {
|
||||
vtabCursors.mu.RLock()
|
||||
gc := vtabCursors.m[pCursor]
|
||||
vtabCursors.mu.RUnlock()
|
||||
if gc != nil {
|
||||
_ = gc.impl.Close()
|
||||
vtabCursors.mu.Lock()
|
||||
delete(vtabCursors.m, pCursor)
|
||||
vtabCursors.mu.Unlock()
|
||||
}
|
||||
sqlite3.Xsqlite3_free(tls, pCursor)
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
// vtabFilterTrampoline is xFilter.
|
||||
func vtabFilterTrampoline(tls *libc.TLS, pCursor uintptr, idxNum int32, idxStr uintptr, argc int32, argv uintptr) int32 {
|
||||
vtabCursors.mu.RLock()
|
||||
gc := vtabCursors.m[pCursor]
|
||||
vtabCursors.mu.RUnlock()
|
||||
if gc == nil {
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
|
||||
var idxStrGo string
|
||||
if idxStr != 0 {
|
||||
idxStrGo = libc.GoString(idxStr)
|
||||
}
|
||||
vals := functionArgs(tls, argc, argv)
|
||||
if err := gc.impl.Filter(int(idxNum), idxStrGo, vals); err != nil {
|
||||
// Set zErrMsg on the associated vtab for better diagnostics.
|
||||
if pCursor != 0 {
|
||||
cur := (*sqlite3.Sqlite3_vtab_cursor)(unsafe.Pointer(pCursor))
|
||||
if cur.FpVtab != 0 {
|
||||
setVtabZErrMsg(tls, cur.FpVtab, err.Error())
|
||||
}
|
||||
}
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
// vtabNextTrampoline is xNext.
|
||||
func vtabNextTrampoline(tls *libc.TLS, pCursor uintptr) int32 {
|
||||
_ = tls
|
||||
vtabCursors.mu.RLock()
|
||||
gc := vtabCursors.m[pCursor]
|
||||
vtabCursors.mu.RUnlock()
|
||||
if gc == nil {
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
if err := gc.impl.Next(); err != nil {
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
// vtabEofTrampoline is xEof.
|
||||
func vtabEofTrampoline(tls *libc.TLS, pCursor uintptr) int32 {
|
||||
_ = tls
|
||||
vtabCursors.mu.RLock()
|
||||
gc := vtabCursors.m[pCursor]
|
||||
vtabCursors.mu.RUnlock()
|
||||
if gc == nil || gc.impl.Eof() {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// vtabColumnTrampoline is xColumn.
|
||||
func vtabColumnTrampoline(tls *libc.TLS, pCursor uintptr, ctx uintptr, iCol int32) int32 {
|
||||
vtabCursors.mu.RLock()
|
||||
gc := vtabCursors.m[pCursor]
|
||||
vtabCursors.mu.RUnlock()
|
||||
if gc == nil {
|
||||
sqlite3.Xsqlite3_result_null(tls, ctx)
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
val, err := gc.impl.Column(int(iCol))
|
||||
if err != nil {
|
||||
// Report via result error on the context.
|
||||
z, cerr := libc.CString(err.Error())
|
||||
if cerr == nil {
|
||||
defer libc.Xfree(tls, z)
|
||||
sqlite3.Xsqlite3_result_error(tls, ctx, z, -1)
|
||||
sqlite3.Xsqlite3_result_error_code(tls, ctx, sqlite3.SQLITE_ERROR)
|
||||
} else {
|
||||
sqlite3.Xsqlite3_result_error_code(tls, ctx, sqlite3.SQLITE_ERROR)
|
||||
}
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
if err := functionReturnValue(tls, ctx, val); err != nil {
|
||||
// Include a descriptive error message for easier debugging
|
||||
// (e.g., unsupported type conversions).
|
||||
if err != nil {
|
||||
z, cerr := libc.CString(err.Error())
|
||||
if cerr == nil {
|
||||
defer libc.Xfree(tls, z)
|
||||
sqlite3.Xsqlite3_result_error(tls, ctx, z, -1)
|
||||
}
|
||||
}
|
||||
sqlite3.Xsqlite3_result_error_code(tls, ctx, sqlite3.SQLITE_ERROR)
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
// vtabRowidTrampoline is xRowid.
|
||||
func vtabRowidTrampoline(tls *libc.TLS, pCursor uintptr, pRowid uintptr) int32 {
|
||||
_ = tls
|
||||
vtabCursors.mu.RLock()
|
||||
gc := vtabCursors.m[pCursor]
|
||||
vtabCursors.mu.RUnlock()
|
||||
if gc == nil {
|
||||
*(*int64)(unsafe.Pointer(pRowid)) = 0
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
rowid, err := gc.impl.Rowid()
|
||||
if err != nil {
|
||||
*(*int64)(unsafe.Pointer(pRowid)) = 0
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
*(*int64)(unsafe.Pointer(pRowid)) = rowid
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
func lookupGoModule(id uintptr) *goModule {
|
||||
vtabModules.mu.RLock()
|
||||
defer vtabModules.mu.RUnlock()
|
||||
return vtabModules.m[id]
|
||||
}
|
||||
|
||||
func extractVtabArgs(tls *libc.TLS, argc int32, argv uintptr) []string {
|
||||
args := make([]string, argc)
|
||||
for i := int32(0); i < argc; i++ {
|
||||
cstr := *(*uintptr)(unsafe.Pointer(argv + uintptr(i)*unsafe.Sizeof(uintptr(0))))
|
||||
args[i] = libc.GoString(cstr)
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func setVtabError(tls *libc.TLS, pzErr uintptr, msg string) {
|
||||
if pzErr == 0 {
|
||||
return
|
||||
}
|
||||
z := sqlite3AllocCString(tls, msg)
|
||||
if z == 0 {
|
||||
return
|
||||
}
|
||||
*(*uintptr)(unsafe.Pointer(pzErr)) = z
|
||||
}
|
||||
|
||||
// setVtabZErrMsg sets pVtab->zErrMsg to a newly allocated C string containing
|
||||
// msg. SQLite will free this pointer.
|
||||
func setVtabZErrMsg(tls *libc.TLS, pVtab uintptr, msg string) {
|
||||
if pVtab == 0 {
|
||||
return
|
||||
}
|
||||
vt := (*sqlite3.Sqlite3_vtab)(unsafe.Pointer(pVtab))
|
||||
if vt.FzErrMsg != 0 {
|
||||
sqlite3.Xsqlite3_free(tls, vt.FzErrMsg)
|
||||
vt.FzErrMsg = 0
|
||||
}
|
||||
z := sqlite3AllocCString(tls, msg)
|
||||
if z == 0 {
|
||||
return
|
||||
}
|
||||
vt.FzErrMsg = z
|
||||
}
|
||||
|
||||
// Optional vtab callbacks
|
||||
|
||||
// vtabFindFunctionTrampoline is xFindFunction. We currently do not expose a
|
||||
// Go surface for per-table SQL functions; report not found (return 0).
|
||||
func vtabFindFunctionTrampoline(tls *libc.TLS, pVtab uintptr, nArg int32, zName uintptr, pxFunc uintptr, ppArg uintptr) int32 {
|
||||
_ = tls
|
||||
_ = pVtab
|
||||
_ = nArg
|
||||
_ = zName
|
||||
if pxFunc != 0 {
|
||||
*(*uintptr)(unsafe.Pointer(pxFunc)) = 0
|
||||
}
|
||||
if ppArg != 0 {
|
||||
*(*uintptr)(unsafe.Pointer(ppArg)) = 0
|
||||
}
|
||||
return 0 // not found
|
||||
}
|
||||
|
||||
// vtabRenameTrampoline is xRename. Calls Table.Rename if implemented.
|
||||
func vtabRenameTrampoline(tls *libc.TLS, pVtab uintptr, zNew uintptr) int32 {
|
||||
vtabTables.mu.RLock()
|
||||
gt := vtabTables.m[pVtab]
|
||||
vtabTables.mu.RUnlock()
|
||||
if gt == nil {
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
name := libc.GoString(zNew)
|
||||
if r, ok := gt.impl.(interface{ Rename(string) error }); ok {
|
||||
if err := r.Rename(name); err != nil {
|
||||
setVtabZErrMsg(tls, pVtab, err.Error())
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
}
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
// vtabUpdateTrampoline is xUpdate. Not supported by default; report read-only.
|
||||
func vtabUpdateTrampoline(tls *libc.TLS, pVtab uintptr, argc int32, argv uintptr, pRowid uintptr) int32 {
|
||||
vtabTables.mu.RLock()
|
||||
gt := vtabTables.m[pVtab]
|
||||
vtabTables.mu.RUnlock()
|
||||
if gt == nil {
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
upd, ok := gt.impl.(interface {
|
||||
Insert(cols []vtab.Value, rowid *int64) error
|
||||
Update(oldRowid int64, cols []vtab.Value, newRowid *int64) error
|
||||
Delete(oldRowid int64) error
|
||||
})
|
||||
if !ok {
|
||||
return sqlite3.SQLITE_READONLY
|
||||
}
|
||||
|
||||
// DELETE: argc == 1; argv[0]=oldRowid
|
||||
if argc == 1 {
|
||||
valPtr := *(*uintptr)(unsafe.Pointer(argv))
|
||||
oldRowid := int64(0)
|
||||
if sqlite3.Xsqlite3_value_type(tls, valPtr) != sqlite3.SQLITE_NULL {
|
||||
oldRowid = int64(sqlite3.Xsqlite3_value_int64(tls, valPtr))
|
||||
}
|
||||
if err := upd.Delete(oldRowid); err != nil {
|
||||
setVtabZErrMsg(tls, pVtab, err.Error())
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
// INSERT or UPDATE: argc == N+2. argv[0]=oldRowid (NULL for insert),
|
||||
// argv[1..N]=column values, argv[N+1]=newRowid (or desired rowid for insert, may be NULL).
|
||||
if argc < 3 {
|
||||
return sqlite3.SQLITE_MISUSE
|
||||
}
|
||||
nCols := argc - 2
|
||||
// Extract column values
|
||||
colsPtr := argv + uintptr(1)*sqliteValPtrSize
|
||||
cols := functionArgs(tls, nCols, colsPtr)
|
||||
|
||||
// Determine old/new rowid
|
||||
oldPtr := *(*uintptr)(unsafe.Pointer(argv + uintptr(0)*sqliteValPtrSize))
|
||||
newPtr := *(*uintptr)(unsafe.Pointer(argv + uintptr(argc-1)*sqliteValPtrSize))
|
||||
|
||||
oldIsNull := sqlite3.Xsqlite3_value_type(tls, oldPtr) == sqlite3.SQLITE_NULL
|
||||
newIsNull := sqlite3.Xsqlite3_value_type(tls, newPtr) == sqlite3.SQLITE_NULL
|
||||
|
||||
if oldIsNull {
|
||||
// INSERT
|
||||
var rid int64
|
||||
if !newIsNull {
|
||||
rid = int64(sqlite3.Xsqlite3_value_int64(tls, newPtr))
|
||||
}
|
||||
if err := upd.Insert(cols, &rid); err != nil {
|
||||
setVtabZErrMsg(tls, pVtab, err.Error())
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
if pRowid != 0 {
|
||||
*(*int64)(unsafe.Pointer(pRowid)) = rid
|
||||
}
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
// UPDATE
|
||||
oldRowid := int64(sqlite3.Xsqlite3_value_int64(tls, oldPtr))
|
||||
var newRid int64
|
||||
if !newIsNull {
|
||||
newRid = int64(sqlite3.Xsqlite3_value_int64(tls, newPtr))
|
||||
}
|
||||
if err := upd.Update(oldRowid, cols, &newRid); err != nil {
|
||||
setVtabZErrMsg(tls, pVtab, err.Error())
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
if pRowid != 0 && newRid != 0 {
|
||||
*(*int64)(unsafe.Pointer(pRowid)) = newRid
|
||||
}
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
// Transactional callbacks
|
||||
func vtabBeginTrampoline(tls *libc.TLS, pVtab uintptr) int32 {
|
||||
vtabTables.mu.RLock()
|
||||
gt := vtabTables.m[pVtab]
|
||||
vtabTables.mu.RUnlock()
|
||||
if gt == nil {
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
if tr, ok := gt.impl.(interface{ Begin() error }); ok {
|
||||
if err := tr.Begin(); err != nil {
|
||||
setVtabZErrMsg(tls, pVtab, err.Error())
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
}
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
func vtabSyncTrampoline(tls *libc.TLS, pVtab uintptr) int32 {
|
||||
vtabTables.mu.RLock()
|
||||
gt := vtabTables.m[pVtab]
|
||||
vtabTables.mu.RUnlock()
|
||||
if gt == nil {
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
if tr, ok := gt.impl.(interface{ Sync() error }); ok {
|
||||
if err := tr.Sync(); err != nil {
|
||||
setVtabZErrMsg(tls, pVtab, err.Error())
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
}
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
func vtabCommitTrampoline(tls *libc.TLS, pVtab uintptr) int32 {
|
||||
vtabTables.mu.RLock()
|
||||
gt := vtabTables.m[pVtab]
|
||||
vtabTables.mu.RUnlock()
|
||||
if gt == nil {
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
if tr, ok := gt.impl.(interface{ Commit() error }); ok {
|
||||
if err := tr.Commit(); err != nil {
|
||||
setVtabZErrMsg(tls, pVtab, err.Error())
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
}
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
func vtabRollbackTrampoline(tls *libc.TLS, pVtab uintptr) int32 {
|
||||
vtabTables.mu.RLock()
|
||||
gt := vtabTables.m[pVtab]
|
||||
vtabTables.mu.RUnlock()
|
||||
if gt == nil {
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
if tr, ok := gt.impl.(interface{ Rollback() error }); ok {
|
||||
if err := tr.Rollback(); err != nil {
|
||||
setVtabZErrMsg(tls, pVtab, err.Error())
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
}
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
func vtabSavepointTrampoline(tls *libc.TLS, pVtab uintptr, i int32) int32 {
|
||||
vtabTables.mu.RLock()
|
||||
gt := vtabTables.m[pVtab]
|
||||
vtabTables.mu.RUnlock()
|
||||
if gt == nil {
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
if tr, ok := gt.impl.(interface{ Savepoint(int) error }); ok {
|
||||
if err := tr.Savepoint(int(i)); err != nil {
|
||||
setVtabZErrMsg(tls, pVtab, err.Error())
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
}
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
func vtabReleaseTrampoline(tls *libc.TLS, pVtab uintptr, i int32) int32 {
|
||||
vtabTables.mu.RLock()
|
||||
gt := vtabTables.m[pVtab]
|
||||
vtabTables.mu.RUnlock()
|
||||
if gt == nil {
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
if tr, ok := gt.impl.(interface{ Release(int) error }); ok {
|
||||
if err := tr.Release(int(i)); err != nil {
|
||||
setVtabZErrMsg(tls, pVtab, err.Error())
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
}
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
|
||||
func vtabRollbackToTrampoline(tls *libc.TLS, pVtab uintptr, i int32) int32 {
|
||||
vtabTables.mu.RLock()
|
||||
gt := vtabTables.m[pVtab]
|
||||
vtabTables.mu.RUnlock()
|
||||
if gt == nil {
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
if tr, ok := gt.impl.(interface{ RollbackTo(int) error }); ok {
|
||||
if err := tr.RollbackTo(int(i)); err != nil {
|
||||
setVtabZErrMsg(tls, pVtab, err.Error())
|
||||
return sqlite3.SQLITE_ERROR
|
||||
}
|
||||
}
|
||||
return sqlite3.SQLITE_OK
|
||||
}
|
||||
53
vendor/modernc.org/sqlite/vtab/doc.go
generated
vendored
Normal file
53
vendor/modernc.org/sqlite/vtab/doc.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
// Package vtab defines a Go-facing API for implementing SQLite virtual table
|
||||
// modules on top of the modernc.org/sqlite driver.
|
||||
//
|
||||
// It is intentionally small and generic so that external projects can
|
||||
// implement virtual tables without depending on the translated C internals.
|
||||
package vtab
|
||||
|
||||
// API notes
|
||||
//
|
||||
// - Schema declaration: Modules must call Context.Declare from within Create
|
||||
// or Connect to declare the virtual table schema (a CREATE TABLE statement).
|
||||
// The driver no longer auto-declares based on USING(...) args to support
|
||||
// dynamic schemas (e.g., CSV headers).
|
||||
//
|
||||
// - Constraint operators: ConstraintOp includes OpUnknown for operators that
|
||||
// are not recognized. The driver maps common SQLite operators including EQ,
|
||||
// NE, GT, GE, LT, LE, MATCH, IS/ISNOT, ISNULL/ISNOTNULL, LIKE, GLOB, REGEXP,
|
||||
// FUNCTION, LIMIT, and OFFSET.
|
||||
//
|
||||
// - ArgIndex: Set as 0-based in Go to indicate which position in argv[] should
|
||||
// receive a constraint value. The driver adds +1 when communicating with
|
||||
// SQLite (which is 1-based). Use -1 (default) to ignore.
|
||||
//
|
||||
// - Omit: Set Constraint.Omit to ask SQLite to not re-evaluate that constraint
|
||||
// in the parent query if the virtual table fully handles it.
|
||||
//
|
||||
// - ColUsed: IndexInfo.ColUsed provides a bitmask of columns referenced by the
|
||||
// query. Bit N indicates column N is used.
|
||||
//
|
||||
// - IdxFlags: IndexInfo.IdxFlags allows modules to set planning flags.
|
||||
// Currently, IndexScanUnique (mirrors SQLITE_INDEX_SCAN_UNIQUE) indicates
|
||||
// the plan will visit at most one row. This can help the optimizer.
|
||||
//
|
||||
// Optional interfaces
|
||||
//
|
||||
// - Updater: Implement on your Table to support writes via xUpdate.
|
||||
// Insert(cols, *rowid), Update(oldRowid, cols, *newRowid), Delete(oldRowid).
|
||||
// The trampoline maps SQLite xUpdate’s calling convention to these methods.
|
||||
//
|
||||
// - Renamer: Implement Rename(newName string) on your Table to handle xRename.
|
||||
// If unimplemented, rename is treated as a no-op.
|
||||
//
|
||||
// - Transactional: Implement Begin/Sync/Commit/Rollback/Savepoint/Release/
|
||||
// RollbackTo as needed. Unimplemented methods are treated as no-ops.
|
||||
// These callbacks let writable or advanced modules coordinate with SQLite
|
||||
// transaction boundaries.
|
||||
//
|
||||
// Re-entrancy cautions
|
||||
// - Avoid executing SQL on the same connection from within vtab methods
|
||||
// (Create/Connect/BestIndex/Filter/etc.). SQLite virtual table callbacks run
|
||||
// inside the engine and issuing re-entrant SQL on the same connection can
|
||||
// lead to deadlocks or undefined behavior. If a module requires issuing SQL,
|
||||
// consider using a separate connection and document the concurrency model.
|
||||
245
vendor/modernc.org/sqlite/vtab/vtab.go
generated
vendored
Normal file
245
vendor/modernc.org/sqlite/vtab/vtab.go
generated
vendored
Normal file
@@ -0,0 +1,245 @@
|
||||
package vtab
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Value is the value type passed to and from virtual table cursors. It
|
||||
// aliases database/sql/driver.Value to avoid exposing low-level details to
|
||||
// module authors while remaining compatible with the driver.
|
||||
type Value = driver.Value
|
||||
|
||||
// Context carries information that a Module may need when creating or
|
||||
// connecting a table instance. It intentionally does not expose *sql.DB to
|
||||
// avoid leaking database/sql internals into the vtab API. Additional fields
|
||||
// may be added in the future as needed.
|
||||
type Context struct {
|
||||
declare func(string) error
|
||||
}
|
||||
|
||||
// Declare must be called by a module from within Create or Connect to declare
|
||||
// the schema of the virtual table. The provided SQL must be a CREATE TABLE
|
||||
// statement describing the exposed columns.
|
||||
//
|
||||
// The engine installs this callback so that the declaration is executed in the
|
||||
// correct context. Calling Declare outside of Create/Connect may fail.
|
||||
func (c Context) Declare(schema string) error {
|
||||
if c.declare == nil {
|
||||
return errors.New("vtab: declare not available in this context")
|
||||
}
|
||||
return c.declare(schema)
|
||||
}
|
||||
|
||||
// NewContext is used by the engine to create a Context bound to the current
|
||||
// xCreate/xConnect call. External modules should not need to call this.
|
||||
func NewContext(declare func(string) error) Context { return Context{declare: declare} }
|
||||
|
||||
// Module represents a virtual table module, analogous to sqlite3_module in
|
||||
// the SQLite C API. Implementations are responsible for creating and
|
||||
// connecting table instances.
|
||||
type Module interface {
|
||||
// Create is called to create a new virtual table. args corresponds to the
|
||||
// argv array passed to xCreate in the SQLite C API: it contains the module
|
||||
// name, the database name, the table name, and module arguments.
|
||||
Create(ctx Context, args []string) (Table, error)
|
||||
|
||||
// Connect is called to connect to an existing virtual table. Its
|
||||
// semantics mirror xConnect in the SQLite C API.
|
||||
Connect(ctx Context, args []string) (Table, error)
|
||||
}
|
||||
|
||||
// Table represents a single virtual table instance (the Go analogue of
|
||||
// sqlite3_vtab and its associated methods).
|
||||
type Table interface {
|
||||
// BestIndex allows the virtual table to inform SQLite about which
|
||||
// constraints and orderings it can efficiently support. The IndexInfo
|
||||
// structure mirrors sqlite3_index_info.
|
||||
BestIndex(info *IndexInfo) error
|
||||
|
||||
// Open creates a new cursor for scanning the table.
|
||||
Open() (Cursor, error)
|
||||
|
||||
// Disconnect is called to disconnect from a table instance (xDisconnect).
|
||||
Disconnect() error
|
||||
|
||||
// Destroy is called when a table is dropped (xDestroy).
|
||||
Destroy() error
|
||||
}
|
||||
|
||||
// Renamer can be implemented by a Table to handle xRename.
|
||||
type Renamer interface {
|
||||
Rename(newName string) error
|
||||
}
|
||||
|
||||
// Transactional can be implemented by a Table to handle transaction-related
|
||||
// callbacks. Methods are optional; unimplemented methods are treated as no-op.
|
||||
type Transactional interface {
|
||||
Begin() error
|
||||
Sync() error
|
||||
Commit() error
|
||||
Rollback() error
|
||||
Savepoint(i int) error
|
||||
Release(i int) error
|
||||
RollbackTo(i int) error
|
||||
}
|
||||
|
||||
// Cursor represents a cursor over a virtual table (sqlite3_vtab_cursor).
|
||||
type Cursor interface {
|
||||
// Filter corresponds to xFilter. idxNum and idxStr are the chosen index
|
||||
// number and string; vals are the constraint arguments.
|
||||
Filter(idxNum int, idxStr string, vals []Value) error
|
||||
|
||||
// Next advances the cursor to the next row (xNext).
|
||||
Next() error
|
||||
|
||||
// Eof reports whether the cursor is past the last row (xEof != 0).
|
||||
Eof() bool
|
||||
|
||||
// Column returns the value of the specified column in the current row
|
||||
// (xColumn).
|
||||
Column(col int) (Value, error)
|
||||
|
||||
// Rowid returns the current rowid (xRowid).
|
||||
Rowid() (int64, error)
|
||||
|
||||
// Close closes the cursor (xClose).
|
||||
Close() error
|
||||
}
|
||||
|
||||
// Updater can be implemented by a Table to support writes via xUpdate.
|
||||
//
|
||||
// Semantics follow SQLite's xUpdate:
|
||||
// - Delete: Delete(oldRowid) is called.
|
||||
// - Insert: Insert(cols, rowid) is called. *rowid may contain a desired rowid
|
||||
// (if provided by SQL) and should be set to the final rowid of the new row.
|
||||
// - Update: Update(oldRowid, cols, newRowid) is called. *newRowid may be set
|
||||
// to the final rowid of the updated row when changed.
|
||||
type Updater interface {
|
||||
Insert(cols []Value, rowid *int64) error
|
||||
Update(oldRowid int64, cols []Value, newRowid *int64) error
|
||||
Delete(oldRowid int64) error
|
||||
}
|
||||
|
||||
// ConstraintOp describes the operator used in a constraint on a virtual
|
||||
// table column. It loosely mirrors the op field of sqlite3_index_constraint.
|
||||
type ConstraintOp int
|
||||
|
||||
const (
|
||||
// OpUnknown indicates an operator that is not recognized or not mapped.
|
||||
// Modules should treat this conservatively.
|
||||
OpUnknown ConstraintOp = iota
|
||||
OpEQ
|
||||
OpGT
|
||||
OpLE
|
||||
OpLT
|
||||
OpGE
|
||||
OpMATCH // "MATCH" operator (e.g. for FTS or KNN semantics)
|
||||
OpNE
|
||||
OpIS
|
||||
OpISNOT
|
||||
OpISNULL
|
||||
OpISNOTNULL
|
||||
OpLIKE
|
||||
OpGLOB
|
||||
OpREGEXP
|
||||
OpFUNCTION
|
||||
OpLIMIT
|
||||
OpOFFSET
|
||||
)
|
||||
|
||||
// Constraint describes a single WHERE-clause constraint that SQLite is
|
||||
// considering pushing down to the virtual table.
|
||||
type Constraint struct {
|
||||
Column int
|
||||
Op ConstraintOp
|
||||
Usable bool
|
||||
// ArgIndex selects which position in argv[] (0-based) should contain the
|
||||
// RHS value for this constraint when Filter is called. Set to -1 to ignore.
|
||||
ArgIndex int
|
||||
// Omit requests SQLite to omit the corresponding constraint from the
|
||||
// parent query if the virtual table fully handles it.
|
||||
Omit bool
|
||||
}
|
||||
|
||||
// OrderBy describes a single ORDER BY term for a query involving a virtual
|
||||
// table.
|
||||
type OrderBy struct {
|
||||
Column int
|
||||
Desc bool
|
||||
}
|
||||
|
||||
// IndexInfo holds information about constraints and orderings for a virtual
|
||||
// table query. It is the Go analogue of sqlite3_index_info.
|
||||
type IndexInfo struct {
|
||||
Constraints []Constraint
|
||||
OrderBy []OrderBy
|
||||
|
||||
// IdxNum selects the query plan chosen in BestIndex. This value is passed
|
||||
// back to Cursor.Filter. Note: SQLite stores this as a 32-bit signed
|
||||
// integer (int32). Implementations must ensure IdxNum fits within the
|
||||
// int32 range; values outside of int32 will cause an error in the driver
|
||||
// to avoid silent truncation.
|
||||
IdxNum int64
|
||||
IdxStr string
|
||||
// IdxFlags provides extra information about the chosen plan.
|
||||
// Set to IndexScanUnique to indicate the plan visits at most one row.
|
||||
IdxFlags int
|
||||
OrderByConsumed bool
|
||||
EstimatedCost float64
|
||||
EstimatedRows int64
|
||||
// ColUsed is a bitmask indicating which columns are used by the query.
|
||||
// Bit N is set if column N is referenced.
|
||||
ColUsed uint64
|
||||
}
|
||||
|
||||
// Index flag values for IndexInfo.IdxFlags.
|
||||
const (
|
||||
// IndexScanUnique mirrors SQLITE_INDEX_SCAN_UNIQUE and indicates that the
|
||||
// chosen plan will visit at most one row.
|
||||
IndexScanUnique = 1
|
||||
)
|
||||
|
||||
// ErrNotImplemented is returned by RegisterModule when the underlying engine
|
||||
// has not yet installed a registration hook. External projects can depend on
|
||||
// the vtab API surface before the low-level bridge to sqlite3_create_module
|
||||
// is fully wired; once the engine sets the hook via SetRegisterFunc,
|
||||
// RegisterModule will forward calls to it.
|
||||
var ErrNotImplemented = errors.New("vtab: RegisterModule not wired into engine")
|
||||
|
||||
// registerHook is installed by the engine package via SetRegisterFunc. It is
|
||||
// invoked by RegisterModule to perform the actual module registration.
|
||||
var registerHook func(name string, m Module) error
|
||||
|
||||
// SetRegisterFunc is intended to be called by the engine package to provide
|
||||
// the concrete implementation of module registration. External callers
|
||||
// should use RegisterModule instead.
|
||||
func SetRegisterFunc(fn func(name string, m Module) error) { registerHook = fn }
|
||||
|
||||
// RegisterModule registers a virtual table module with the provided *sql.DB.
|
||||
//
|
||||
// Registration applies to new connections only. Existing open connections will
|
||||
// not be updated to include newly registered modules.
|
||||
//
|
||||
// Registration is performed when opening a new connection. If the underlying
|
||||
// sqlite3_create_module_v2 call fails, opening the connection fails and returns
|
||||
// that error. This fail-fast behavior prevents partially-initialized
|
||||
// connections when a module cannot be installed.
|
||||
//
|
||||
// The db parameter is currently unused by the engine; it is available so
|
||||
// module implementations can capture it if they need a *sql.DB for their own
|
||||
// internal queries.
|
||||
func RegisterModule(db *sql.DB, name string, m Module) error {
|
||||
_ = db
|
||||
if registerHook == nil {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
if name == "" {
|
||||
return errors.New("vtab: module name must be non-empty")
|
||||
}
|
||||
if m == nil {
|
||||
return errors.New("vtab: module implementation is nil")
|
||||
}
|
||||
return registerHook(name, m)
|
||||
}
|
||||
Reference in New Issue
Block a user