update
This commit is contained in:
90
phoenix/deps/exqlite/.clang-format
Normal file
90
phoenix/deps/exqlite/.clang-format
Normal file
@@ -0,0 +1,90 @@
|
||||
---
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignConsecutiveMacros: true
|
||||
AlignEscapedNewlinesLeft: false
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: TopLevel
|
||||
AlwaysBreakAfterReturnType: TopLevelDefinitions
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterControlStatement: false
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Mozilla
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: true
|
||||
ColumnLimit: 0
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 2
|
||||
ContinuationIndentWidth: 2
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
- Regex: '^(<|"(gtest|isl|json)/)'
|
||||
Priority: 3
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
IndentCaseLabels: true
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
IndentPPDirectives: BeforeHash
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: false
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerAlignment: Left
|
||||
ReflowComments: false
|
||||
SortIncludes: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
...
|
||||
7
phoenix/deps/exqlite/.formatter.exs
Normal file
7
phoenix/deps/exqlite/.formatter.exs
Normal file
@@ -0,0 +1,7 @@
|
||||
[
|
||||
inputs: [
|
||||
"{mix,.formatter}.exs",
|
||||
"{config,lib,test}/**/*.{ex,exs}"
|
||||
],
|
||||
line_length: 88
|
||||
]
|
||||
BIN
phoenix/deps/exqlite/.hex
Normal file
BIN
phoenix/deps/exqlite/.hex
Normal file
Binary file not shown.
21
phoenix/deps/exqlite/LICENSE
Normal file
21
phoenix/deps/exqlite/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Matthew A. Johnston
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
160
phoenix/deps/exqlite/Makefile
Normal file
160
phoenix/deps/exqlite/Makefile
Normal file
@@ -0,0 +1,160 @@
|
||||
#
|
||||
# Makefile for building the NIF
|
||||
#
|
||||
# Makefile targets:
|
||||
#
|
||||
# all build and install the NIF
|
||||
# clean clean build products and intermediates
|
||||
#
|
||||
# Variables to override:
|
||||
#
|
||||
# MIX_APP_PATH path to the build directory
|
||||
#
|
||||
# CC The C compiler
|
||||
# CROSSCOMPILE crosscompiler prefix, if any
|
||||
# CFLAGS compiler flags for compiling all C files
|
||||
# LDFLAGS linker flags for linking all binaries
|
||||
# ERL_CFLAGS additional compiler flags for files using Erlang header files
|
||||
# ERL_EI_INCLUDE_DIR include path to header files (Possibly required for crosscompile)
|
||||
#
|
||||
|
||||
SRC = c_src/sqlite3_nif.c
|
||||
|
||||
CFLAGS = -I"$(ERTS_INCLUDE_DIR)"
|
||||
|
||||
ifeq ($(EXQLITE_USE_SYSTEM),)
|
||||
SRC += c_src/sqlite3.c
|
||||
CFLAGS += -Ic_src
|
||||
else
|
||||
ifneq ($(EXQLITE_SYSTEM_LDFLAGS),)
|
||||
LDFLAGS += $(EXQLITE_SYSTEM_LDFLAGS)
|
||||
else
|
||||
# best attempt to link the system library
|
||||
# if the user didn't supply it in the environment
|
||||
LDFLAGS += -lsqlite3
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(DEBUG),)
|
||||
CFLAGS += -g
|
||||
else
|
||||
CFLAGS += -DNDEBUG=1 -O2
|
||||
endif
|
||||
|
||||
KERNEL_NAME := $(shell uname -s)
|
||||
|
||||
PREFIX = $(MIX_APP_PATH)/priv
|
||||
BUILD = $(MIX_APP_PATH)/obj
|
||||
LIB_NAME = $(PREFIX)/sqlite3_nif.so
|
||||
ARCHIVE_NAME = $(PREFIX)/sqlite3_nif.a
|
||||
|
||||
OBJ = $(SRC:c_src/%.c=$(BUILD)/%.o)
|
||||
|
||||
ifneq ($(CROSSCOMPILE),)
|
||||
ifeq ($(CROSSCOMPILE), Android)
|
||||
CFLAGS:=$(filter-out -O2,$(CFLAGS))
|
||||
CFLAGS += -fPIC -Os -z global
|
||||
LDFLAGS += -fPIC -shared -lm
|
||||
else ifeq ($(findstring linux,$(CROSSCOMPILE)),linux)
|
||||
CFLAGS:=$(filter-out -O2,$(CFLAGS))
|
||||
CFLAGS += -fPIC -Os -fvisibility=hidden
|
||||
LDFLAGS += -fPIC -shared
|
||||
else
|
||||
CFLAGS += -fPIC -fvisibility=hidden
|
||||
LDFLAGS += -fPIC -shared
|
||||
endif
|
||||
else
|
||||
ifeq ($(KERNEL_NAME), Linux)
|
||||
CFLAGS += -fPIC -fvisibility=hidden
|
||||
LDFLAGS += -fPIC -shared
|
||||
endif
|
||||
ifeq ($(KERNEL_NAME), Darwin)
|
||||
CFLAGS += -fPIC
|
||||
LDFLAGS += -dynamiclib -undefined dynamic_lookup
|
||||
endif
|
||||
ifeq (MINGW, $(findstring MINGW,$(KERNEL_NAME)))
|
||||
CFLAGS += -fPIC
|
||||
LDFLAGS += -fPIC -shared
|
||||
LIB_NAME = $(PREFIX)/sqlite3_nif.dll
|
||||
endif
|
||||
ifeq ($(KERNEL_NAME), $(filter $(KERNEL_NAME),OpenBSD FreeBSD NetBSD SunOS))
|
||||
CFLAGS += -fPIC
|
||||
LDFLAGS += -fPIC -shared
|
||||
endif
|
||||
endif
|
||||
|
||||
# ########################
|
||||
# COMPILE TIME DEFINITIONS
|
||||
# ########################
|
||||
|
||||
# For more information about these features being enabled, check out
|
||||
# --> https://sqlite.org/compile.html
|
||||
CFLAGS += -DSQLITE_THREADSAFE=1
|
||||
CFLAGS += -DSQLITE_USE_URI=1
|
||||
CFLAGS += -DSQLITE_LIKE_DOESNT_MATCH_BLOBS=1
|
||||
CFLAGS += -DSQLITE_DQS=0
|
||||
CFLAGS += -DHAVE_USLEEP=1
|
||||
|
||||
# TODO: The following features should be completely configurable by the person
|
||||
# installing the nif. Just need to have certain environment variables
|
||||
# enabled to support them.
|
||||
CFLAGS += -DALLOW_COVERING_INDEX_SCAN=1
|
||||
CFLAGS += -DENABLE_FTS3_PARENTHESIS=1
|
||||
CFLAGS += -DENABLE_LOAD_EXTENSION=1
|
||||
CFLAGS += -DENABLE_SOUNDEX=1
|
||||
CFLAGS += -DENABLE_STAT4=1
|
||||
CFLAGS += -DENABLE_UPDATE_DELETE_LIMIT=1
|
||||
CFLAGS += -DSQLITE_ENABLE_FTS3=1
|
||||
CFLAGS += -DSQLITE_ENABLE_FTS4=1
|
||||
CFLAGS += -DSQLITE_ENABLE_FTS5=1
|
||||
CFLAGS += -DSQLITE_ENABLE_GEOPOLY=1
|
||||
CFLAGS += -DSQLITE_ENABLE_MATH_FUNCTIONS=1
|
||||
CFLAGS += -DSQLITE_ENABLE_RBU=1
|
||||
CFLAGS += -DSQLITE_ENABLE_RTREE=1
|
||||
CFLAGS += -DSQLITE_OMIT_DEPRECATED=1
|
||||
CFLAGS += -DSQLITE_ENABLE_DBSTAT_VTAB=1
|
||||
|
||||
# Add any extra flags set in the environment
|
||||
ifneq ($(EXQLITE_SYSTEM_CFLAGS),)
|
||||
CFLAGS += $(EXQLITE_SYSTEM_CFLAGS)
|
||||
endif
|
||||
|
||||
# Set Erlang-specific compile flags
|
||||
ifeq ($(CC_PRECOMPILER_CURRENT_TARGET),armv7l-linux-gnueabihf)
|
||||
ERL_CFLAGS ?= -I"$(PRECOMPILE_ERL_EI_INCLUDE_DIR)"
|
||||
else
|
||||
ERL_CFLAGS ?= -I"$(ERL_EI_INCLUDE_DIR)"
|
||||
endif
|
||||
|
||||
ifneq ($(STATIC_ERLANG_NIF),)
|
||||
CFLAGS += -DSTATIC_ERLANG_NIF=1
|
||||
endif
|
||||
|
||||
ifeq ($(STATIC_ERLANG_NIF),)
|
||||
all: $(PREFIX) $(BUILD) $(LIB_NAME)
|
||||
else
|
||||
all: $(PREFIX) $(BUILD) $(ARCHIVE_NAME)
|
||||
endif
|
||||
|
||||
$(BUILD)/%.o: c_src/%.c
|
||||
@echo " CC $(notdir $@)"
|
||||
$(CC) -c $(ERL_CFLAGS) $(CFLAGS) -o $@ $<
|
||||
|
||||
$(LIB_NAME): $(OBJ)
|
||||
@echo " LD $(notdir $@)"
|
||||
$(CC) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
$(ARCHIVE_NAME): $(OBJ)
|
||||
@echo " AR $(notdir $@)"
|
||||
$(AR) -rv $@ $^
|
||||
|
||||
$(PREFIX) $(BUILD):
|
||||
mkdir -p $@
|
||||
|
||||
clean:
|
||||
$(RM) $(LIB_NAME) $(ARCHIVE_NAME) $(OBJ)
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
# Don't echo commands unless the caller exports "V=1"
|
||||
${V}.SILENT:
|
||||
71
phoenix/deps/exqlite/Makefile.win
Normal file
71
phoenix/deps/exqlite/Makefile.win
Normal file
@@ -0,0 +1,71 @@
|
||||
!IF [where /q Makefile.auto.win]
|
||||
# The file doesn't exist, so don't include it.
|
||||
!ELSE
|
||||
!INCLUDE Makefile.auto.win
|
||||
!IF [del /f /q Makefile.auto.win] == 0
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
NMAKE = nmake -$(MAKEFLAGS)
|
||||
|
||||
SRC = c_src\sqlite3.c \
|
||||
c_src\sqlite3_nif.c
|
||||
|
||||
CFLAGS = -O2 $(CFLAGS)
|
||||
CFLAGS = -EHsc $(CFLAGS)
|
||||
|
||||
# -Wall will emit a lot of warnings on Windows
|
||||
# CFLAGS = -Wall $(CFLAGS)
|
||||
CFLAGS = -Ic_src $(CFLAGS)
|
||||
|
||||
# For more information about these features being enabled, check out
|
||||
# --> https://sqlite.org/compile.html
|
||||
CFLAGS = -DSQLITE_THREADSAFE=1 $(CFLAGS)
|
||||
CFLAGS = -DSQLITE_USE_URI=1 $(CFLAGS)
|
||||
CFLAGS = -DSQLITE_LIKE_DOESNT_MATCH_BLOBS=1 $(CFLAGS)
|
||||
CFLAGS = -DSQLITE_DQS=0 $(CFLAGS)
|
||||
CFLAGS = -DHAVE_USLEEP=1 $(CFLAGS)
|
||||
|
||||
# TODO: The following features should be completely configurable by the person
|
||||
# installing the nif. Just need to have certain environment variables
|
||||
# enabled to support them.
|
||||
CFLAGS = -DALLOW_COVERING_INDEX_SCAN=1 $(CFLAGS)
|
||||
CFLAGS = -DENABLE_FTS3_PARENTHESIS=1 $(CFLAGS)
|
||||
CFLAGS = -DENABLE_LOAD_EXTENSION=1 $(CFLAGS)
|
||||
CFLAGS = -DENABLE_SOUNDEX=1 $(CFLAGS)
|
||||
CFLAGS = -DENABLE_STAT4=1 $(CFLAGS)
|
||||
CFLAGS = -DENABLE_UPDATE_DELETE_LIMIT=1 $(CFLAGS)
|
||||
CFLAGS = -DSQLITE_ENABLE_FTS3=1 $(CFLAGS)
|
||||
CFLAGS = -DSQLITE_ENABLE_FTS4=1 $(CFLAGS)
|
||||
CFLAGS = -DSQLITE_ENABLE_FTS5=1 $(CFLAGS)
|
||||
CFLAGS = -DSQLITE_ENABLE_GEOPOLY=1 $(CFLAGS)
|
||||
CFLAGS = -DSQLITE_ENABLE_MATH_FUNCTIONS=1 $(CFLAGS)
|
||||
CFLAGS = -DSQLITE_ENABLE_RBU=1 $(CFLAGS)
|
||||
CFLAGS = -DSQLITE_ENABLE_RTREE=1 $(CFLAGS)
|
||||
CFLAGS = -DSQLITE_OMIT_DEPRECATED=1 $(CFLAGS)
|
||||
CFLAGS = -DSQLITE_ENABLE_DBSTAT_VTAB=1 $(CFLAGS)
|
||||
|
||||
# TODO: We should allow the person building to be able to specify this
|
||||
CFLAGS = -DNDEBUG=1 $(CFLAGS)
|
||||
|
||||
# Set Erlang-specific compile flags
|
||||
!IFNDEF ERL_CFLAGS
|
||||
ERL_CFLAGS = -I"$(ERL_EI_INCLUDE_DIR)"
|
||||
!ENDIF
|
||||
|
||||
all: clean priv\sqlite3_nif.dll
|
||||
|
||||
clean:
|
||||
del /f /q priv
|
||||
|
||||
Makefile.auto.win:
|
||||
erl -noshell -eval "io:format(\"ERTS_INCLUDE_PATH=~ts/erts-~ts/include/\", [code:root_dir(), erlang:system_info(version)])." -s erlang halt > $@
|
||||
|
||||
!IFDEF ERTS_INCLUDE_PATH
|
||||
priv\sqlite3_nif.dll:
|
||||
if NOT EXIST "priv" mkdir "priv"
|
||||
$(CC) $(ERL_CFLAGS) $(CFLAGS) -I"$(ERTS_INCLUDE_PATH)" -LD -MD -Fe$@ $(SRC)
|
||||
!ELSE
|
||||
priv\sqlite3_nif.dll: Makefile.auto.win
|
||||
$(NMAKE) -F Makefile.win priv\sqlite3_nif.dll
|
||||
!ENDIF
|
||||
264
phoenix/deps/exqlite/README.md
Normal file
264
phoenix/deps/exqlite/README.md
Normal file
@@ -0,0 +1,264 @@
|
||||
# Exqlite
|
||||
|
||||
[](https://github.com/elixir-sqlite/exqlite/actions)
|
||||
[](https://hex.pm/packages/exqlite)
|
||||
[](https://hexdocs.pm/exqlite)
|
||||
|
||||
An Elixir SQLite3 library.
|
||||
|
||||
If you are looking for the Ecto adapter, take a look at the
|
||||
[Ecto SQLite3 library][ecto_sqlite3].
|
||||
|
||||
Documentation: https://hexdocs.pm/exqlite
|
||||
Package: https://hex.pm/packages/exqlite
|
||||
|
||||
|
||||
## Caveats
|
||||
|
||||
* Prepared statements are not cached.
|
||||
* Prepared statements are not immutable. You must be careful when manipulating
|
||||
statements and binding values to statements. Do not try to manipulate the
|
||||
statements concurrently. Keep it isolated to one process.
|
||||
* Simultaneous writing is not supported by SQLite3 and will not be supported
|
||||
here.
|
||||
* All native calls are run through the Dirty NIF scheduler.
|
||||
* Datetimes are stored without offsets. This is due to how SQLite3 handles date
|
||||
and times. If you would like to store a timezone, you will need to create a
|
||||
second column somewhere storing the timezone name and shifting it when you
|
||||
get it from the database. This is more reliable than storing the offset as
|
||||
`+03:00` as it does not respect daylight savings time.
|
||||
* When storing `BLOB` values, you have to use `{:blob, the_binary}`, otherwise
|
||||
it will be interpreted as a string.
|
||||
|
||||
## Installation
|
||||
|
||||
```elixir
|
||||
defp deps do
|
||||
[
|
||||
{:exqlite, "~> 0.27"}
|
||||
]
|
||||
end
|
||||
```
|
||||
|
||||
|
||||
## Configuration
|
||||
|
||||
### Runtime Configuration
|
||||
|
||||
```elixir
|
||||
config :exqlite,
|
||||
default_chunk_size: 100,
|
||||
type_extensions: [MyApp.TypeExtension]
|
||||
```
|
||||
|
||||
* `default_chunk_size` - The chunk size that is used when multi-stepping when
|
||||
not specifying the chunk size explicitly.
|
||||
* `type_extensions`: An optional list of modules that implement the
|
||||
Exqlite.TypeExtension behaviour, allowing types beyond the default set that
|
||||
can be stored and retrieved from the database.
|
||||
|
||||
### Compile-time Configuration
|
||||
|
||||
In `config/config.exs`,
|
||||
|
||||
```elixir
|
||||
config :exqlite, force_build: false
|
||||
```
|
||||
|
||||
* `force_build` - Set `true` to opt out of using precompiled artefacts.
|
||||
This option only affects the default configuration. For advanced configuation,
|
||||
this library will always compile natively.
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Defining Extra Compile Flags
|
||||
|
||||
You can enable certain features by doing the following:
|
||||
|
||||
```bash
|
||||
export EXQLITE_SYSTEM_CFLAGS=-DSQLITE_ENABLE_DBSTAT_VTAB=1
|
||||
```
|
||||
|
||||
Or you can pass extra environment variables using the Elixir config:
|
||||
|
||||
```elixir
|
||||
config :exqlite,
|
||||
force_build: true,
|
||||
make_env: %{
|
||||
"EXQLITE_SYSTEM_CFLAGS" => "-DSQLITE_ENABLE_DBSTAT_VTAB=1",
|
||||
"V" => "1"
|
||||
}
|
||||
```
|
||||
|
||||
### Listing Flags Used For Compilation
|
||||
|
||||
If you `export V=1` the flags used for compilation will be output to stdout.
|
||||
|
||||
### Using System Installed Libraries
|
||||
|
||||
This will vary depending on the operating system.
|
||||
|
||||
```bash
|
||||
# tell exqlite that we wish to use some other sqlite installation. this will prevent sqlite3.c and friends from compiling
|
||||
export EXQLITE_USE_SYSTEM=1
|
||||
|
||||
# Tell exqlite where to find the `sqlite3.h` file
|
||||
export EXQLITE_SYSTEM_CFLAGS=-I/usr/include
|
||||
|
||||
# tell exqlite which sqlite implementation to use
|
||||
export EXQLITE_SYSTEM_LDFLAGS=-L/lib -lsqlite3
|
||||
```
|
||||
|
||||
After exporting those variables you can then invoke `mix deps.compile`. Note if you
|
||||
re-export those values, you will need to recompile the `exqlite` dependency in order to
|
||||
pickup those changes.
|
||||
|
||||
### Database Encryption
|
||||
|
||||
As of version 0.9, `exqlite` supports loading database engines at runtime rather than compiling `sqlite3.c` itself.
|
||||
This can be used to support database level encryption via alternate engines such as [SQLCipher](https://www.zetetic.net/sqlcipher/design)
|
||||
or the [Official SEE extension](https://www.sqlite.org/see/doc/trunk/www/readme.wiki). Once you have either of those projects installed
|
||||
on your system, use the following environment variables during compilation:
|
||||
|
||||
```bash
|
||||
# tell exqlite that we wish to use some other sqlite installation. this will prevent sqlite3.c and friends from compiling
|
||||
export EXQLITE_USE_SYSTEM=1
|
||||
|
||||
# Tell exqlite where to find the `sqlite3.h` file
|
||||
export EXQLITE_SYSTEM_CFLAGS=-I/usr/local/include/sqlcipher
|
||||
|
||||
# tell exqlite which sqlite implementation to use
|
||||
export EXQLITE_SYSTEM_LDFLAGS=-L/usr/local/lib -lsqlcipher
|
||||
```
|
||||
|
||||
Once you have `exqlite` configured, you can use the `:key` option in the database config to enable encryption:
|
||||
|
||||
```elixir
|
||||
config :exqlite, key: "super-secret'
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
The `Exqlite.Sqlite3` module usage is fairly straight forward.
|
||||
|
||||
```elixir
|
||||
# We'll just keep it in memory right now
|
||||
{:ok, conn} = Exqlite.Sqlite3.open(":memory:")
|
||||
|
||||
# Create the table
|
||||
:ok = Exqlite.Sqlite3.execute(conn, "create table test (id integer primary key, stuff text)")
|
||||
|
||||
# Prepare a statement
|
||||
{:ok, statement} = Exqlite.Sqlite3.prepare(conn, "insert into test (stuff) values (?1)")
|
||||
:ok = Exqlite.Sqlite3.bind(statement, ["Hello world"])
|
||||
|
||||
# Step is used to run statements
|
||||
:done = Exqlite.Sqlite3.step(conn, statement)
|
||||
|
||||
# Prepare a select statement
|
||||
{:ok, statement} = Exqlite.Sqlite3.prepare(conn, "select id, stuff from test")
|
||||
|
||||
# Get the results
|
||||
{:row, [1, "Hello world"]} = Exqlite.Sqlite3.step(conn, statement)
|
||||
|
||||
# No more results
|
||||
:done = Exqlite.Sqlite3.step(conn, statement)
|
||||
|
||||
# Release the statement.
|
||||
#
|
||||
# It is recommended you release the statement after using it to reclaim the memory
|
||||
# asap, instead of letting the garbage collector eventually releasing the statement.
|
||||
#
|
||||
# If you are operating at a high load issuing thousands of statements, it would be
|
||||
# possible to run out of memory or cause a lot of pressure on memory.
|
||||
:ok = Exqlite.Sqlite3.release(conn, statement)
|
||||
```
|
||||
|
||||
### Using SQLite3 native extensions
|
||||
|
||||
Exqlite supports loading [run-time loadable SQLite3 extensions](https://www.sqlite.org/loadext.html).
|
||||
A selection of precompiled extensions for popular CPU types / architectures is
|
||||
available by installing the [ExSqlean](https://github.com/mindreframer/ex_sqlean)
|
||||
package. This package wraps [SQLean: all the missing SQLite functions](https://github.com/nalgeon/sqlean).
|
||||
|
||||
```elixir
|
||||
alias Exqlite.Basic
|
||||
{:ok, conn} = Basic.open("db.sqlite3")
|
||||
:ok = Basic.enable_load_extension(conn)
|
||||
|
||||
# load the regexp extension - https://github.com/nalgeon/sqlean/blob/main/docs/re.md
|
||||
Basic.load_extension(conn, ExSqlean.path_for("re"))
|
||||
|
||||
# run some queries to test the new `regexp_like` function
|
||||
{:ok, [[1]], ["value"]} = Basic.exec(conn, "select regexp_like('the year is 2021', ?) as value", ["2021"]) |> Basic.rows()
|
||||
{:ok, [[0]], ["value"]} = Basic.exec(conn, "select regexp_like('the year is 2021', ?) as value", ["2020"]) |> Basic.rows()
|
||||
|
||||
# prevent loading further extensions
|
||||
:ok = Basic.disable_load_extension(conn)
|
||||
{:error, %Exqlite.Error{message: "not authorized"}, _} = Basic.load_extension(conn, ExSqlean.path_for("re"))
|
||||
|
||||
# close connection
|
||||
Basic.close(conn)
|
||||
```
|
||||
|
||||
It is also possible to load extensions using the `Connection` configuration. For example:
|
||||
|
||||
```elixir
|
||||
arch_dir =
|
||||
System.cmd("uname", ["-sm"])
|
||||
|> elem(0)
|
||||
|> String.trim()
|
||||
|> String.replace(" ", "-")
|
||||
|> String.downcase() # => "darwin-arm64"
|
||||
|
||||
config :myapp, arch_dir: arch_dir
|
||||
|
||||
# global
|
||||
config :exqlite, load_extensions: [ "./priv/sqlite/\#{arch_dir}/rotate" ]
|
||||
|
||||
# per connection in a Phoenix app
|
||||
config :myapp, Myapp.Repo,
|
||||
database: "path/to/db",
|
||||
load_extensions: [
|
||||
"./priv/sqlite/\#{arch_dir}/vector0",
|
||||
"./priv/sqlite/\#{arch_dir}/vss0"
|
||||
]
|
||||
```
|
||||
|
||||
See [Exqlite.Connection.connect/1](https://hexdocs.pm/exqlite/Exqlite.Connection.html#connect/1)
|
||||
for more information. When using extensions for SQLite3, they must be compiled
|
||||
for the environment you are targeting.
|
||||
|
||||
## Why SQLite3
|
||||
|
||||
I needed an Ecto3 adapter to store time series data for a personal project. I
|
||||
didn't want to go through the hassle of trying to setup a postgres database or
|
||||
mysql database when I was just wanting to explore data ingestion and some map
|
||||
reduce problems.
|
||||
|
||||
I also noticed that other SQLite3 implementations didn't really fit my needs. At
|
||||
some point I also wanted to use this with a nerves project on an embedded device
|
||||
that would be resiliant to power outages and still maintain some state that
|
||||
`ets` can not afford.
|
||||
|
||||
|
||||
## Under The Hood
|
||||
|
||||
We are using the Dirty NIF scheduler to execute the sqlite calls. The rationale
|
||||
behind this is that maintaining each sqlite's connection command pool is
|
||||
complicated and error prone.
|
||||
|
||||
|
||||
## Compiling NIF for Windows
|
||||
|
||||
When compiling on Windows, you will need the [Build Tools](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022) or equivalent toolchain. Please make sure you have the correct environment variables, including path to compiler and linker and architecture that matches `erl.exe` (likely x64).
|
||||
|
||||
You may also need to invoke `vcvarsall.bat amd64` _before_ running `mix`.
|
||||
|
||||
A guide is available at [guides/windows.md](./guides/windows.md)
|
||||
|
||||
## Contributing
|
||||
|
||||
Feel free to check the project out and submit pull requests.
|
||||
|
||||
[ecto_sqlite3]: <https://github.com/elixir-sqlite/ecto_sqlite3>
|
||||
265977
phoenix/deps/exqlite/c_src/sqlite3.c
Normal file
265977
phoenix/deps/exqlite/c_src/sqlite3.c
Normal file
File diff suppressed because it is too large
Load Diff
13968
phoenix/deps/exqlite/c_src/sqlite3.h
Normal file
13968
phoenix/deps/exqlite/c_src/sqlite3.h
Normal file
File diff suppressed because it is too large
Load Diff
1799
phoenix/deps/exqlite/c_src/sqlite3_nif.c
Normal file
1799
phoenix/deps/exqlite/c_src/sqlite3_nif.c
Normal file
File diff suppressed because it is too large
Load Diff
730
phoenix/deps/exqlite/c_src/sqlite3ext.h
Normal file
730
phoenix/deps/exqlite/c_src/sqlite3ext.h
Normal file
@@ -0,0 +1,730 @@
|
||||
/*
|
||||
** 2006 June 7
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This header file defines the SQLite interface for use by
|
||||
** shared libraries that want to be imported as extensions into
|
||||
** an SQLite instance. Shared libraries that intend to be loaded
|
||||
** as extensions by SQLite should #include this file instead of
|
||||
** sqlite3.h.
|
||||
*/
|
||||
#ifndef SQLITE3EXT_H
|
||||
#define SQLITE3EXT_H
|
||||
#include "sqlite3.h"
|
||||
|
||||
/*
|
||||
** The following structure holds pointers to all of the SQLite API
|
||||
** routines.
|
||||
**
|
||||
** WARNING: In order to maintain backwards compatibility, add new
|
||||
** interfaces to the end of this structure only. If you insert new
|
||||
** interfaces in the middle of this structure, then older different
|
||||
** versions of SQLite will not be able to load each other's shared
|
||||
** libraries!
|
||||
*/
|
||||
struct sqlite3_api_routines {
|
||||
void * (*aggregate_context)(sqlite3_context*,int nBytes);
|
||||
int (*aggregate_count)(sqlite3_context*);
|
||||
int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
|
||||
int (*bind_double)(sqlite3_stmt*,int,double);
|
||||
int (*bind_int)(sqlite3_stmt*,int,int);
|
||||
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
|
||||
int (*bind_null)(sqlite3_stmt*,int);
|
||||
int (*bind_parameter_count)(sqlite3_stmt*);
|
||||
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
|
||||
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
|
||||
int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
|
||||
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
|
||||
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
|
||||
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
|
||||
int (*busy_timeout)(sqlite3*,int ms);
|
||||
int (*changes)(sqlite3*);
|
||||
int (*close)(sqlite3*);
|
||||
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
||||
int eTextRep,const char*));
|
||||
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
||||
int eTextRep,const void*));
|
||||
const void * (*column_blob)(sqlite3_stmt*,int iCol);
|
||||
int (*column_bytes)(sqlite3_stmt*,int iCol);
|
||||
int (*column_bytes16)(sqlite3_stmt*,int iCol);
|
||||
int (*column_count)(sqlite3_stmt*pStmt);
|
||||
const char * (*column_database_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_database_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_decltype)(sqlite3_stmt*,int i);
|
||||
const void * (*column_decltype16)(sqlite3_stmt*,int);
|
||||
double (*column_double)(sqlite3_stmt*,int iCol);
|
||||
int (*column_int)(sqlite3_stmt*,int iCol);
|
||||
sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
|
||||
const char * (*column_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_origin_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_origin_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_table_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_table_name16)(sqlite3_stmt*,int);
|
||||
const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
|
||||
const void * (*column_text16)(sqlite3_stmt*,int iCol);
|
||||
int (*column_type)(sqlite3_stmt*,int iCol);
|
||||
sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
|
||||
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
|
||||
int (*complete)(const char*sql);
|
||||
int (*complete16)(const void*sql);
|
||||
int (*create_collation)(sqlite3*,const char*,int,void*,
|
||||
int(*)(void*,int,const void*,int,const void*));
|
||||
int (*create_collation16)(sqlite3*,const void*,int,void*,
|
||||
int(*)(void*,int,const void*,int,const void*));
|
||||
int (*create_function)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*));
|
||||
int (*create_function16)(sqlite3*,const void*,int,int,void*,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*));
|
||||
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
|
||||
int (*data_count)(sqlite3_stmt*pStmt);
|
||||
sqlite3 * (*db_handle)(sqlite3_stmt*);
|
||||
int (*declare_vtab)(sqlite3*,const char*);
|
||||
int (*enable_shared_cache)(int);
|
||||
int (*errcode)(sqlite3*db);
|
||||
const char * (*errmsg)(sqlite3*);
|
||||
const void * (*errmsg16)(sqlite3*);
|
||||
int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
|
||||
int (*expired)(sqlite3_stmt*);
|
||||
int (*finalize)(sqlite3_stmt*pStmt);
|
||||
void (*free)(void*);
|
||||
void (*free_table)(char**result);
|
||||
int (*get_autocommit)(sqlite3*);
|
||||
void * (*get_auxdata)(sqlite3_context*,int);
|
||||
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
|
||||
int (*global_recover)(void);
|
||||
void (*interruptx)(sqlite3*);
|
||||
sqlite_int64 (*last_insert_rowid)(sqlite3*);
|
||||
const char * (*libversion)(void);
|
||||
int (*libversion_number)(void);
|
||||
void *(*malloc)(int);
|
||||
char * (*mprintf)(const char*,...);
|
||||
int (*open)(const char*,sqlite3**);
|
||||
int (*open16)(const void*,sqlite3**);
|
||||
int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||
int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||
void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
|
||||
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
|
||||
void *(*realloc)(void*,int);
|
||||
int (*reset)(sqlite3_stmt*pStmt);
|
||||
void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_double)(sqlite3_context*,double);
|
||||
void (*result_error)(sqlite3_context*,const char*,int);
|
||||
void (*result_error16)(sqlite3_context*,const void*,int);
|
||||
void (*result_int)(sqlite3_context*,int);
|
||||
void (*result_int64)(sqlite3_context*,sqlite_int64);
|
||||
void (*result_null)(sqlite3_context*);
|
||||
void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
|
||||
void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_value)(sqlite3_context*,sqlite3_value*);
|
||||
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
|
||||
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
|
||||
const char*,const char*),void*);
|
||||
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
|
||||
char * (*xsnprintf)(int,char*,const char*,...);
|
||||
int (*step)(sqlite3_stmt*);
|
||||
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
|
||||
char const**,char const**,int*,int*,int*);
|
||||
void (*thread_cleanup)(void);
|
||||
int (*total_changes)(sqlite3*);
|
||||
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
|
||||
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
|
||||
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
|
||||
sqlite_int64),void*);
|
||||
void * (*user_data)(sqlite3_context*);
|
||||
const void * (*value_blob)(sqlite3_value*);
|
||||
int (*value_bytes)(sqlite3_value*);
|
||||
int (*value_bytes16)(sqlite3_value*);
|
||||
double (*value_double)(sqlite3_value*);
|
||||
int (*value_int)(sqlite3_value*);
|
||||
sqlite_int64 (*value_int64)(sqlite3_value*);
|
||||
int (*value_numeric_type)(sqlite3_value*);
|
||||
const unsigned char * (*value_text)(sqlite3_value*);
|
||||
const void * (*value_text16)(sqlite3_value*);
|
||||
const void * (*value_text16be)(sqlite3_value*);
|
||||
const void * (*value_text16le)(sqlite3_value*);
|
||||
int (*value_type)(sqlite3_value*);
|
||||
char *(*vmprintf)(const char*,va_list);
|
||||
/* Added ??? */
|
||||
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
|
||||
/* Added by 3.3.13 */
|
||||
int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||
int (*clear_bindings)(sqlite3_stmt*);
|
||||
/* Added by 3.4.1 */
|
||||
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
|
||||
void (*xDestroy)(void *));
|
||||
/* Added by 3.5.0 */
|
||||
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
|
||||
int (*blob_bytes)(sqlite3_blob*);
|
||||
int (*blob_close)(sqlite3_blob*);
|
||||
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
|
||||
int,sqlite3_blob**);
|
||||
int (*blob_read)(sqlite3_blob*,void*,int,int);
|
||||
int (*blob_write)(sqlite3_blob*,const void*,int,int);
|
||||
int (*create_collation_v2)(sqlite3*,const char*,int,void*,
|
||||
int(*)(void*,int,const void*,int,const void*),
|
||||
void(*)(void*));
|
||||
int (*file_control)(sqlite3*,const char*,int,void*);
|
||||
sqlite3_int64 (*memory_highwater)(int);
|
||||
sqlite3_int64 (*memory_used)(void);
|
||||
sqlite3_mutex *(*mutex_alloc)(int);
|
||||
void (*mutex_enter)(sqlite3_mutex*);
|
||||
void (*mutex_free)(sqlite3_mutex*);
|
||||
void (*mutex_leave)(sqlite3_mutex*);
|
||||
int (*mutex_try)(sqlite3_mutex*);
|
||||
int (*open_v2)(const char*,sqlite3**,int,const char*);
|
||||
int (*release_memory)(int);
|
||||
void (*result_error_nomem)(sqlite3_context*);
|
||||
void (*result_error_toobig)(sqlite3_context*);
|
||||
int (*sleep)(int);
|
||||
void (*soft_heap_limit)(int);
|
||||
sqlite3_vfs *(*vfs_find)(const char*);
|
||||
int (*vfs_register)(sqlite3_vfs*,int);
|
||||
int (*vfs_unregister)(sqlite3_vfs*);
|
||||
int (*xthreadsafe)(void);
|
||||
void (*result_zeroblob)(sqlite3_context*,int);
|
||||
void (*result_error_code)(sqlite3_context*,int);
|
||||
int (*test_control)(int, ...);
|
||||
void (*randomness)(int,void*);
|
||||
sqlite3 *(*context_db_handle)(sqlite3_context*);
|
||||
int (*extended_result_codes)(sqlite3*,int);
|
||||
int (*limit)(sqlite3*,int,int);
|
||||
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
|
||||
const char *(*sql)(sqlite3_stmt*);
|
||||
int (*status)(int,int*,int*,int);
|
||||
int (*backup_finish)(sqlite3_backup*);
|
||||
sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
|
||||
int (*backup_pagecount)(sqlite3_backup*);
|
||||
int (*backup_remaining)(sqlite3_backup*);
|
||||
int (*backup_step)(sqlite3_backup*,int);
|
||||
const char *(*compileoption_get)(int);
|
||||
int (*compileoption_used)(const char*);
|
||||
int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void(*xDestroy)(void*));
|
||||
int (*db_config)(sqlite3*,int,...);
|
||||
sqlite3_mutex *(*db_mutex)(sqlite3*);
|
||||
int (*db_status)(sqlite3*,int,int*,int*,int);
|
||||
int (*extended_errcode)(sqlite3*);
|
||||
void (*log)(int,const char*,...);
|
||||
sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
|
||||
const char *(*sourceid)(void);
|
||||
int (*stmt_status)(sqlite3_stmt*,int,int);
|
||||
int (*strnicmp)(const char*,const char*,int);
|
||||
int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
|
||||
int (*wal_autocheckpoint)(sqlite3*,int);
|
||||
int (*wal_checkpoint)(sqlite3*,const char*);
|
||||
void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
|
||||
int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
|
||||
int (*vtab_config)(sqlite3*,int op,...);
|
||||
int (*vtab_on_conflict)(sqlite3*);
|
||||
/* Version 3.7.16 and later */
|
||||
int (*close_v2)(sqlite3*);
|
||||
const char *(*db_filename)(sqlite3*,const char*);
|
||||
int (*db_readonly)(sqlite3*,const char*);
|
||||
int (*db_release_memory)(sqlite3*);
|
||||
const char *(*errstr)(int);
|
||||
int (*stmt_busy)(sqlite3_stmt*);
|
||||
int (*stmt_readonly)(sqlite3_stmt*);
|
||||
int (*stricmp)(const char*,const char*);
|
||||
int (*uri_boolean)(const char*,const char*,int);
|
||||
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
|
||||
const char *(*uri_parameter)(const char*,const char*);
|
||||
char *(*xvsnprintf)(int,char*,const char*,va_list);
|
||||
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
|
||||
/* Version 3.8.7 and later */
|
||||
int (*auto_extension)(void(*)(void));
|
||||
int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
|
||||
void(*)(void*));
|
||||
int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
|
||||
void(*)(void*),unsigned char);
|
||||
int (*cancel_auto_extension)(void(*)(void));
|
||||
int (*load_extension)(sqlite3*,const char*,const char*,char**);
|
||||
void *(*malloc64)(sqlite3_uint64);
|
||||
sqlite3_uint64 (*msize)(void*);
|
||||
void *(*realloc64)(void*,sqlite3_uint64);
|
||||
void (*reset_auto_extension)(void);
|
||||
void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,
|
||||
void(*)(void*));
|
||||
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
|
||||
void(*)(void*), unsigned char);
|
||||
int (*strglob)(const char*,const char*);
|
||||
/* Version 3.8.11 and later */
|
||||
sqlite3_value *(*value_dup)(const sqlite3_value*);
|
||||
void (*value_free)(sqlite3_value*);
|
||||
int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
|
||||
int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
|
||||
/* Version 3.9.0 and later */
|
||||
unsigned int (*value_subtype)(sqlite3_value*);
|
||||
void (*result_subtype)(sqlite3_context*,unsigned int);
|
||||
/* Version 3.10.0 and later */
|
||||
int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
|
||||
int (*strlike)(const char*,const char*,unsigned int);
|
||||
int (*db_cacheflush)(sqlite3*);
|
||||
/* Version 3.12.0 and later */
|
||||
int (*system_errno)(sqlite3*);
|
||||
/* Version 3.14.0 and later */
|
||||
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
|
||||
char *(*expanded_sql)(sqlite3_stmt*);
|
||||
/* Version 3.18.0 and later */
|
||||
void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
|
||||
/* Version 3.20.0 and later */
|
||||
int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
|
||||
sqlite3_stmt**,const char**);
|
||||
int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
|
||||
sqlite3_stmt**,const void**);
|
||||
int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
|
||||
void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
|
||||
void *(*value_pointer)(sqlite3_value*,const char*);
|
||||
int (*vtab_nochange)(sqlite3_context*);
|
||||
int (*value_nochange)(sqlite3_value*);
|
||||
const char *(*vtab_collation)(sqlite3_index_info*,int);
|
||||
/* Version 3.24.0 and later */
|
||||
int (*keyword_count)(void);
|
||||
int (*keyword_name)(int,const char**,int*);
|
||||
int (*keyword_check)(const char*,int);
|
||||
sqlite3_str *(*str_new)(sqlite3*);
|
||||
char *(*str_finish)(sqlite3_str*);
|
||||
void (*str_appendf)(sqlite3_str*, const char *zFormat, ...);
|
||||
void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list);
|
||||
void (*str_append)(sqlite3_str*, const char *zIn, int N);
|
||||
void (*str_appendall)(sqlite3_str*, const char *zIn);
|
||||
void (*str_appendchar)(sqlite3_str*, int N, char C);
|
||||
void (*str_reset)(sqlite3_str*);
|
||||
int (*str_errcode)(sqlite3_str*);
|
||||
int (*str_length)(sqlite3_str*);
|
||||
char *(*str_value)(sqlite3_str*);
|
||||
/* Version 3.25.0 and later */
|
||||
int (*create_window_function)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void (*xValue)(sqlite3_context*),
|
||||
void (*xInv)(sqlite3_context*,int,sqlite3_value**),
|
||||
void(*xDestroy)(void*));
|
||||
/* Version 3.26.0 and later */
|
||||
const char *(*normalized_sql)(sqlite3_stmt*);
|
||||
/* Version 3.28.0 and later */
|
||||
int (*stmt_isexplain)(sqlite3_stmt*);
|
||||
int (*value_frombind)(sqlite3_value*);
|
||||
/* Version 3.30.0 and later */
|
||||
int (*drop_modules)(sqlite3*,const char**);
|
||||
/* Version 3.31.0 and later */
|
||||
sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64);
|
||||
const char *(*uri_key)(const char*,int);
|
||||
const char *(*filename_database)(const char*);
|
||||
const char *(*filename_journal)(const char*);
|
||||
const char *(*filename_wal)(const char*);
|
||||
/* Version 3.32.0 and later */
|
||||
const char *(*create_filename)(const char*,const char*,const char*,
|
||||
int,const char**);
|
||||
void (*free_filename)(const char*);
|
||||
sqlite3_file *(*database_file_object)(const char*);
|
||||
/* Version 3.34.0 and later */
|
||||
int (*txn_state)(sqlite3*,const char*);
|
||||
/* Version 3.36.1 and later */
|
||||
sqlite3_int64 (*changes64)(sqlite3*);
|
||||
sqlite3_int64 (*total_changes64)(sqlite3*);
|
||||
/* Version 3.37.0 and later */
|
||||
int (*autovacuum_pages)(sqlite3*,
|
||||
unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int),
|
||||
void*, void(*)(void*));
|
||||
/* Version 3.38.0 and later */
|
||||
int (*error_offset)(sqlite3*);
|
||||
int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**);
|
||||
int (*vtab_distinct)(sqlite3_index_info*);
|
||||
int (*vtab_in)(sqlite3_index_info*,int,int);
|
||||
int (*vtab_in_first)(sqlite3_value*,sqlite3_value**);
|
||||
int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
|
||||
/* Version 3.39.0 and later */
|
||||
int (*deserialize)(sqlite3*,const char*,unsigned char*,
|
||||
sqlite3_int64,sqlite3_int64,unsigned);
|
||||
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
|
||||
unsigned int);
|
||||
const char *(*db_name)(sqlite3*,int);
|
||||
/* Version 3.40.0 and later */
|
||||
int (*value_encoding)(sqlite3_value*);
|
||||
/* Version 3.41.0 and later */
|
||||
int (*is_interrupted)(sqlite3*);
|
||||
/* Version 3.43.0 and later */
|
||||
int (*stmt_explain)(sqlite3_stmt*,int);
|
||||
/* Version 3.44.0 and later */
|
||||
void *(*get_clientdata)(sqlite3*,const char*);
|
||||
int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
|
||||
/* Version 3.50.0 and later */
|
||||
int (*setlk_timeout)(sqlite3*,int,int);
|
||||
/* Version 3.51.0 and later */
|
||||
int (*set_errmsg)(sqlite3*,int,const char*);
|
||||
int (*db_status64)(sqlite3*,int,sqlite3_int64*,sqlite3_int64*,int);
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
** This is the function signature used for all extension entry points. It
|
||||
** is also defined in the file "loadext.c".
|
||||
*/
|
||||
typedef int (*sqlite3_loadext_entry)(
|
||||
sqlite3 *db, /* Handle to the database. */
|
||||
char **pzErrMsg, /* Used to set error string on failure. */
|
||||
const sqlite3_api_routines *pThunk /* Extension API function pointers. */
|
||||
);
|
||||
|
||||
/*
|
||||
** The following macros redefine the API routines so that they are
|
||||
** redirected through the global sqlite3_api structure.
|
||||
**
|
||||
** This header file is also used by the loadext.c source file
|
||||
** (part of the main SQLite library - not an extension) so that
|
||||
** it can get access to the sqlite3_api_routines structure
|
||||
** definition. But the main library does not want to redefine
|
||||
** the API. So the redefinition macros are only valid if the
|
||||
** SQLITE_CORE macros is undefined.
|
||||
*/
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
|
||||
#endif
|
||||
#define sqlite3_bind_blob sqlite3_api->bind_blob
|
||||
#define sqlite3_bind_double sqlite3_api->bind_double
|
||||
#define sqlite3_bind_int sqlite3_api->bind_int
|
||||
#define sqlite3_bind_int64 sqlite3_api->bind_int64
|
||||
#define sqlite3_bind_null sqlite3_api->bind_null
|
||||
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
|
||||
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
|
||||
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
|
||||
#define sqlite3_bind_text sqlite3_api->bind_text
|
||||
#define sqlite3_bind_text16 sqlite3_api->bind_text16
|
||||
#define sqlite3_bind_value sqlite3_api->bind_value
|
||||
#define sqlite3_busy_handler sqlite3_api->busy_handler
|
||||
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
|
||||
#define sqlite3_changes sqlite3_api->changes
|
||||
#define sqlite3_close sqlite3_api->close
|
||||
#define sqlite3_collation_needed sqlite3_api->collation_needed
|
||||
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
|
||||
#define sqlite3_column_blob sqlite3_api->column_blob
|
||||
#define sqlite3_column_bytes sqlite3_api->column_bytes
|
||||
#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
|
||||
#define sqlite3_column_count sqlite3_api->column_count
|
||||
#define sqlite3_column_database_name sqlite3_api->column_database_name
|
||||
#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
|
||||
#define sqlite3_column_decltype sqlite3_api->column_decltype
|
||||
#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
|
||||
#define sqlite3_column_double sqlite3_api->column_double
|
||||
#define sqlite3_column_int sqlite3_api->column_int
|
||||
#define sqlite3_column_int64 sqlite3_api->column_int64
|
||||
#define sqlite3_column_name sqlite3_api->column_name
|
||||
#define sqlite3_column_name16 sqlite3_api->column_name16
|
||||
#define sqlite3_column_origin_name sqlite3_api->column_origin_name
|
||||
#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
|
||||
#define sqlite3_column_table_name sqlite3_api->column_table_name
|
||||
#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
|
||||
#define sqlite3_column_text sqlite3_api->column_text
|
||||
#define sqlite3_column_text16 sqlite3_api->column_text16
|
||||
#define sqlite3_column_type sqlite3_api->column_type
|
||||
#define sqlite3_column_value sqlite3_api->column_value
|
||||
#define sqlite3_commit_hook sqlite3_api->commit_hook
|
||||
#define sqlite3_complete sqlite3_api->complete
|
||||
#define sqlite3_complete16 sqlite3_api->complete16
|
||||
#define sqlite3_create_collation sqlite3_api->create_collation
|
||||
#define sqlite3_create_collation16 sqlite3_api->create_collation16
|
||||
#define sqlite3_create_function sqlite3_api->create_function
|
||||
#define sqlite3_create_function16 sqlite3_api->create_function16
|
||||
#define sqlite3_create_module sqlite3_api->create_module
|
||||
#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
|
||||
#define sqlite3_data_count sqlite3_api->data_count
|
||||
#define sqlite3_db_handle sqlite3_api->db_handle
|
||||
#define sqlite3_declare_vtab sqlite3_api->declare_vtab
|
||||
#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
|
||||
#define sqlite3_errcode sqlite3_api->errcode
|
||||
#define sqlite3_errmsg sqlite3_api->errmsg
|
||||
#define sqlite3_errmsg16 sqlite3_api->errmsg16
|
||||
#define sqlite3_exec sqlite3_api->exec
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_expired sqlite3_api->expired
|
||||
#endif
|
||||
#define sqlite3_finalize sqlite3_api->finalize
|
||||
#define sqlite3_free sqlite3_api->free
|
||||
#define sqlite3_free_table sqlite3_api->free_table
|
||||
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
|
||||
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
|
||||
#define sqlite3_get_table sqlite3_api->get_table
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_global_recover sqlite3_api->global_recover
|
||||
#endif
|
||||
#define sqlite3_interrupt sqlite3_api->interruptx
|
||||
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
|
||||
#define sqlite3_libversion sqlite3_api->libversion
|
||||
#define sqlite3_libversion_number sqlite3_api->libversion_number
|
||||
#define sqlite3_malloc sqlite3_api->malloc
|
||||
#define sqlite3_mprintf sqlite3_api->mprintf
|
||||
#define sqlite3_open sqlite3_api->open
|
||||
#define sqlite3_open16 sqlite3_api->open16
|
||||
#define sqlite3_prepare sqlite3_api->prepare
|
||||
#define sqlite3_prepare16 sqlite3_api->prepare16
|
||||
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||
#define sqlite3_profile sqlite3_api->profile
|
||||
#define sqlite3_progress_handler sqlite3_api->progress_handler
|
||||
#define sqlite3_realloc sqlite3_api->realloc
|
||||
#define sqlite3_reset sqlite3_api->reset
|
||||
#define sqlite3_result_blob sqlite3_api->result_blob
|
||||
#define sqlite3_result_double sqlite3_api->result_double
|
||||
#define sqlite3_result_error sqlite3_api->result_error
|
||||
#define sqlite3_result_error16 sqlite3_api->result_error16
|
||||
#define sqlite3_result_int sqlite3_api->result_int
|
||||
#define sqlite3_result_int64 sqlite3_api->result_int64
|
||||
#define sqlite3_result_null sqlite3_api->result_null
|
||||
#define sqlite3_result_text sqlite3_api->result_text
|
||||
#define sqlite3_result_text16 sqlite3_api->result_text16
|
||||
#define sqlite3_result_text16be sqlite3_api->result_text16be
|
||||
#define sqlite3_result_text16le sqlite3_api->result_text16le
|
||||
#define sqlite3_result_value sqlite3_api->result_value
|
||||
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
|
||||
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
|
||||
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
|
||||
#define sqlite3_snprintf sqlite3_api->xsnprintf
|
||||
#define sqlite3_step sqlite3_api->step
|
||||
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
|
||||
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
|
||||
#define sqlite3_total_changes sqlite3_api->total_changes
|
||||
#define sqlite3_trace sqlite3_api->trace
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
|
||||
#endif
|
||||
#define sqlite3_update_hook sqlite3_api->update_hook
|
||||
#define sqlite3_user_data sqlite3_api->user_data
|
||||
#define sqlite3_value_blob sqlite3_api->value_blob
|
||||
#define sqlite3_value_bytes sqlite3_api->value_bytes
|
||||
#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
|
||||
#define sqlite3_value_double sqlite3_api->value_double
|
||||
#define sqlite3_value_int sqlite3_api->value_int
|
||||
#define sqlite3_value_int64 sqlite3_api->value_int64
|
||||
#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
|
||||
#define sqlite3_value_text sqlite3_api->value_text
|
||||
#define sqlite3_value_text16 sqlite3_api->value_text16
|
||||
#define sqlite3_value_text16be sqlite3_api->value_text16be
|
||||
#define sqlite3_value_text16le sqlite3_api->value_text16le
|
||||
#define sqlite3_value_type sqlite3_api->value_type
|
||||
#define sqlite3_vmprintf sqlite3_api->vmprintf
|
||||
#define sqlite3_vsnprintf sqlite3_api->xvsnprintf
|
||||
#define sqlite3_overload_function sqlite3_api->overload_function
|
||||
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||
#define sqlite3_clear_bindings sqlite3_api->clear_bindings
|
||||
#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
|
||||
#define sqlite3_blob_bytes sqlite3_api->blob_bytes
|
||||
#define sqlite3_blob_close sqlite3_api->blob_close
|
||||
#define sqlite3_blob_open sqlite3_api->blob_open
|
||||
#define sqlite3_blob_read sqlite3_api->blob_read
|
||||
#define sqlite3_blob_write sqlite3_api->blob_write
|
||||
#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
|
||||
#define sqlite3_file_control sqlite3_api->file_control
|
||||
#define sqlite3_memory_highwater sqlite3_api->memory_highwater
|
||||
#define sqlite3_memory_used sqlite3_api->memory_used
|
||||
#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
|
||||
#define sqlite3_mutex_enter sqlite3_api->mutex_enter
|
||||
#define sqlite3_mutex_free sqlite3_api->mutex_free
|
||||
#define sqlite3_mutex_leave sqlite3_api->mutex_leave
|
||||
#define sqlite3_mutex_try sqlite3_api->mutex_try
|
||||
#define sqlite3_open_v2 sqlite3_api->open_v2
|
||||
#define sqlite3_release_memory sqlite3_api->release_memory
|
||||
#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
|
||||
#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
|
||||
#define sqlite3_sleep sqlite3_api->sleep
|
||||
#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
|
||||
#define sqlite3_vfs_find sqlite3_api->vfs_find
|
||||
#define sqlite3_vfs_register sqlite3_api->vfs_register
|
||||
#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
|
||||
#define sqlite3_threadsafe sqlite3_api->xthreadsafe
|
||||
#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
|
||||
#define sqlite3_result_error_code sqlite3_api->result_error_code
|
||||
#define sqlite3_test_control sqlite3_api->test_control
|
||||
#define sqlite3_randomness sqlite3_api->randomness
|
||||
#define sqlite3_context_db_handle sqlite3_api->context_db_handle
|
||||
#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
|
||||
#define sqlite3_limit sqlite3_api->limit
|
||||
#define sqlite3_next_stmt sqlite3_api->next_stmt
|
||||
#define sqlite3_sql sqlite3_api->sql
|
||||
#define sqlite3_status sqlite3_api->status
|
||||
#define sqlite3_backup_finish sqlite3_api->backup_finish
|
||||
#define sqlite3_backup_init sqlite3_api->backup_init
|
||||
#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
|
||||
#define sqlite3_backup_remaining sqlite3_api->backup_remaining
|
||||
#define sqlite3_backup_step sqlite3_api->backup_step
|
||||
#define sqlite3_compileoption_get sqlite3_api->compileoption_get
|
||||
#define sqlite3_compileoption_used sqlite3_api->compileoption_used
|
||||
#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
|
||||
#define sqlite3_db_config sqlite3_api->db_config
|
||||
#define sqlite3_db_mutex sqlite3_api->db_mutex
|
||||
#define sqlite3_db_status sqlite3_api->db_status
|
||||
#define sqlite3_extended_errcode sqlite3_api->extended_errcode
|
||||
#define sqlite3_log sqlite3_api->log
|
||||
#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
|
||||
#define sqlite3_sourceid sqlite3_api->sourceid
|
||||
#define sqlite3_stmt_status sqlite3_api->stmt_status
|
||||
#define sqlite3_strnicmp sqlite3_api->strnicmp
|
||||
#define sqlite3_unlock_notify sqlite3_api->unlock_notify
|
||||
#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
|
||||
#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
|
||||
#define sqlite3_wal_hook sqlite3_api->wal_hook
|
||||
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
|
||||
#define sqlite3_vtab_config sqlite3_api->vtab_config
|
||||
#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
|
||||
/* Version 3.7.16 and later */
|
||||
#define sqlite3_close_v2 sqlite3_api->close_v2
|
||||
#define sqlite3_db_filename sqlite3_api->db_filename
|
||||
#define sqlite3_db_readonly sqlite3_api->db_readonly
|
||||
#define sqlite3_db_release_memory sqlite3_api->db_release_memory
|
||||
#define sqlite3_errstr sqlite3_api->errstr
|
||||
#define sqlite3_stmt_busy sqlite3_api->stmt_busy
|
||||
#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly
|
||||
#define sqlite3_stricmp sqlite3_api->stricmp
|
||||
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
|
||||
#define sqlite3_uri_int64 sqlite3_api->uri_int64
|
||||
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
|
||||
#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf
|
||||
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
|
||||
/* Version 3.8.7 and later */
|
||||
#define sqlite3_auto_extension sqlite3_api->auto_extension
|
||||
#define sqlite3_bind_blob64 sqlite3_api->bind_blob64
|
||||
#define sqlite3_bind_text64 sqlite3_api->bind_text64
|
||||
#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension
|
||||
#define sqlite3_load_extension sqlite3_api->load_extension
|
||||
#define sqlite3_malloc64 sqlite3_api->malloc64
|
||||
#define sqlite3_msize sqlite3_api->msize
|
||||
#define sqlite3_realloc64 sqlite3_api->realloc64
|
||||
#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension
|
||||
#define sqlite3_result_blob64 sqlite3_api->result_blob64
|
||||
#define sqlite3_result_text64 sqlite3_api->result_text64
|
||||
#define sqlite3_strglob sqlite3_api->strglob
|
||||
/* Version 3.8.11 and later */
|
||||
#define sqlite3_value_dup sqlite3_api->value_dup
|
||||
#define sqlite3_value_free sqlite3_api->value_free
|
||||
#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
|
||||
#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
|
||||
/* Version 3.9.0 and later */
|
||||
#define sqlite3_value_subtype sqlite3_api->value_subtype
|
||||
#define sqlite3_result_subtype sqlite3_api->result_subtype
|
||||
/* Version 3.10.0 and later */
|
||||
#define sqlite3_status64 sqlite3_api->status64
|
||||
#define sqlite3_strlike sqlite3_api->strlike
|
||||
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
|
||||
/* Version 3.12.0 and later */
|
||||
#define sqlite3_system_errno sqlite3_api->system_errno
|
||||
/* Version 3.14.0 and later */
|
||||
#define sqlite3_trace_v2 sqlite3_api->trace_v2
|
||||
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
|
||||
/* Version 3.18.0 and later */
|
||||
#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid
|
||||
/* Version 3.20.0 and later */
|
||||
#define sqlite3_prepare_v3 sqlite3_api->prepare_v3
|
||||
#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3
|
||||
#define sqlite3_bind_pointer sqlite3_api->bind_pointer
|
||||
#define sqlite3_result_pointer sqlite3_api->result_pointer
|
||||
#define sqlite3_value_pointer sqlite3_api->value_pointer
|
||||
/* Version 3.22.0 and later */
|
||||
#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange
|
||||
#define sqlite3_value_nochange sqlite3_api->value_nochange
|
||||
#define sqlite3_vtab_collation sqlite3_api->vtab_collation
|
||||
/* Version 3.24.0 and later */
|
||||
#define sqlite3_keyword_count sqlite3_api->keyword_count
|
||||
#define sqlite3_keyword_name sqlite3_api->keyword_name
|
||||
#define sqlite3_keyword_check sqlite3_api->keyword_check
|
||||
#define sqlite3_str_new sqlite3_api->str_new
|
||||
#define sqlite3_str_finish sqlite3_api->str_finish
|
||||
#define sqlite3_str_appendf sqlite3_api->str_appendf
|
||||
#define sqlite3_str_vappendf sqlite3_api->str_vappendf
|
||||
#define sqlite3_str_append sqlite3_api->str_append
|
||||
#define sqlite3_str_appendall sqlite3_api->str_appendall
|
||||
#define sqlite3_str_appendchar sqlite3_api->str_appendchar
|
||||
#define sqlite3_str_reset sqlite3_api->str_reset
|
||||
#define sqlite3_str_errcode sqlite3_api->str_errcode
|
||||
#define sqlite3_str_length sqlite3_api->str_length
|
||||
#define sqlite3_str_value sqlite3_api->str_value
|
||||
/* Version 3.25.0 and later */
|
||||
#define sqlite3_create_window_function sqlite3_api->create_window_function
|
||||
/* Version 3.26.0 and later */
|
||||
#define sqlite3_normalized_sql sqlite3_api->normalized_sql
|
||||
/* Version 3.28.0 and later */
|
||||
#define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain
|
||||
#define sqlite3_value_frombind sqlite3_api->value_frombind
|
||||
/* Version 3.30.0 and later */
|
||||
#define sqlite3_drop_modules sqlite3_api->drop_modules
|
||||
/* Version 3.31.0 and later */
|
||||
#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64
|
||||
#define sqlite3_uri_key sqlite3_api->uri_key
|
||||
#define sqlite3_filename_database sqlite3_api->filename_database
|
||||
#define sqlite3_filename_journal sqlite3_api->filename_journal
|
||||
#define sqlite3_filename_wal sqlite3_api->filename_wal
|
||||
/* Version 3.32.0 and later */
|
||||
#define sqlite3_create_filename sqlite3_api->create_filename
|
||||
#define sqlite3_free_filename sqlite3_api->free_filename
|
||||
#define sqlite3_database_file_object sqlite3_api->database_file_object
|
||||
/* Version 3.34.0 and later */
|
||||
#define sqlite3_txn_state sqlite3_api->txn_state
|
||||
/* Version 3.36.1 and later */
|
||||
#define sqlite3_changes64 sqlite3_api->changes64
|
||||
#define sqlite3_total_changes64 sqlite3_api->total_changes64
|
||||
/* Version 3.37.0 and later */
|
||||
#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages
|
||||
/* Version 3.38.0 and later */
|
||||
#define sqlite3_error_offset sqlite3_api->error_offset
|
||||
#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value
|
||||
#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct
|
||||
#define sqlite3_vtab_in sqlite3_api->vtab_in
|
||||
#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first
|
||||
#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next
|
||||
/* Version 3.39.0 and later */
|
||||
#ifndef SQLITE_OMIT_DESERIALIZE
|
||||
#define sqlite3_deserialize sqlite3_api->deserialize
|
||||
#define sqlite3_serialize sqlite3_api->serialize
|
||||
#endif
|
||||
#define sqlite3_db_name sqlite3_api->db_name
|
||||
/* Version 3.40.0 and later */
|
||||
#define sqlite3_value_encoding sqlite3_api->value_encoding
|
||||
/* Version 3.41.0 and later */
|
||||
#define sqlite3_is_interrupted sqlite3_api->is_interrupted
|
||||
/* Version 3.43.0 and later */
|
||||
#define sqlite3_stmt_explain sqlite3_api->stmt_explain
|
||||
/* Version 3.44.0 and later */
|
||||
#define sqlite3_get_clientdata sqlite3_api->get_clientdata
|
||||
#define sqlite3_set_clientdata sqlite3_api->set_clientdata
|
||||
/* Version 3.50.0 and later */
|
||||
#define sqlite3_setlk_timeout sqlite3_api->setlk_timeout
|
||||
/* Version 3.51.0 and later */
|
||||
#define sqlite3_set_errmsg sqlite3_api->set_errmsg
|
||||
#define sqlite3_db_status64 sqlite3_api->db_status64
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
/* This case when the file really is being compiled as a loadable
|
||||
** extension */
|
||||
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
|
||||
# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
|
||||
# define SQLITE_EXTENSION_INIT3 \
|
||||
extern const sqlite3_api_routines *sqlite3_api;
|
||||
#else
|
||||
/* This case when the file is being statically linked into the
|
||||
** application */
|
||||
# define SQLITE_EXTENSION_INIT1 /*no-op*/
|
||||
# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
|
||||
# define SQLITE_EXTENSION_INIT3 /*no-op*/
|
||||
#endif
|
||||
|
||||
#endif /* SQLITE3EXT_H */
|
||||
28
phoenix/deps/exqlite/checksum.exs
Normal file
28
phoenix/deps/exqlite/checksum.exs
Normal file
@@ -0,0 +1,28 @@
|
||||
%{
|
||||
"exqlite-nif-2.16-aarch64-apple-darwin-0.36.0.tar.gz" => "sha256:c1032fc21142b399dff1d04dc982f5df28903ff0a2a95f29b70ef9191e048bb2",
|
||||
"exqlite-nif-2.16-aarch64-linux-gnu-0.36.0.tar.gz" => "sha256:6552f9cc187a916a01ea631a8265cad2c0ad942a7493033f80874aae4a3bec26",
|
||||
"exqlite-nif-2.16-aarch64-linux-musl-0.36.0.tar.gz" => "sha256:3b2868ae094306b8bed5a5b9de194358eb99bb1dd537498fae2f26fdc55c8bc4",
|
||||
"exqlite-nif-2.16-armv7l-linux-gnueabihf-0.36.0.tar.gz" => "sha256:425bc8e473ac4916b791d4cb463c8c20822c74a7801e5eaac1b81ac869e546ee",
|
||||
"exqlite-nif-2.16-i686-linux-gnu-0.36.0.tar.gz" => "sha256:b142008ab0bc70a52182ed1df55c1fd24bd7052367bd4fc155c1b39f32849b8f",
|
||||
"exqlite-nif-2.16-powerpc64le-linux-gnu-0.36.0.tar.gz" => "sha256:055c2a7831c8fdafe675dd01a4ff4703c326cdef19a1d76a5e1afc1a54978868",
|
||||
"exqlite-nif-2.16-riscv64-linux-gnu-0.36.0.tar.gz" => "sha256:10ed8ab8684c32930a9c9f526940182d969a58eb992f3a9e17edde8848c00fda",
|
||||
"exqlite-nif-2.16-riscv64-linux-musl-0.36.0.tar.gz" => "sha256:7e7d2894792c32936a1eb4d6c5ea970cf3765e92d9f0648fae917c729dcda438",
|
||||
"exqlite-nif-2.16-s390x-linux-gnu-0.36.0.tar.gz" => "sha256:e81d7a0a2d157148dc38451ffc98fa17442eca0af6d4f473221f246fa032f5d9",
|
||||
"exqlite-nif-2.16-x86_64-apple-darwin-0.36.0.tar.gz" => "sha256:abd9aeeccfd2bdcd775e4590ef4ae375fd347f1c7d0ab0f24bcf85498a59d1ca",
|
||||
"exqlite-nif-2.16-x86_64-linux-gnu-0.36.0.tar.gz" => "sha256:b609be28ddc62825441ba2e094f00d298a882a503b1a865fa74506fdf0dcb113",
|
||||
"exqlite-nif-2.16-x86_64-linux-musl-0.36.0.tar.gz" => "sha256:0dface2bb37234f12767bef0d57975c3818beeba573c786fc8e819eafb851135",
|
||||
"exqlite-nif-2.16-x86_64-windows-msvc-0.36.0.tar.gz" => "sha256:dec20a05617b808673b3266399eb44e0bf21006721c5de3f94d75d4247e7bd0b",
|
||||
"exqlite-nif-2.17-aarch64-apple-darwin-0.36.0.tar.gz" => "sha256:1779b848424c0bba893406a232dfba01caaa661c6ab79b83f4ff6f875b551299",
|
||||
"exqlite-nif-2.17-aarch64-linux-gnu-0.36.0.tar.gz" => "sha256:42063fc2f2e63ec1cc319e894b4425130dda48e8ddc39ef47877ce657afe9e56",
|
||||
"exqlite-nif-2.17-aarch64-linux-musl-0.36.0.tar.gz" => "sha256:21bc2d753b3c85bb91a57bcab89b3ad18c88e24392ee6e6b681d3178b71e339c",
|
||||
"exqlite-nif-2.17-armv7l-linux-gnueabihf-0.36.0.tar.gz" => "sha256:3c2941464f848c2e49eecd2cde7c30d03632117b7847902725fbe2dd2999eb45",
|
||||
"exqlite-nif-2.17-i686-linux-gnu-0.36.0.tar.gz" => "sha256:33cb0e4c86d9e3c679ceed54141aa088bb4fe1e628155b282b2ad0201b66c0fa",
|
||||
"exqlite-nif-2.17-powerpc64le-linux-gnu-0.36.0.tar.gz" => "sha256:67f48217a041d9f279f372ae16412543ea24f8c92c5749c40b66c16835934055",
|
||||
"exqlite-nif-2.17-riscv64-linux-gnu-0.36.0.tar.gz" => "sha256:62cde955d57bc1fd87797537d56147658ed7e3a62a1875ef39a4a7a8bad4ab60",
|
||||
"exqlite-nif-2.17-riscv64-linux-musl-0.36.0.tar.gz" => "sha256:7d6aa20ef6c872b7995d125fb426f0189940049253079fce52f4ff7dbbeb4f4a",
|
||||
"exqlite-nif-2.17-s390x-linux-gnu-0.36.0.tar.gz" => "sha256:77a357b94fd876e0288daea817e3bbec2516d307b6c6cbaa2224ecdc670f5f5f",
|
||||
"exqlite-nif-2.17-x86_64-apple-darwin-0.36.0.tar.gz" => "sha256:bb2df40b43313bf969c7bd2a903971fbe6d200916506e6bf13a2d8f5ef17b6f2",
|
||||
"exqlite-nif-2.17-x86_64-linux-gnu-0.36.0.tar.gz" => "sha256:1c8402cbc1232f00fee08bb76a4dd0e75221a995accd7835a34bbda080c0d2df",
|
||||
"exqlite-nif-2.17-x86_64-linux-musl-0.36.0.tar.gz" => "sha256:60ceb146f5023345e0aeadbc7aa59a2c5c601b421c4b041f6d05c7a436931cea",
|
||||
"exqlite-nif-2.17-x86_64-windows-msvc-0.36.0.tar.gz" => "sha256:3b46bc0f25ee81aeae3932a7c2b569a16a0a501db7146ec5bef7bf04d313d47d",
|
||||
}
|
||||
43
phoenix/deps/exqlite/hex_metadata.config
Normal file
43
phoenix/deps/exqlite/hex_metadata.config
Normal file
@@ -0,0 +1,43 @@
|
||||
{<<"links">>,
|
||||
[{<<"Changelog">>,
|
||||
<<"https://github.com/elixir-sqlite/exqlite/blob/main/CHANGELOG.md">>},
|
||||
{<<"GitHub">>,<<"https://github.com/elixir-sqlite/exqlite">>}]}.
|
||||
{<<"name">>,<<"exqlite">>}.
|
||||
{<<"version">>,<<"0.36.0">>}.
|
||||
{<<"description">>,<<"An Elixir SQLite3 library">>}.
|
||||
{<<"elixir">>,<<"~> 1.14">>}.
|
||||
{<<"app">>,<<"exqlite">>}.
|
||||
{<<"files">>,
|
||||
[<<"lib">>,<<"lib/exqlite.ex">>,<<"lib/exqlite">>,<<"lib/exqlite/error.ex">>,
|
||||
<<"lib/exqlite/flags.ex">>,<<"lib/exqlite/pragma.ex">>,
|
||||
<<"lib/exqlite/query.ex">>,<<"lib/exqlite/result.ex">>,
|
||||
<<"lib/exqlite/stream.ex">>,<<"lib/exqlite/basic.ex">>,
|
||||
<<"lib/exqlite/type_extension.ex">>,<<"lib/exqlite/connection.ex">>,
|
||||
<<"lib/exqlite/sqlite3.ex">>,<<"lib/exqlite/sqlite3_nif.ex">>,
|
||||
<<".formatter.exs">>,<<"mix.exs">>,<<"README.md">>,<<"LICENSE">>,
|
||||
<<".clang-format">>,<<"c_src">>,<<"c_src/sqlite3ext.h">>,
|
||||
<<"c_src/sqlite3.c">>,<<"c_src/sqlite3.h">>,<<"c_src/sqlite3_nif.c">>,
|
||||
<<"Makefile">>,<<"Makefile.win">>,<<"checksum.exs">>]}.
|
||||
{<<"licenses">>,[<<"MIT">>]}.
|
||||
{<<"requirements">>,
|
||||
[[{<<"name">>,<<"db_connection">>},
|
||||
{<<"app">>,<<"db_connection">>},
|
||||
{<<"optional">>,false},
|
||||
{<<"requirement">>,<<"~> 2.1">>},
|
||||
{<<"repository">>,<<"hexpm">>}],
|
||||
[{<<"name">>,<<"elixir_make">>},
|
||||
{<<"app">>,<<"elixir_make">>},
|
||||
{<<"optional">>,false},
|
||||
{<<"requirement">>,<<"~> 0.8">>},
|
||||
{<<"repository">>,<<"hexpm">>}],
|
||||
[{<<"name">>,<<"cc_precompiler">>},
|
||||
{<<"app">>,<<"cc_precompiler">>},
|
||||
{<<"optional">>,false},
|
||||
{<<"requirement">>,<<"~> 0.1">>},
|
||||
{<<"repository">>,<<"hexpm">>}],
|
||||
[{<<"name">>,<<"table">>},
|
||||
{<<"app">>,<<"table">>},
|
||||
{<<"optional">>,true},
|
||||
{<<"requirement">>,<<"~> 0.1.0">>},
|
||||
{<<"repository">>,<<"hexpm">>}]]}.
|
||||
{<<"build_tools">>,[<<"mix">>,<<"make">>]}.
|
||||
104
phoenix/deps/exqlite/lib/exqlite.ex
Normal file
104
phoenix/deps/exqlite/lib/exqlite.ex
Normal file
@@ -0,0 +1,104 @@
|
||||
defmodule Exqlite do
|
||||
@moduledoc """
|
||||
SQLite3 driver for Elixir.
|
||||
"""
|
||||
|
||||
alias Exqlite.Connection
|
||||
alias Exqlite.Error
|
||||
alias Exqlite.Query
|
||||
alias Exqlite.Result
|
||||
|
||||
@doc "See `Exqlite.Connection.connect/1`"
|
||||
@spec start_link([Connection.connection_opt()]) :: {:ok, pid()} | {:error, Error.t()}
|
||||
def start_link(opts) do
|
||||
DBConnection.start_link(Connection, opts)
|
||||
end
|
||||
|
||||
@spec query(DBConnection.conn(), iodata(), list(), list()) ::
|
||||
{:ok, Result.t()} | {:error, Exception.t()}
|
||||
def query(conn, statement, params \\ [], opts \\ []) do
|
||||
query = %Query{name: "", statement: IO.iodata_to_binary(statement)}
|
||||
|
||||
case DBConnection.prepare_execute(conn, query, params, opts) do
|
||||
{:ok, _query, result} ->
|
||||
{:ok, result}
|
||||
|
||||
otherwise ->
|
||||
otherwise
|
||||
end
|
||||
end
|
||||
|
||||
@spec query!(DBConnection.conn(), iodata(), list(), list()) :: Result.t()
|
||||
def query!(conn, statement, params \\ [], opts \\ []) do
|
||||
case query(conn, statement, params, opts) do
|
||||
{:ok, result} -> result
|
||||
{:error, err} -> raise err
|
||||
end
|
||||
end
|
||||
|
||||
@spec prepare(DBConnection.conn(), iodata(), list()) ::
|
||||
{:ok, Query.t()} | {:error, Exception.t()}
|
||||
def prepare(conn, name, statement, opts \\ []) do
|
||||
query = %Query{name: name, statement: statement}
|
||||
DBConnection.prepare(conn, query, opts)
|
||||
end
|
||||
|
||||
@spec prepare!(DBConnection.conn(), iodata(), iodata(), list()) :: Query.t()
|
||||
def prepare!(conn, name, statement, opts \\ []) do
|
||||
query = %Query{name: name, statement: statement}
|
||||
DBConnection.prepare!(conn, query, opts)
|
||||
end
|
||||
|
||||
@spec prepare_execute(DBConnection.conn(), iodata(), iodata(), list(), list()) ::
|
||||
{:ok, Query.t(), Result.t()} | {:error, Error.t()}
|
||||
def prepare_execute(conn, name, statement, params, opts \\ []) do
|
||||
query = %Query{name: name, statement: statement}
|
||||
DBConnection.prepare_execute(conn, query, params, opts)
|
||||
end
|
||||
|
||||
@spec prepare_execute!(DBConnection.conn(), iodata(), iodata(), list(), list()) ::
|
||||
{Query.t(), Result.t()}
|
||||
def prepare_execute!(conn, name, statement, params, opts \\ []) do
|
||||
query = %Query{name: name, statement: statement}
|
||||
DBConnection.prepare_execute!(conn, query, params, opts)
|
||||
end
|
||||
|
||||
@spec execute(DBConnection.conn(), Query.t(), list(), list()) ::
|
||||
{:ok, Result.t()} | {:error, Error.t()}
|
||||
def execute(conn, query, params, opts \\ []) do
|
||||
DBConnection.execute(conn, query, params, opts)
|
||||
end
|
||||
|
||||
@spec execute!(DBConnection.conn(), Query.t(), list(), list()) :: Result.t()
|
||||
def execute!(conn, query, params, opts \\ []) do
|
||||
DBConnection.execute!(conn, query, params, opts)
|
||||
end
|
||||
|
||||
@spec close(DBConnection.conn(), Query.t(), list()) :: :ok | {:error, Exception.t()}
|
||||
def close(conn, query, opts \\ []) do
|
||||
with {:ok, _} <- DBConnection.close(conn, query, opts) do
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
@spec close!(DBConnection.conn(), Query.t(), list()) :: :ok
|
||||
def close!(conn, query, opts \\ []) do
|
||||
DBConnection.close!(conn, query, opts)
|
||||
:ok
|
||||
end
|
||||
|
||||
@spec transaction(DBConnection.conn(), (DBConnection.t() -> result), list()) ::
|
||||
{:ok, result} | {:error, any}
|
||||
when result: var
|
||||
def transaction(conn, fun, opts \\ []) do
|
||||
DBConnection.transaction(conn, fun, opts)
|
||||
end
|
||||
|
||||
@spec rollback(DBConnection.t(), term()) :: no_return()
|
||||
def rollback(conn, reason), do: DBConnection.rollback(conn, reason)
|
||||
|
||||
@spec child_spec([Connection.connection_opt()]) :: :supervisor.child_spec()
|
||||
def child_spec(opts) do
|
||||
DBConnection.child_spec(Connection, opts)
|
||||
end
|
||||
end
|
||||
48
phoenix/deps/exqlite/lib/exqlite/basic.ex
Normal file
48
phoenix/deps/exqlite/lib/exqlite/basic.ex
Normal file
@@ -0,0 +1,48 @@
|
||||
defmodule Exqlite.Basic do
|
||||
@moduledoc """
|
||||
A very basic API for simple use cases.
|
||||
"""
|
||||
|
||||
alias Exqlite.Connection
|
||||
alias Exqlite.Query
|
||||
alias Exqlite.Sqlite3
|
||||
alias Exqlite.Error
|
||||
alias Exqlite.Result
|
||||
|
||||
def open(path) do
|
||||
Connection.connect(database: path)
|
||||
end
|
||||
|
||||
def close(%Connection{} = conn) do
|
||||
case Sqlite3.close(conn.db) do
|
||||
:ok -> :ok
|
||||
{:error, reason} -> {:error, %Error{message: to_string(reason)}}
|
||||
end
|
||||
end
|
||||
|
||||
def exec(%Connection{} = conn, stmt, args \\ []) do
|
||||
%Query{statement: stmt} |> Connection.handle_execute(args, [], conn)
|
||||
end
|
||||
|
||||
def rows(exec_result) do
|
||||
case exec_result do
|
||||
{:ok, %Query{}, %Result{rows: rows, columns: columns}, %Connection{}} ->
|
||||
{:ok, rows, columns}
|
||||
|
||||
{:error, %Error{message: message}, %Connection{}} ->
|
||||
{:error, to_string(message)}
|
||||
end
|
||||
end
|
||||
|
||||
def load_extension(conn, path) do
|
||||
exec(conn, "select load_extension(?)", [path])
|
||||
end
|
||||
|
||||
def enable_load_extension(conn) do
|
||||
Sqlite3.enable_load_extension(conn.db, true)
|
||||
end
|
||||
|
||||
def disable_load_extension(conn) do
|
||||
Sqlite3.enable_load_extension(conn.db, false)
|
||||
end
|
||||
end
|
||||
741
phoenix/deps/exqlite/lib/exqlite/connection.ex
Normal file
741
phoenix/deps/exqlite/lib/exqlite/connection.ex
Normal file
@@ -0,0 +1,741 @@
|
||||
defmodule Exqlite.Connection do
|
||||
@moduledoc """
|
||||
This module implements connection details as defined in DBProtocol.
|
||||
|
||||
## Attributes
|
||||
|
||||
- `db` - The sqlite3 database reference.
|
||||
- `path` - The path that was used to open.
|
||||
- `transaction_status` - The status of the connection. Can be `:idle` or `:transaction`.
|
||||
|
||||
## Unknowns
|
||||
|
||||
- How are pooled connections going to work? Since sqlite3 doesn't allow for
|
||||
simultaneous access. We would need to check if the write ahead log is
|
||||
enabled on the database. We can't assume and set the WAL pragma because the
|
||||
database may be stored on a network volume which would cause potential
|
||||
issues.
|
||||
|
||||
Notes:
|
||||
- we try to closely follow structure and naming convention of myxql.
|
||||
- sqlite thrives when there are many small conventions, so we may not implement
|
||||
some strategies employed by other adapters. See https://sqlite.org/np1queryprob.html
|
||||
"""
|
||||
|
||||
use DBConnection
|
||||
alias Exqlite.Error
|
||||
alias Exqlite.Pragma
|
||||
alias Exqlite.Query
|
||||
alias Exqlite.Result
|
||||
alias Exqlite.Sqlite3
|
||||
require Logger
|
||||
|
||||
defstruct [
|
||||
:db,
|
||||
:default_transaction_mode,
|
||||
:directory,
|
||||
:path,
|
||||
:transaction_status,
|
||||
:status,
|
||||
:chunk_size,
|
||||
:before_disconnect
|
||||
]
|
||||
|
||||
@type t() :: %__MODULE__{
|
||||
db: Sqlite3.db(),
|
||||
directory: String.t() | nil,
|
||||
path: String.t(),
|
||||
transaction_status: :idle | :transaction,
|
||||
status: :idle | :busy,
|
||||
chunk_size: integer(),
|
||||
before_disconnect: (t -> any) | {module, atom, [any]} | nil
|
||||
}
|
||||
|
||||
@type journal_mode() :: :delete | :truncate | :persist | :memory | :wal | :off
|
||||
@type temp_store() :: :default | :file | :memory
|
||||
@type synchronous() :: :extra | :full | :normal | :off
|
||||
@type auto_vacuum() :: :none | :full | :incremental
|
||||
@type locking_mode() :: :normal | :exclusive
|
||||
@type transaction_mode() :: :deferred | :immediate | :exclusive
|
||||
|
||||
@type connection_opt() ::
|
||||
{:database, String.t()}
|
||||
| {:default_transaction_mode, transaction_mode()}
|
||||
| {:mode, Sqlite3.open_opt()}
|
||||
| {:journal_mode, journal_mode()}
|
||||
| {:temp_store, temp_store()}
|
||||
| {:synchronous, synchronous()}
|
||||
| {:foreign_keys, :on | :off}
|
||||
| {:cache_size, integer()}
|
||||
| {:cache_spill, :on | :off}
|
||||
| {:case_sensitive_like, boolean()}
|
||||
| {:auto_vacuum, auto_vacuum()}
|
||||
| {:locking_mode, locking_mode()}
|
||||
| {:secure_delete, :on | :off}
|
||||
| {:wal_auto_check_point, integer()}
|
||||
| {:busy_timeout, integer()}
|
||||
| {:chunk_size, integer()}
|
||||
| {:journal_size_limit, integer()}
|
||||
| {:soft_heap_limit, integer()}
|
||||
| {:hard_heap_limit, integer()}
|
||||
| {:key, String.t()}
|
||||
| {:custom_pragmas, [{keyword(), integer() | boolean() | String.t()}]}
|
||||
| {:before_disconnect, (t -> any) | {module, atom, [any]} | nil}
|
||||
|
||||
@impl true
|
||||
@doc """
|
||||
Initializes the Ecto Exqlite adapter.
|
||||
|
||||
For connection configurations we use the defaults that come with SQLite3, but
|
||||
we recommend which options to choose. We do not default to the recommended
|
||||
because we don't know what your environment is like.
|
||||
|
||||
Allowed options:
|
||||
|
||||
* `:database` - The path to the database. In memory is allowed. You can use
|
||||
`:memory` or `":memory:"` to designate that.
|
||||
* `:default_transaction_mode` - one of `deferred` (default), `immediate`,
|
||||
or `exclusive`. If a mode is not specified in a call to `Repo.transaction/2`,
|
||||
this will be the default transaction mode.
|
||||
* `:mode` - use `:readwrite` to open the database for reading and writing
|
||||
, `:readonly` to open it in read-only mode or `[:readonly | :readwrite, :nomutex]`
|
||||
to open it with no mutex mode. `:readwrite` will also create
|
||||
the database if it doesn't already exist. Defaults to `:readwrite`.
|
||||
Note: [:readwrite, :nomutex] is not recommended.
|
||||
* `:journal_mode` - Sets the journal mode for the sqlite connection. Can be
|
||||
one of the following `:delete`, `:truncate`, `:persist`, `:memory`,
|
||||
`:wal`, or `:off`. Defaults to `:delete`. It is recommended that you use
|
||||
`:wal` due to support for concurrent reads. Note: `:wal` does not mean
|
||||
concurrent writes.
|
||||
* `:temp_store` - Sets the storage used for temporary tables. Default is
|
||||
`:default`. Allowed values are `:default`, `:file`, `:memory`. It is
|
||||
recommended that you use `:memory` for storage.
|
||||
* `:synchronous` - Can be `:extra`, `:full`, `:normal`, or `:off`. Defaults
|
||||
to `:normal`.
|
||||
* `:foreign_keys` - Sets if foreign key checks should be enforced or not.
|
||||
Can be `:on` or `:off`. Default is `:on`.
|
||||
* `:cache_size` - Sets the cache size to be used for the connection. This is
|
||||
an odd setting as a positive value is the number of pages in memory to use
|
||||
and a negative value is the size in kilobytes to use. Default is `-2000`.
|
||||
It is recommended that you use `-64000`.
|
||||
* `:cache_spill` - The cache_spill pragma enables or disables the ability of
|
||||
the pager to spill dirty cache pages to the database file in the middle of
|
||||
a transaction. By default it is `:on`, and for most applications, it
|
||||
should remain so.
|
||||
* `:case_sensitive_like`
|
||||
* `:auto_vacuum` - Defaults to `:none`. Can be `:none`, `:full` or
|
||||
`:incremental`. Depending on the database size, `:incremental` may be
|
||||
beneficial.
|
||||
* `:locking_mode` - Defaults to `:normal`. Allowed values are `:normal` or
|
||||
`:exclusive`. See [sqlite documentation][1] for more information.
|
||||
* `:secure_delete` - Defaults to `:off`. If enabled, it will cause SQLite3
|
||||
to overwrite records that were deleted with zeros.
|
||||
* `:wal_auto_check_point` - Sets the write-ahead log auto-checkpoint
|
||||
interval. Default is `1000`. Setting the auto-checkpoint size to zero or a
|
||||
negative value turns auto-checkpointing off.
|
||||
* `:busy_timeout` - Sets the busy timeout in milliseconds for a connection.
|
||||
Default is `2000`.
|
||||
* `:chunk_size` - The chunk size for bulk fetching. Defaults to `50`.
|
||||
* `:key` - Optional key to set during database initialization. This PRAGMA
|
||||
is often used to set up database level encryption.
|
||||
* `:journal_size_limit` - The size limit in bytes of the journal.
|
||||
* `:soft_heap_limit` - The size limit in bytes for the heap limit.
|
||||
* `:hard_heap_limit` - The size limit in bytes for the heap.
|
||||
* `:custom_pragmas` - A list of custom pragmas to set on the connection, for example to configure extensions.
|
||||
* `:serialized` - A SQLite database which was previously serialized, to load into the database after connection.
|
||||
* `:load_extensions` - A list of paths identifying extensions to load. Defaults to `[]`.
|
||||
The provided list will be merged with the global extensions list, set on `:exqlite, :load_extensions`.
|
||||
Be aware that the path should handle pointing to a library compiled for the current architecture.
|
||||
Example configuration:
|
||||
|
||||
```
|
||||
arch_dir =
|
||||
System.cmd("uname", ["-sm"])
|
||||
|> elem(0)
|
||||
|> String.trim()
|
||||
|> String.replace(" ", "-")
|
||||
|> String.downcase() # => "darwin-arm64"
|
||||
|
||||
config :myapp, arch_dir: arch_dir
|
||||
|
||||
# global
|
||||
config :exqlite, load_extensions: [ "./priv/sqlite/\#{arch_dir}/rotate" ]
|
||||
|
||||
# per connection in a Phoenix app
|
||||
config :myapp, Myapp.Repo,
|
||||
database: "path/to/db",
|
||||
load_extensions: [
|
||||
"./priv/sqlite/\#{arch_dir}/vector0",
|
||||
"./priv/sqlite/\#{arch_dir}/vss0"
|
||||
]
|
||||
```
|
||||
* `:before_disconnect` - A function to run before disconnect, either a
|
||||
2-arity fun or `{module, function, args}` with the close reason and
|
||||
`t:Exqlite.Connection.t/0` prepended to `args` or `nil` (default: `nil`)
|
||||
|
||||
For more information about the options above, see [sqlite documentation][1]
|
||||
|
||||
[1]: https://www.sqlite.org/pragma.html
|
||||
"""
|
||||
@spec connect([connection_opt()]) :: {:ok, t()} | {:error, Exception.t()}
|
||||
def connect(options) do
|
||||
database = Keyword.get(options, :database)
|
||||
|
||||
options =
|
||||
Keyword.put_new(
|
||||
options,
|
||||
:chunk_size,
|
||||
Application.get_env(:exqlite, :default_chunk_size, 50)
|
||||
)
|
||||
|
||||
case database do
|
||||
nil ->
|
||||
{:error,
|
||||
%Error{
|
||||
message: """
|
||||
You must provide a :database to the database. \
|
||||
Example: connect(database: "./") or connect(database: :memory)\
|
||||
"""
|
||||
}}
|
||||
|
||||
:memory ->
|
||||
do_connect(":memory:", options)
|
||||
|
||||
_ ->
|
||||
do_connect(database, options)
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def disconnect(err, %__MODULE__{db: db} = state) do
|
||||
if state.before_disconnect != nil do
|
||||
apply(state.before_disconnect, [err, state])
|
||||
end
|
||||
|
||||
case Sqlite3.close(db) do
|
||||
:ok -> :ok
|
||||
{:error, reason} -> {:error, %Error{message: to_string(reason)}}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def checkout(%__MODULE__{status: :idle} = state) do
|
||||
{:ok, %{state | status: :busy}}
|
||||
end
|
||||
|
||||
def checkout(%__MODULE__{status: :busy} = state) do
|
||||
{:disconnect, %Error{message: "Database is busy"}, state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def ping(state), do: {:ok, state}
|
||||
|
||||
##
|
||||
## Handlers
|
||||
##
|
||||
|
||||
@impl true
|
||||
def handle_prepare(%Query{} = query, options, state) do
|
||||
with {:ok, query} <- prepare(query, options, state) do
|
||||
{:ok, query, state}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_execute(%Query{} = query, params, options, state) do
|
||||
with {:ok, query} <- prepare(query, options, state) do
|
||||
execute(:execute, query, params, state)
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Begin a transaction.
|
||||
|
||||
For full info refer to sqlite docs: https://sqlite.org/lang_transaction.html
|
||||
|
||||
Note: default transaction mode is DEFERRED.
|
||||
"""
|
||||
@impl true
|
||||
def handle_begin(options, %{transaction_status: transaction_status} = state) do
|
||||
# This doesn't handle more than 2 levels of transactions.
|
||||
#
|
||||
# One possible solution would be to just track the number of open
|
||||
# transactions and use that for driving the transaction status being idle or
|
||||
# in a transaction.
|
||||
#
|
||||
# I do not know why the other official adapters do not track this and just
|
||||
# append level on the savepoint. Instead the rollbacks would just completely
|
||||
# revert the issues when it may be desirable to fix something while in the
|
||||
# transaction and then commit.
|
||||
|
||||
mode = Keyword.get(options, :mode, state.default_transaction_mode)
|
||||
|
||||
case mode do
|
||||
:deferred when transaction_status == :idle ->
|
||||
handle_transaction(:begin, "BEGIN TRANSACTION", state)
|
||||
|
||||
:transaction when transaction_status == :idle ->
|
||||
handle_transaction(:begin, "BEGIN TRANSACTION", state)
|
||||
|
||||
:immediate when transaction_status == :idle ->
|
||||
handle_transaction(:begin, "BEGIN IMMEDIATE TRANSACTION", state)
|
||||
|
||||
:exclusive when transaction_status == :idle ->
|
||||
handle_transaction(:begin, "BEGIN EXCLUSIVE TRANSACTION", state)
|
||||
|
||||
mode
|
||||
when mode in [:deferred, :immediate, :exclusive, :savepoint] and
|
||||
transaction_status == :transaction ->
|
||||
handle_transaction(:begin, "SAVEPOINT exqlite_savepoint", state)
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_commit(options, %{transaction_status: transaction_status} = state) do
|
||||
case Keyword.get(options, :mode, :deferred) do
|
||||
:savepoint when transaction_status == :transaction ->
|
||||
handle_transaction(
|
||||
:commit_savepoint,
|
||||
"RELEASE SAVEPOINT exqlite_savepoint",
|
||||
state
|
||||
)
|
||||
|
||||
mode
|
||||
when mode in [:deferred, :immediate, :exclusive, :transaction] and
|
||||
transaction_status == :transaction ->
|
||||
handle_transaction(:commit, "COMMIT", state)
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_rollback(options, %{transaction_status: transaction_status} = state) do
|
||||
case Keyword.get(options, :mode, :deferred) do
|
||||
:savepoint when transaction_status == :transaction ->
|
||||
with {:ok, _result, state} <-
|
||||
handle_transaction(
|
||||
:rollback_savepoint,
|
||||
"ROLLBACK TO SAVEPOINT exqlite_savepoint",
|
||||
state
|
||||
) do
|
||||
handle_transaction(
|
||||
:rollback_savepoint,
|
||||
"RELEASE SAVEPOINT exqlite_savepoint",
|
||||
state
|
||||
)
|
||||
end
|
||||
|
||||
mode
|
||||
when mode in [:deferred, :immediate, :exclusive, :transaction] ->
|
||||
handle_transaction(:rollback, "ROLLBACK TRANSACTION", state)
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Close a query prepared by `handle_prepare/3` with the database. Return
|
||||
`{:ok, result, state}` on success and to continue,
|
||||
`{:error, exception, state}` to return an error and continue, or
|
||||
`{:disconnect, exception, state}` to return an error and disconnect.
|
||||
|
||||
This callback is called in the client process.
|
||||
"""
|
||||
@impl true
|
||||
def handle_close(query, _opts, state) do
|
||||
Sqlite3.release(state.db, query.ref)
|
||||
{:ok, nil, state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_declare(%Query{} = query, params, opts, state) do
|
||||
# We emulate cursor functionality by just using a prepared statement and
|
||||
# step through it. Thus we just return the query ref as the cursor.
|
||||
with {:ok, query} <- prepare_no_cache(query, opts, state),
|
||||
{:ok, query} <- bind_params(query, params, state) do
|
||||
{:ok, query, query.ref, state}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_deallocate(%Query{} = query, _cursor, _opts, state) do
|
||||
Sqlite3.release(state.db, query.ref)
|
||||
{:ok, nil, state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_fetch(%Query{statement: statement}, cursor, opts, state) do
|
||||
chunk_size = opts[:chunk_size] || opts[:max_rows] || state.chunk_size
|
||||
|
||||
case Sqlite3.multi_step(state.db, cursor, chunk_size) do
|
||||
{:done, rows} ->
|
||||
{:halt, %Result{rows: rows, command: :fetch, num_rows: length(rows)}, state}
|
||||
|
||||
{:rows, rows} ->
|
||||
{:cont, %Result{rows: rows, command: :fetch, num_rows: chunk_size}, state}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, %Error{message: to_string(reason), statement: statement}, state}
|
||||
|
||||
:busy ->
|
||||
{:error, %Error{message: "Database is busy", statement: statement}, state}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_status(_opts, state) do
|
||||
{state.transaction_status, state}
|
||||
end
|
||||
|
||||
### ----------------------------------
|
||||
# Internal functions and helpers
|
||||
### ----------------------------------
|
||||
|
||||
defp set_pragma(db, pragma_name, value) do
|
||||
Sqlite3.execute(db, "PRAGMA #{pragma_name} = #{value}")
|
||||
end
|
||||
|
||||
defp get_pragma(db, pragma_name) do
|
||||
{:ok, statement} = Sqlite3.prepare(db, "PRAGMA #{pragma_name}")
|
||||
|
||||
case Sqlite3.fetch_all(db, statement) do
|
||||
{:ok, [[value]]} -> {:ok, value}
|
||||
_ -> :error
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_set_pragma(db, pragma_name, value) do
|
||||
case get_pragma(db, pragma_name) do
|
||||
{:ok, current} ->
|
||||
if current == value do
|
||||
:ok
|
||||
else
|
||||
set_pragma(db, pragma_name, value)
|
||||
end
|
||||
|
||||
_ ->
|
||||
set_pragma(db, pragma_name, value)
|
||||
end
|
||||
end
|
||||
|
||||
defp set_key(db, options) do
|
||||
# we can't use maybe_set_pragma here since
|
||||
# the only thing that will work on an encrypted
|
||||
# database without error is setting the key.
|
||||
case Keyword.fetch(options, :key) do
|
||||
{:ok, key} -> set_pragma(db, "key", key)
|
||||
_ -> :ok
|
||||
end
|
||||
end
|
||||
|
||||
defp set_custom_pragmas(db, options) do
|
||||
# we can't use maybe_set_pragma because some pragmas
|
||||
# are required to be set before the database is e.g. decrypted.
|
||||
case Keyword.fetch(options, :custom_pragmas) do
|
||||
{:ok, list} -> do_set_custom_pragmas(db, list)
|
||||
_ -> :ok
|
||||
end
|
||||
end
|
||||
|
||||
defp do_set_custom_pragmas(db, list) do
|
||||
list
|
||||
|> Enum.reduce_while(:ok, fn {key, value}, :ok ->
|
||||
case set_pragma(db, key, value) do
|
||||
:ok -> {:cont, :ok}
|
||||
{:error, _reason} -> {:halt, :error}
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp set_pragma_if_present(_db, _pragma, nil), do: :ok
|
||||
defp set_pragma_if_present(db, pragma, value), do: set_pragma(db, pragma, value)
|
||||
|
||||
defp set_journal_size_limit(db, options) do
|
||||
set_pragma_if_present(
|
||||
db,
|
||||
"journal_size_limit",
|
||||
Keyword.get(options, :journal_size_limit)
|
||||
)
|
||||
end
|
||||
|
||||
defp set_soft_heap_limit(db, options) do
|
||||
set_pragma_if_present(db, "soft_heap_limit", Keyword.get(options, :soft_heap_limit))
|
||||
end
|
||||
|
||||
defp set_hard_heap_limit(db, options) do
|
||||
set_pragma_if_present(db, "hard_heap_limit", Keyword.get(options, :hard_heap_limit))
|
||||
end
|
||||
|
||||
defp set_journal_mode(db, options) do
|
||||
set_pragma_if_present(db, "journal_mode", Keyword.get(options, :journal_mode))
|
||||
end
|
||||
|
||||
defp set_temp_store(db, options) do
|
||||
set_pragma(db, "temp_store", Pragma.temp_store(options))
|
||||
end
|
||||
|
||||
defp set_synchronous(db, options) do
|
||||
set_pragma(db, "synchronous", Pragma.synchronous(options))
|
||||
end
|
||||
|
||||
defp set_foreign_keys(db, options) do
|
||||
set_pragma(db, "foreign_keys", Pragma.foreign_keys(options))
|
||||
end
|
||||
|
||||
defp set_cache_size(db, options) do
|
||||
maybe_set_pragma(db, "cache_size", Pragma.cache_size(options))
|
||||
end
|
||||
|
||||
defp set_cache_spill(db, options) do
|
||||
set_pragma(db, "cache_spill", Pragma.cache_spill(options))
|
||||
end
|
||||
|
||||
defp set_case_sensitive_like(db, options) do
|
||||
set_pragma(db, "case_sensitive_like", Pragma.case_sensitive_like(options))
|
||||
end
|
||||
|
||||
defp set_auto_vacuum(db, options) do
|
||||
set_pragma(db, "auto_vacuum", Pragma.auto_vacuum(options))
|
||||
end
|
||||
|
||||
defp set_locking_mode(db, options) do
|
||||
set_pragma(db, "locking_mode", Pragma.locking_mode(options))
|
||||
end
|
||||
|
||||
defp set_secure_delete(db, options) do
|
||||
set_pragma(db, "secure_delete", Pragma.secure_delete(options))
|
||||
end
|
||||
|
||||
defp set_wal_auto_check_point(db, options) do
|
||||
set_pragma(db, "wal_autocheckpoint", Pragma.wal_auto_check_point(options))
|
||||
end
|
||||
|
||||
defp set_busy_timeout(db, options) do
|
||||
set_pragma(db, "busy_timeout", Pragma.busy_timeout(options))
|
||||
end
|
||||
|
||||
defp deserialize(db, options) do
|
||||
case Keyword.get(options, :serialized, nil) do
|
||||
nil -> :ok
|
||||
serialized -> Sqlite3.deserialize(db, serialized)
|
||||
end
|
||||
end
|
||||
|
||||
defp load_extensions(db, options) do
|
||||
global_extensions = Application.get_env(:exqlite, :load_extensions, [])
|
||||
|
||||
extensions =
|
||||
Keyword.get(options, :load_extensions, [])
|
||||
|> Enum.concat(global_extensions)
|
||||
|> Enum.uniq()
|
||||
|
||||
do_load_extensions(db, extensions)
|
||||
end
|
||||
|
||||
defp do_load_extensions(_db, []), do: :ok
|
||||
|
||||
defp do_load_extensions(db, extensions) do
|
||||
Sqlite3.enable_load_extension(db, true)
|
||||
|
||||
Enum.each(extensions, fn extension ->
|
||||
Logger.debug(fn -> "Exqlite: loading extension `#{extension}`" end)
|
||||
Sqlite3.execute(db, "SELECT load_extension('#{extension}')")
|
||||
end)
|
||||
|
||||
Sqlite3.enable_load_extension(db, false)
|
||||
end
|
||||
|
||||
defp do_connect(database, options) do
|
||||
with {:ok, directory} <- resolve_directory(database),
|
||||
:ok <- mkdir_p(directory),
|
||||
{:ok, db} <- Sqlite3.open(database, options),
|
||||
:ok <- set_key(db, options),
|
||||
:ok <- set_custom_pragmas(db, options),
|
||||
:ok <- set_journal_mode(db, options),
|
||||
:ok <- set_temp_store(db, options),
|
||||
:ok <- set_synchronous(db, options),
|
||||
:ok <- set_foreign_keys(db, options),
|
||||
:ok <- set_cache_size(db, options),
|
||||
:ok <- set_cache_spill(db, options),
|
||||
:ok <- set_auto_vacuum(db, options),
|
||||
:ok <- set_locking_mode(db, options),
|
||||
:ok <- set_secure_delete(db, options),
|
||||
:ok <- set_wal_auto_check_point(db, options),
|
||||
:ok <- set_case_sensitive_like(db, options),
|
||||
:ok <- set_busy_timeout(db, options),
|
||||
:ok <- set_journal_size_limit(db, options),
|
||||
:ok <- set_soft_heap_limit(db, options),
|
||||
:ok <- set_hard_heap_limit(db, options),
|
||||
:ok <- load_extensions(db, options),
|
||||
:ok <- deserialize(db, options) do
|
||||
state = %__MODULE__{
|
||||
db: db,
|
||||
default_transaction_mode:
|
||||
Keyword.get(options, :default_transaction_mode, :deferred),
|
||||
directory: directory,
|
||||
path: database,
|
||||
transaction_status: :idle,
|
||||
status: :idle,
|
||||
chunk_size: Keyword.get(options, :chunk_size),
|
||||
before_disconnect: Keyword.get(options, :before_disconnect, nil)
|
||||
}
|
||||
|
||||
{:ok, state}
|
||||
else
|
||||
{:error, reason} ->
|
||||
{:error, %Exqlite.Error{message: to_string(reason)}}
|
||||
end
|
||||
end
|
||||
|
||||
def maybe_put_command(query, options) do
|
||||
case Keyword.get(options, :command) do
|
||||
nil -> query
|
||||
command -> %{query | command: command}
|
||||
end
|
||||
end
|
||||
|
||||
# Attempt to retrieve the cached query, if it doesn't exist, we'll prepare one
|
||||
# and cache it for later.
|
||||
defp prepare(%Query{statement: statement} = query, options, state) do
|
||||
query = maybe_put_command(query, options)
|
||||
|
||||
with {:ok, ref} <- Sqlite3.prepare(state.db, IO.iodata_to_binary(statement)),
|
||||
query <- %{query | ref: ref} do
|
||||
{:ok, query}
|
||||
else
|
||||
{:error, reason} ->
|
||||
{:error, %Error{message: to_string(reason), statement: statement}, state}
|
||||
end
|
||||
end
|
||||
|
||||
# Prepare a query and do not cache it.
|
||||
defp prepare_no_cache(%Query{statement: statement} = query, options, state) do
|
||||
query = maybe_put_command(query, options)
|
||||
|
||||
case Sqlite3.prepare(state.db, statement) do
|
||||
{:ok, ref} ->
|
||||
{:ok, %{query | ref: ref}}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, %Error{message: to_string(reason), statement: statement}, state}
|
||||
end
|
||||
end
|
||||
|
||||
@spec maybe_changes(Sqlite3.db(), Query.t()) :: integer() | nil
|
||||
defp maybe_changes(db, %Query{command: command})
|
||||
when command in [:update, :insert, :delete] do
|
||||
case Sqlite3.changes(db) do
|
||||
{:ok, total} -> total
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_changes(_, _), do: nil
|
||||
|
||||
# when we have an empty list of columns, that signifies that
|
||||
# there was no possible return tuple (e.g., update statement without RETURNING)
|
||||
# and in that case, we return nil to signify no possible result.
|
||||
defp maybe_rows([], []), do: nil
|
||||
defp maybe_rows(rows, _cols), do: rows
|
||||
|
||||
defp execute(call, %Query{} = query, params, state) do
|
||||
with {:ok, query} <- bind_params(query, params, state),
|
||||
{:ok, columns} <- get_columns(query, state),
|
||||
{:ok, rows} <- get_rows(query, state),
|
||||
{:ok, transaction_status} <- Sqlite3.transaction_status(state.db),
|
||||
changes <- maybe_changes(state.db, query) do
|
||||
case query.command do
|
||||
command when command in [:delete, :insert, :update] ->
|
||||
{
|
||||
:ok,
|
||||
query,
|
||||
Result.new(
|
||||
command: call,
|
||||
num_rows: changes,
|
||||
rows: maybe_rows(rows, columns)
|
||||
),
|
||||
%{state | transaction_status: transaction_status}
|
||||
}
|
||||
|
||||
_ ->
|
||||
{
|
||||
:ok,
|
||||
query,
|
||||
Result.new(
|
||||
command: call,
|
||||
columns: columns,
|
||||
rows: rows,
|
||||
num_rows: Enum.count(rows)
|
||||
),
|
||||
%{state | transaction_status: transaction_status}
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp bind_params(%Query{ref: ref, statement: statement} = query, params, state)
|
||||
when ref != nil do
|
||||
try do
|
||||
Sqlite3.bind(ref, params)
|
||||
rescue
|
||||
e -> {:error, %Error{message: Exception.message(e), statement: statement}, state}
|
||||
else
|
||||
:ok -> {:ok, query}
|
||||
end
|
||||
end
|
||||
|
||||
defp get_columns(%Query{ref: ref, statement: statement}, state) do
|
||||
case Sqlite3.columns(state.db, ref) do
|
||||
{:ok, columns} ->
|
||||
{:ok, columns}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, %Error{message: to_string(reason), statement: statement}, state}
|
||||
end
|
||||
end
|
||||
|
||||
defp get_rows(%Query{ref: ref, statement: statement}, state) do
|
||||
case Sqlite3.fetch_all(state.db, ref, state.chunk_size) do
|
||||
{:ok, rows} ->
|
||||
{:ok, rows}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, %Error{message: to_string(reason), statement: statement}, state}
|
||||
end
|
||||
end
|
||||
|
||||
defp handle_transaction(call, statement, state) do
|
||||
with :ok <- Sqlite3.execute(state.db, statement),
|
||||
{:ok, transaction_status} <- Sqlite3.transaction_status(state.db) do
|
||||
result = %Result{
|
||||
command: call,
|
||||
rows: [],
|
||||
columns: [],
|
||||
num_rows: 0
|
||||
}
|
||||
|
||||
{:ok, result, %{state | transaction_status: transaction_status}}
|
||||
else
|
||||
{:error, reason} ->
|
||||
{:disconnect, %Error{message: to_string(reason), statement: statement}, state}
|
||||
end
|
||||
end
|
||||
|
||||
defp resolve_directory(":memory:"), do: {:ok, nil}
|
||||
|
||||
defp resolve_directory("file:" <> _ = uri) do
|
||||
case URI.parse(uri) do
|
||||
%{path: path} when is_binary(path) ->
|
||||
{:ok, Path.dirname(path)}
|
||||
|
||||
_ ->
|
||||
{:error, "No path in #{inspect(uri)}"}
|
||||
end
|
||||
end
|
||||
|
||||
defp resolve_directory(path), do: {:ok, Path.dirname(path)}
|
||||
|
||||
# SQLITE_OPEN_CREATE will create the DB file if not existing, but
|
||||
# will not create intermediary directories if they are missing.
|
||||
# So let's preemptively create the intermediate directories here
|
||||
# before trying to open the DB file.
|
||||
defp mkdir_p(nil), do: :ok
|
||||
defp mkdir_p(directory), do: File.mkdir_p(directory)
|
||||
end
|
||||
18
phoenix/deps/exqlite/lib/exqlite/error.ex
Normal file
18
phoenix/deps/exqlite/lib/exqlite/error.ex
Normal file
@@ -0,0 +1,18 @@
|
||||
defmodule Exqlite.Error do
|
||||
@moduledoc """
|
||||
The error emitted from SQLite or a general error with the library.
|
||||
"""
|
||||
|
||||
defexception [:message, :statement]
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
message: String.t(),
|
||||
statement: String.t()
|
||||
}
|
||||
|
||||
@impl true
|
||||
def message(%__MODULE__{message: message, statement: nil}), do: message
|
||||
|
||||
def message(%__MODULE__{message: message, statement: statement}),
|
||||
do: "#{message}\n#{statement}"
|
||||
end
|
||||
35
phoenix/deps/exqlite/lib/exqlite/flags.ex
Normal file
35
phoenix/deps/exqlite/lib/exqlite/flags.ex
Normal file
@@ -0,0 +1,35 @@
|
||||
defmodule Exqlite.Flags do
|
||||
@moduledoc false
|
||||
|
||||
import Bitwise
|
||||
|
||||
# https://www.sqlite.org/c3ref/c_open_autoproxy.html
|
||||
@file_open_flags [
|
||||
sqlite_open_readonly: 0x00000001,
|
||||
sqlite_open_readwrite: 0x00000002,
|
||||
sqlite_open_create: 0x00000004,
|
||||
sqlite_open_deleteonclos: 0x00000008,
|
||||
sqlite_open_exclusive: 0x00000010,
|
||||
sqlite_open_autoproxy: 0x00000020,
|
||||
sqlite_open_uri: 0x00000040,
|
||||
sqlite_open_memory: 0x00000080,
|
||||
sqlite_open_main_db: 0x00000100,
|
||||
sqlite_open_temp_db: 0x00000200,
|
||||
sqlite_open_transient_db: 0x00000400,
|
||||
sqlite_open_main_journal: 0x00000800,
|
||||
sqlite_open_temp_journal: 0x00001000,
|
||||
sqlite_open_subjournal: 0x00002000,
|
||||
sqlite_open_super_journal: 0x00004000,
|
||||
sqlite_open_nomutex: 0x00008000,
|
||||
sqlite_open_fullmutex: 0x00010000,
|
||||
sqlite_open_sharedcache: 0x00020000,
|
||||
sqlite_open_privatecache: 0x00040000,
|
||||
sqlite_open_wal: 0x00080000,
|
||||
sqlite_open_nofollow: 0x01000000,
|
||||
sqlite_open_exrescode: 0x02000000
|
||||
]
|
||||
|
||||
def put_file_open_flags(current_flags \\ 0, flags) do
|
||||
Enum.reduce(flags, current_flags, &(&2 ||| Keyword.fetch!(@file_open_flags, &1)))
|
||||
end
|
||||
end
|
||||
121
phoenix/deps/exqlite/lib/exqlite/pragma.ex
Normal file
121
phoenix/deps/exqlite/lib/exqlite/pragma.ex
Normal file
@@ -0,0 +1,121 @@
|
||||
defmodule Exqlite.Pragma do
|
||||
@moduledoc """
|
||||
Handles parsing extra options for the SQLite connection
|
||||
"""
|
||||
|
||||
def busy_timeout(nil), do: busy_timeout([])
|
||||
|
||||
def busy_timeout(options) do
|
||||
Keyword.get(options, :busy_timeout, 2000)
|
||||
end
|
||||
|
||||
def journal_mode(nil), do: journal_mode([])
|
||||
|
||||
def journal_mode(options) do
|
||||
case Keyword.get(options, :journal_mode, :delete) do
|
||||
:delete -> "delete"
|
||||
:memory -> "memory"
|
||||
:off -> "off"
|
||||
:persist -> "persist"
|
||||
:truncate -> "truncate"
|
||||
:wal -> "wal"
|
||||
_ -> raise ArgumentError, "invalid :journal_mode"
|
||||
end
|
||||
end
|
||||
|
||||
def temp_store(nil), do: temp_store([])
|
||||
|
||||
def temp_store(options) do
|
||||
case Keyword.get(options, :temp_store, :default) do
|
||||
:file -> 1
|
||||
:memory -> 2
|
||||
:default -> 0
|
||||
_ -> raise ArgumentError, "invalid :temp_store"
|
||||
end
|
||||
end
|
||||
|
||||
def synchronous(nil), do: synchronous([])
|
||||
|
||||
def synchronous(options) do
|
||||
case Keyword.get(options, :synchronous, :normal) do
|
||||
:extra -> 3
|
||||
:full -> 2
|
||||
:normal -> 1
|
||||
:off -> 0
|
||||
_ -> raise ArgumentError, "invalid :synchronous"
|
||||
end
|
||||
end
|
||||
|
||||
def foreign_keys(nil), do: foreign_keys([])
|
||||
|
||||
def foreign_keys(options) do
|
||||
case Keyword.get(options, :foreign_keys, :on) do
|
||||
:off -> 0
|
||||
:on -> 1
|
||||
_ -> raise ArgumentError, "invalid :foreign_keys"
|
||||
end
|
||||
end
|
||||
|
||||
def cache_size(nil), do: cache_size([])
|
||||
|
||||
def cache_size(options) do
|
||||
Keyword.get(options, :cache_size, -2000)
|
||||
end
|
||||
|
||||
def cache_spill(nil), do: cache_spill([])
|
||||
|
||||
def cache_spill(options) do
|
||||
case Keyword.get(options, :cache_spill, :on) do
|
||||
:off -> 0
|
||||
:on -> 1
|
||||
_ -> raise ArgumentError, "invalid :cache_spill"
|
||||
end
|
||||
end
|
||||
|
||||
def case_sensitive_like(nil), do: case_sensitive_like([])
|
||||
|
||||
def case_sensitive_like(options) do
|
||||
case Keyword.get(options, :case_sensitive_like, :off) do
|
||||
:off -> 0
|
||||
:on -> 1
|
||||
_ -> raise ArgumentError, "invalid :case_sensitive_like"
|
||||
end
|
||||
end
|
||||
|
||||
def auto_vacuum(nil), do: auto_vacuum([])
|
||||
|
||||
def auto_vacuum(options) do
|
||||
case Keyword.get(options, :auto_vacuum, :none) do
|
||||
:none -> 0
|
||||
:full -> 1
|
||||
:incremental -> 2
|
||||
_ -> raise ArgumentError, "invalid :auto_vacuum"
|
||||
end
|
||||
end
|
||||
|
||||
def locking_mode(nil), do: locking_mode([])
|
||||
|
||||
def locking_mode(options) do
|
||||
case Keyword.get(options, :locking_mode, :normal) do
|
||||
:normal -> "NORMAL"
|
||||
:exclusive -> "EXCLUSIVE"
|
||||
_ -> raise ArgumentError, "invalid :locking_mode"
|
||||
end
|
||||
end
|
||||
|
||||
def secure_delete(nil), do: secure_delete([])
|
||||
|
||||
def secure_delete(options) do
|
||||
case Keyword.get(options, :secure_delete, :off) do
|
||||
:off -> 0
|
||||
:on -> 1
|
||||
_ -> raise ArgumentError, "invalid :secure_delete"
|
||||
end
|
||||
end
|
||||
|
||||
def wal_auto_check_point(nil), do: wal_auto_check_point([])
|
||||
|
||||
def wal_auto_check_point(options) do
|
||||
Keyword.get(options, :wal_auto_check_point, 1000)
|
||||
end
|
||||
end
|
||||
70
phoenix/deps/exqlite/lib/exqlite/query.ex
Normal file
70
phoenix/deps/exqlite/lib/exqlite/query.ex
Normal file
@@ -0,0 +1,70 @@
|
||||
defmodule Exqlite.Query do
|
||||
@moduledoc """
|
||||
Query struct returned from a successfully prepared query.
|
||||
"""
|
||||
@type t :: %__MODULE__{
|
||||
statement: iodata(),
|
||||
name: atom() | String.t(),
|
||||
ref: reference() | nil,
|
||||
command: :insert | :delete | :update | nil
|
||||
}
|
||||
|
||||
defstruct statement: nil,
|
||||
name: nil,
|
||||
ref: nil,
|
||||
command: nil
|
||||
|
||||
def build(options) do
|
||||
statement = Keyword.get(options, :statement)
|
||||
name = Keyword.get(options, :name)
|
||||
ref = Keyword.get(options, :ref)
|
||||
|
||||
command =
|
||||
case Keyword.get(options, :command) do
|
||||
nil -> extract_command(statement)
|
||||
value -> value
|
||||
end
|
||||
|
||||
%__MODULE__{
|
||||
statement: statement,
|
||||
name: name,
|
||||
ref: ref,
|
||||
command: command
|
||||
}
|
||||
end
|
||||
|
||||
defp extract_command(nil), do: nil
|
||||
|
||||
defp extract_command(statement) do
|
||||
cond do
|
||||
String.contains?(statement, "INSERT") -> :insert
|
||||
String.contains?(statement, "DELETE") -> :delete
|
||||
String.contains?(statement, "UPDATE") -> :update
|
||||
true -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defimpl DBConnection.Query do
|
||||
def parse(query, _opts) do
|
||||
query
|
||||
end
|
||||
|
||||
def describe(query, _opts) do
|
||||
query
|
||||
end
|
||||
|
||||
def encode(_query, params, _opts) do
|
||||
params
|
||||
end
|
||||
|
||||
def decode(_query, result, _opts) do
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
defimpl String.Chars do
|
||||
def to_string(%{statement: statement}) do
|
||||
IO.iodata_to_binary(statement)
|
||||
end
|
||||
end
|
||||
end
|
||||
35
phoenix/deps/exqlite/lib/exqlite/result.ex
Normal file
35
phoenix/deps/exqlite/lib/exqlite/result.ex
Normal file
@@ -0,0 +1,35 @@
|
||||
defmodule Exqlite.Result do
|
||||
@moduledoc """
|
||||
The database results.
|
||||
"""
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
command: atom,
|
||||
columns: [String.t()] | nil,
|
||||
rows: [[term] | term] | nil,
|
||||
num_rows: integer()
|
||||
}
|
||||
|
||||
defstruct command: nil, columns: [], rows: [], num_rows: 0
|
||||
|
||||
def new(options) do
|
||||
%__MODULE__{
|
||||
command: Keyword.get(options, :command),
|
||||
columns: Keyword.get(options, :columns, []),
|
||||
rows: Keyword.get(options, :rows, []),
|
||||
num_rows: Keyword.get(options, :num_rows, 0)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
if Code.ensure_loaded?(Table.Reader) do
|
||||
defimpl Table.Reader, for: Exqlite.Result do
|
||||
def init(%{columns: columns}) when columns in [nil, []] do
|
||||
{:rows, %{columns: []}, []}
|
||||
end
|
||||
|
||||
def init(result) do
|
||||
{:rows, %{columns: result.columns}, result.rows}
|
||||
end
|
||||
end
|
||||
end
|
||||
587
phoenix/deps/exqlite/lib/exqlite/sqlite3.ex
Normal file
587
phoenix/deps/exqlite/lib/exqlite/sqlite3.ex
Normal file
@@ -0,0 +1,587 @@
|
||||
defmodule Exqlite.Sqlite3 do
|
||||
@moduledoc """
|
||||
The interface to the NIF implementation.
|
||||
"""
|
||||
|
||||
# If the database reference is closed, any prepared statements should be
|
||||
# dereferenced as well. It is entirely possible that an application does
|
||||
# not properly remove a stale reference.
|
||||
#
|
||||
# Will need to add a test for this and think of possible solution.
|
||||
|
||||
# Need to figure out if we can just stream results where we use this
|
||||
# module as a sink.
|
||||
|
||||
alias Exqlite.Flags
|
||||
alias Exqlite.Sqlite3NIF
|
||||
|
||||
@type db() :: reference()
|
||||
@type statement() :: reference()
|
||||
@type reason() :: atom() | String.t()
|
||||
@type row() :: list()
|
||||
@type open_mode :: :readwrite | :readonly | :nomutex
|
||||
@type open_opt :: {:mode, :readwrite | :readonly | [open_mode()]}
|
||||
|
||||
@doc """
|
||||
Opens a new sqlite database at the Path provided.
|
||||
|
||||
`path` can be `":memory"` to keep the sqlite database in memory.
|
||||
|
||||
## Options
|
||||
|
||||
* `:mode` - use `:readwrite` to open the database for reading and writing
|
||||
, `:readonly` to open it in read-only mode or `[:readonly | :readwrite, :nomutex]`
|
||||
to open it with no mutex mode. `:readwrite` will also create
|
||||
the database if it doesn't already exist. Defaults to `:readwrite`.
|
||||
Note: [:readwrite, :nomutex] is not recommended.
|
||||
"""
|
||||
@spec open(String.t(), [open_opt()]) :: {:ok, db()} | {:error, reason()}
|
||||
def open(path, opts \\ []) do
|
||||
mode = Keyword.get(opts, :mode, :readwrite)
|
||||
Sqlite3NIF.open(path, flags_from_mode(mode))
|
||||
end
|
||||
|
||||
defp flags_from_mode(:nomutex) do
|
||||
raise ArgumentError,
|
||||
"expected mode to be `:readwrite` or `:readonly`, can't use a single :nomutex mode"
|
||||
end
|
||||
|
||||
defp flags_from_mode(:readwrite),
|
||||
do: do_flags_from_mode([:readwrite], [])
|
||||
|
||||
defp flags_from_mode(:readonly),
|
||||
do: do_flags_from_mode([:readonly], [])
|
||||
|
||||
defp flags_from_mode([_ | _] = modes),
|
||||
do: do_flags_from_mode(modes, [])
|
||||
|
||||
defp flags_from_mode(mode) do
|
||||
raise ArgumentError,
|
||||
"expected mode to be `:readwrite`, `:readonly` or list of modes, but received #{inspect(mode)}"
|
||||
end
|
||||
|
||||
defp do_flags_from_mode([:readwrite | tail], acc),
|
||||
do: do_flags_from_mode(tail, [:sqlite_open_readwrite, :sqlite_open_create | acc])
|
||||
|
||||
defp do_flags_from_mode([:readonly | tail], acc),
|
||||
do: do_flags_from_mode(tail, [:sqlite_open_readonly | acc])
|
||||
|
||||
defp do_flags_from_mode([:nomutex | tail], acc),
|
||||
do: do_flags_from_mode(tail, [:sqlite_open_nomutex | acc])
|
||||
|
||||
defp do_flags_from_mode([mode | _tail], _acc) do
|
||||
raise ArgumentError,
|
||||
"expected mode to be `:readwrite`, `:readonly` or `:nomutex`, but received #{inspect(mode)}"
|
||||
end
|
||||
|
||||
defp do_flags_from_mode([], acc),
|
||||
do: Flags.put_file_open_flags(acc)
|
||||
|
||||
@doc """
|
||||
Closes the database and releases any underlying resources.
|
||||
"""
|
||||
@spec close(db() | nil) :: :ok | {:error, reason()}
|
||||
def close(nil), do: :ok
|
||||
def close(conn), do: Sqlite3NIF.close(conn)
|
||||
|
||||
@doc """
|
||||
Interrupt a long-running query.
|
||||
|
||||
> #### Warning {: .warning}
|
||||
> If you are going to interrupt a long running process, it is unsafe to call
|
||||
> `close/1` immediately after. You run the risk of undefined behavior. This
|
||||
> is a limitation of the sqlite library itself. Please see the documentation
|
||||
> https://www.sqlite.org/c3ref/interrupt.html for more information.
|
||||
>
|
||||
> If close must be called after, it is best to put a short sleep in order to
|
||||
> let sqlite finish doing its book keeping.
|
||||
"""
|
||||
@spec interrupt(db() | nil) :: :ok | {:error, reason()}
|
||||
def interrupt(nil), do: :ok
|
||||
def interrupt(conn), do: Sqlite3NIF.interrupt(conn)
|
||||
|
||||
@doc """
|
||||
Executes an sql script. Multiple stanzas can be passed at once.
|
||||
"""
|
||||
@spec execute(db(), String.t()) :: :ok | {:error, reason()}
|
||||
def execute(conn, sql), do: Sqlite3NIF.execute(conn, sql)
|
||||
|
||||
@doc """
|
||||
Get the number of changes recently.
|
||||
|
||||
**Note**: If triggers are used, the count may be larger than expected.
|
||||
|
||||
See: https://sqlite.org/c3ref/changes.html
|
||||
"""
|
||||
@spec changes(db()) :: {:ok, integer()} | {:error, reason()}
|
||||
def changes(conn), do: Sqlite3NIF.changes(conn)
|
||||
|
||||
@spec prepare(db(), String.t()) :: {:ok, statement()} | {:error, reason()}
|
||||
def prepare(conn, sql), do: Sqlite3NIF.prepare(conn, sql)
|
||||
|
||||
@doc """
|
||||
Resets a prepared statement.
|
||||
|
||||
See: https://sqlite.org/c3ref/reset.html
|
||||
"""
|
||||
@spec reset(statement) :: :ok | {:error, atom()}
|
||||
def reset(stmt), do: Sqlite3NIF.reset(stmt)
|
||||
|
||||
@doc """
|
||||
Returns number of SQL parameters in a prepared statement.
|
||||
|
||||
iex> {:ok, conn} = Sqlite3.open(":memory:", [:readonly])
|
||||
iex> {:ok, stmt} = Sqlite3.prepare(conn, "SELECT ?, ?")
|
||||
iex> Sqlite3.bind_parameter_count(stmt)
|
||||
2
|
||||
|
||||
"""
|
||||
@spec bind_parameter_count(statement) :: non_neg_integer | {:error, atom()}
|
||||
def bind_parameter_count(stmt), do: Sqlite3NIF.bind_parameter_count(stmt)
|
||||
|
||||
@type bind_value ::
|
||||
NaiveDateTime.t()
|
||||
| DateTime.t()
|
||||
| Date.t()
|
||||
| Time.t()
|
||||
| number
|
||||
| iodata
|
||||
| {:blob, iodata}
|
||||
| atom
|
||||
|
||||
@doc """
|
||||
Resets a prepared statement and binds values to it.
|
||||
|
||||
iex> {:ok, conn} = Sqlite3.open(":memory:", [:readonly])
|
||||
iex> {:ok, stmt} = Sqlite3.prepare(conn, "SELECT ?, ?, ?, ?, ?")
|
||||
iex> Sqlite3.bind(stmt, [42, 3.14, "Alice", {:blob, <<0, 0, 0>>}, nil])
|
||||
iex> Sqlite3.step(conn, stmt)
|
||||
{:row, [42, 3.14, "Alice", <<0, 0, 0>>, nil]}
|
||||
|
||||
iex> {:ok, conn} = Sqlite3.open(":memory:", [:readonly])
|
||||
iex> {:ok, stmt} = Sqlite3.prepare(conn, "SELECT :42, @pi, $name, @blob, :null")
|
||||
iex> Sqlite3.bind(stmt, %{":42" => 42, "@pi" => 3.14, "$name" => "Alice", :"@blob" => {:blob, <<0, 0, 0>>}, ~c":null" => nil})
|
||||
iex> Sqlite3.step(conn, stmt)
|
||||
{:row, [42, 3.14, "Alice", <<0, 0, 0>>, nil]}
|
||||
|
||||
iex> {:ok, conn} = Sqlite3.open(":memory:", [:readonly])
|
||||
iex> {:ok, stmt} = Sqlite3.prepare(conn, "SELECT ?")
|
||||
iex> Sqlite3.bind(stmt, [42, 3.14, "Alice"])
|
||||
** (ArgumentError) expected 1 arguments, got 3
|
||||
|
||||
iex> {:ok, conn} = Sqlite3.open(":memory:", [:readonly])
|
||||
iex> {:ok, stmt} = Sqlite3.prepare(conn, "SELECT ?, ?")
|
||||
iex> Sqlite3.bind(stmt, [42])
|
||||
** (ArgumentError) expected 2 arguments, got 1
|
||||
|
||||
iex> {:ok, conn} = Sqlite3.open(":memory:", [:readonly])
|
||||
iex> {:ok, stmt} = Sqlite3.prepare(conn, "SELECT ?")
|
||||
iex> Sqlite3.bind(stmt, [:erlang.list_to_pid(~c"<0.0.0>")])
|
||||
** (ArgumentError) unsupported type: #PID<0.0.0>
|
||||
|
||||
"""
|
||||
@spec bind(
|
||||
statement,
|
||||
[bind_value] | %{optional(String.t()) => bind_value} | nil
|
||||
) :: :ok
|
||||
def bind(stmt, nil), do: bind(stmt, [])
|
||||
|
||||
def bind(stmt, args) when is_list(args) do
|
||||
case bind_parameter_count(stmt) do
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
|
||||
params_count ->
|
||||
args_count = length(args)
|
||||
|
||||
if args_count == params_count do
|
||||
bind_all(args, stmt, 1)
|
||||
else
|
||||
raise ArgumentError, "expected #{params_count} arguments, got #{args_count}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def bind(stmt, args) when is_map(args) do
|
||||
case bind_parameter_count(stmt) do
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
|
||||
params_count ->
|
||||
args_count = map_size(args)
|
||||
|
||||
if args_count == params_count do
|
||||
bind_all_named(Map.to_list(args), stmt)
|
||||
else
|
||||
raise ArgumentError,
|
||||
"expected #{params_count} named arguments, got #{args_count}: #{inspect(Map.keys(args))}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp bind_all([param | params], stmt, idx) do
|
||||
do_bind(stmt, idx, param)
|
||||
bind_all(params, stmt, idx + 1)
|
||||
end
|
||||
|
||||
defp bind_all([], _stmt, _idx), do: :ok
|
||||
|
||||
defp bind_all_named([{name, param} | named_params], stmt) do
|
||||
idx = Sqlite3NIF.bind_parameter_index(stmt, to_string(name))
|
||||
|
||||
if idx == 0 do
|
||||
raise ArgumentError, "unknown named parameter: #{inspect(name)}"
|
||||
end
|
||||
|
||||
do_bind(stmt, idx, param)
|
||||
bind_all_named(named_params, stmt)
|
||||
end
|
||||
|
||||
defp bind_all_named([], _stmt), do: :ok
|
||||
|
||||
# credo:disable-for-next-line Credo.Check.Refactor.CyclomaticComplexity
|
||||
defp do_bind(stmt, idx, param) do
|
||||
case convert(param) do
|
||||
i when is_integer(i) -> bind_integer(stmt, idx, i)
|
||||
f when is_float(f) -> bind_float(stmt, idx, f)
|
||||
b when is_binary(b) -> bind_text(stmt, idx, b)
|
||||
b when is_list(b) -> bind_text(stmt, idx, IO.iodata_to_binary(b))
|
||||
nil -> bind_null(stmt, idx)
|
||||
:undefined -> bind_null(stmt, idx)
|
||||
a when is_atom(a) -> bind_text(stmt, idx, Atom.to_string(a))
|
||||
{:blob, b} when is_binary(b) -> bind_blob(stmt, idx, b)
|
||||
{:blob, b} when is_list(b) -> bind_blob(stmt, idx, IO.iodata_to_binary(b))
|
||||
_other -> raise ArgumentError, "unsupported type: #{inspect(param)}"
|
||||
end
|
||||
end
|
||||
|
||||
@spec columns(db(), statement()) :: {:ok, [binary()]} | {:error, reason()}
|
||||
def columns(conn, statement), do: Sqlite3NIF.columns(conn, statement)
|
||||
|
||||
@spec step(db(), statement()) :: :done | :busy | {:row, row()} | {:error, reason()}
|
||||
def step(conn, statement), do: Sqlite3NIF.step(conn, statement)
|
||||
|
||||
@spec multi_step(db(), statement()) ::
|
||||
:busy | {:rows, [row()]} | {:done, [row()]} | {:error, reason()}
|
||||
def multi_step(conn, statement) do
|
||||
chunk_size = Application.get_env(:exqlite, :default_chunk_size, 50)
|
||||
multi_step(conn, statement, chunk_size)
|
||||
end
|
||||
|
||||
@spec multi_step(db(), statement(), integer()) ::
|
||||
:busy | {:rows, [row()]} | {:done, [row()]} | {:error, reason()}
|
||||
def multi_step(conn, statement, chunk_size) do
|
||||
case Sqlite3NIF.multi_step(conn, statement, chunk_size) do
|
||||
:busy ->
|
||||
:busy
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
|
||||
{:rows, rows} ->
|
||||
{:rows, Enum.reverse(rows)}
|
||||
|
||||
{:done, rows} ->
|
||||
{:done, Enum.reverse(rows)}
|
||||
end
|
||||
end
|
||||
|
||||
@spec last_insert_rowid(db()) :: {:ok, integer()}
|
||||
def last_insert_rowid(conn), do: Sqlite3NIF.last_insert_rowid(conn)
|
||||
|
||||
@spec transaction_status(db()) :: {:ok, :idle | :transaction}
|
||||
def transaction_status(conn), do: Sqlite3NIF.transaction_status(conn)
|
||||
|
||||
@doc """
|
||||
Causes the database connection to free as much memory as it can. This is
|
||||
useful if you are on a memory restricted system.
|
||||
"""
|
||||
@spec shrink_memory(db()) :: :ok | {:error, reason()}
|
||||
def shrink_memory(conn) do
|
||||
Sqlite3NIF.execute(conn, "PRAGMA shrink_memory")
|
||||
end
|
||||
|
||||
@spec fetch_all(db(), statement(), integer()) :: {:ok, [row()]} | {:error, reason()}
|
||||
def fetch_all(conn, statement, chunk_size) do
|
||||
{:ok, try_fetch_all(conn, statement, chunk_size)}
|
||||
catch
|
||||
:throw, {:error, _reason} = error -> error
|
||||
end
|
||||
|
||||
defp try_fetch_all(conn, statement, chunk_size) do
|
||||
case multi_step(conn, statement, chunk_size) do
|
||||
{:done, rows} -> rows
|
||||
{:rows, rows} -> rows ++ try_fetch_all(conn, statement, chunk_size)
|
||||
{:error, _reason} = error -> throw(error)
|
||||
:busy -> throw({:error, "Database busy"})
|
||||
end
|
||||
end
|
||||
|
||||
@spec fetch_all(db(), statement()) :: {:ok, [row()]} | {:error, reason()}
|
||||
def fetch_all(conn, statement) do
|
||||
# Should this be done in the NIF? It can be _much_ faster to build a list
|
||||
# there, but at the expense that it could block other dirty nifs from
|
||||
# getting work done.
|
||||
#
|
||||
# For now this just works
|
||||
chunk_size = Application.get_env(:exqlite, :default_chunk_size, 50)
|
||||
fetch_all(conn, statement, chunk_size)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Serialize the contents of the database to a binary.
|
||||
"""
|
||||
@spec serialize(db(), String.t()) :: {:ok, binary()} | {:error, reason()}
|
||||
def serialize(conn, database \\ "main") do
|
||||
Sqlite3NIF.serialize(conn, database)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Disconnect from database and then reopen as an in-memory database based on
|
||||
the serialized binary.
|
||||
"""
|
||||
@spec deserialize(db(), String.t(), binary()) :: :ok | {:error, reason()}
|
||||
def deserialize(conn, database \\ "main", serialized) do
|
||||
Sqlite3NIF.deserialize(conn, database, serialized)
|
||||
end
|
||||
|
||||
def release(_conn, nil), do: :ok
|
||||
|
||||
@doc """
|
||||
Once finished with the prepared statement, call this to release the underlying
|
||||
resources.
|
||||
|
||||
This should be called whenever you are done operating with the prepared statement. If
|
||||
the system has a high load the garbage collector may not clean up the prepared
|
||||
statements in a timely manner and causing higher than normal levels of memory
|
||||
pressure.
|
||||
|
||||
If you are operating on limited memory capacity systems, definitely call this.
|
||||
"""
|
||||
@spec release(db(), statement()) :: :ok | {:error, reason()}
|
||||
def release(conn, statement) do
|
||||
Sqlite3NIF.release(conn, statement)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Allow loading native extensions.
|
||||
"""
|
||||
@spec enable_load_extension(db(), boolean()) :: :ok | {:error, reason()}
|
||||
def enable_load_extension(conn, flag) do
|
||||
if flag do
|
||||
Sqlite3NIF.enable_load_extension(conn, 1)
|
||||
else
|
||||
Sqlite3NIF.enable_load_extension(conn, 0)
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Send data change notifications to a process.
|
||||
|
||||
Each time an insert, update, or delete is performed on the connection provided
|
||||
as the first argument, a message will be sent to the pid provided as the second argument.
|
||||
|
||||
The message is of the form: `{action, db_name, table, row_id}`, where:
|
||||
|
||||
* `action` is one of `:insert`, `:update` or `:delete`
|
||||
* `db_name` is a string representing the database name where the change took place
|
||||
* `table` is a string representing the table name where the change took place
|
||||
* `row_id` is an integer representing the unique row id assigned by SQLite
|
||||
|
||||
## Restrictions
|
||||
|
||||
* There are some conditions where the update hook will not be invoked by SQLite.
|
||||
See the documentation for [more details](https://www.sqlite.org/c3ref/update_hook.html)
|
||||
* Only one pid can listen to the changes on a given database connection at a time.
|
||||
If this function is called multiple times for the same connection, only the last pid will
|
||||
receive the notifications
|
||||
* Updates only happen for the connection that is opened. For example, there
|
||||
are two connections A and B. When an update happens on connection B, the
|
||||
hook set for connection A will not receive the update, but the hook for
|
||||
connection B will receive the update.
|
||||
"""
|
||||
@spec set_update_hook(db(), pid()) :: :ok | {:error, reason()}
|
||||
def set_update_hook(conn, pid) do
|
||||
Sqlite3NIF.set_update_hook(conn, pid)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Set an authorizer that denies specific SQL operations.
|
||||
|
||||
Accepts a list of action atoms to deny. Any SQL statement that triggers a
|
||||
denied action will fail with a "not authorized" error during preparation.
|
||||
|
||||
Pass an empty list to clear the authorizer.
|
||||
|
||||
## Action atoms
|
||||
|
||||
`:attach`, `:detach`, `:pragma`, `:insert`, `:update`, `:delete`,
|
||||
`:create_table`, `:drop_table`, `:create_index`, `:drop_index`,
|
||||
`:create_trigger`, `:drop_trigger`, `:create_view`, `:drop_view`,
|
||||
`:alter_table`, `:reindex`, `:analyze`, `:function`, `:savepoint`,
|
||||
`:transaction`, `:read`, `:select`, `:recursive`,
|
||||
`:create_temp_table`, `:create_temp_index`, `:create_temp_trigger`,
|
||||
`:create_temp_view`, `:drop_temp_table`, `:drop_temp_index`,
|
||||
`:drop_temp_trigger`, `:drop_temp_view`, `:create_vtable`, `:drop_vtable`
|
||||
|
||||
## Examples
|
||||
|
||||
# Block ATTACH and DETACH (prevent cross-database reads)
|
||||
:ok = Sqlite3.set_authorizer(conn, [:attach, :detach])
|
||||
|
||||
# Clear the authorizer
|
||||
:ok = Sqlite3.set_authorizer(conn, [])
|
||||
"""
|
||||
@spec set_authorizer(db(), [atom()]) :: :ok | {:error, reason()}
|
||||
def set_authorizer(conn, deny_list) when is_list(deny_list) do
|
||||
Sqlite3NIF.set_authorizer(conn, deny_list)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Send log messages to a process.
|
||||
|
||||
Each time a message is logged in SQLite a message will be sent to the pid provided as the argument.
|
||||
|
||||
The message is of the form: `{:log, rc, message}`, where:
|
||||
|
||||
* `rc` is an integer [result code](https://www.sqlite.org/rescode.html) or an [extended result code](https://www.sqlite.org/rescode.html#extrc)
|
||||
* `message` is a string representing the log message
|
||||
|
||||
See [`SQLITE_CONFIG_LOG`](https://www.sqlite.org/c3ref/c_config_covering_index_scan.html) and
|
||||
["The Error And Warning Log"](https://www.sqlite.org/errlog.html) for more details.
|
||||
|
||||
## Restrictions
|
||||
|
||||
* Only one pid can listen to the log messages at a time.
|
||||
If this function is called multiple times, only the last pid will
|
||||
receive the notifications
|
||||
"""
|
||||
@spec set_log_hook(pid()) :: :ok | {:error, reason()}
|
||||
def set_log_hook(pid) do
|
||||
Sqlite3NIF.set_log_hook(pid)
|
||||
end
|
||||
|
||||
@sqlite_ok 0
|
||||
|
||||
@doc """
|
||||
Binds a text value to a prepared statement.
|
||||
|
||||
iex> {:ok, conn} = Sqlite3.open(":memory:", [:readonly])
|
||||
iex> {:ok, stmt} = Sqlite3.prepare(conn, "SELECT ?")
|
||||
iex> Sqlite3.bind_text(stmt, 1, "Alice")
|
||||
:ok
|
||||
|
||||
"""
|
||||
@spec bind_text(statement, non_neg_integer, String.t()) :: :ok
|
||||
def bind_text(stmt, index, text) do
|
||||
case Sqlite3NIF.bind_text(stmt, index, text) do
|
||||
@sqlite_ok -> :ok
|
||||
rc -> raise Exqlite.Error, message: errmsg(stmt) || errstr(rc)
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Binds a blob value to a prepared statement.
|
||||
|
||||
iex> {:ok, conn} = Sqlite3.open(":memory:", [:readonly])
|
||||
iex> {:ok, stmt} = Sqlite3.prepare(conn, "SELECT ?")
|
||||
iex> Sqlite3.bind_blob(stmt, 1, <<0, 0, 0>>)
|
||||
:ok
|
||||
|
||||
"""
|
||||
@spec bind_blob(statement, non_neg_integer, binary) :: :ok
|
||||
def bind_blob(stmt, index, blob) do
|
||||
case Sqlite3NIF.bind_blob(stmt, index, blob) do
|
||||
@sqlite_ok -> :ok
|
||||
rc -> raise Exqlite.Error, message: errmsg(stmt) || errstr(rc)
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Binds an integer value to a prepared statement.
|
||||
|
||||
iex> {:ok, conn} = Sqlite3.open(":memory:", [:readonly])
|
||||
iex> {:ok, stmt} = Sqlite3.prepare(conn, "SELECT ?")
|
||||
iex> Sqlite3.bind_integer(stmt, 1, 42)
|
||||
:ok
|
||||
|
||||
"""
|
||||
@spec bind_integer(statement, non_neg_integer, integer) :: :ok
|
||||
def bind_integer(stmt, index, integer) do
|
||||
case Sqlite3NIF.bind_integer(stmt, index, integer) do
|
||||
@sqlite_ok -> :ok
|
||||
rc -> raise Exqlite.Error, message: errmsg(stmt) || errstr(rc)
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Binds a float value to a prepared statement.
|
||||
|
||||
iex> {:ok, conn} = Sqlite3.open(":memory:", [:readonly])
|
||||
iex> {:ok, stmt} = Sqlite3.prepare(conn, "SELECT ?")
|
||||
iex> Sqlite3.bind_float(stmt, 1, 3.14)
|
||||
:ok
|
||||
|
||||
"""
|
||||
@spec bind_float(statement, non_neg_integer, float) :: :ok
|
||||
def bind_float(stmt, index, float) do
|
||||
case Sqlite3NIF.bind_float(stmt, index, float) do
|
||||
@sqlite_ok -> :ok
|
||||
rc -> raise Exqlite.Error, message: errmsg(stmt) || errstr(rc)
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Binds a null value to a prepared statement.
|
||||
|
||||
iex> {:ok, conn} = Sqlite3.open(":memory:", [:readonly])
|
||||
iex> {:ok, stmt} = Sqlite3.prepare(conn, "SELECT ?")
|
||||
iex> Sqlite3.bind_null(stmt, 1)
|
||||
:ok
|
||||
|
||||
"""
|
||||
@spec bind_null(statement, non_neg_integer) :: :ok
|
||||
def bind_null(stmt, index) do
|
||||
case Sqlite3NIF.bind_null(stmt, index) do
|
||||
@sqlite_ok -> :ok
|
||||
rc -> raise Exqlite.Error, message: errmsg(stmt) || errstr(rc)
|
||||
end
|
||||
end
|
||||
|
||||
defp errmsg(stmt), do: Sqlite3NIF.errmsg(stmt)
|
||||
defp errstr(rc), do: Sqlite3NIF.errstr(rc)
|
||||
|
||||
defp convert(%Date{} = val), do: Date.to_iso8601(val)
|
||||
defp convert(%Time{} = val), do: Time.to_iso8601(val)
|
||||
defp convert(%NaiveDateTime{} = val), do: NaiveDateTime.to_iso8601(val)
|
||||
defp convert(%DateTime{time_zone: "Etc/UTC"} = val), do: NaiveDateTime.to_iso8601(val)
|
||||
|
||||
defp convert(%DateTime{} = datetime) do
|
||||
raise ArgumentError, "#{inspect(datetime)} is not in UTC"
|
||||
end
|
||||
|
||||
defp convert(val) do
|
||||
convert_with_type_extensions(type_extensions(), val)
|
||||
end
|
||||
|
||||
defp convert_with_type_extensions(nil, val), do: val
|
||||
defp convert_with_type_extensions([], val), do: val
|
||||
|
||||
defp convert_with_type_extensions([extension | other_extensions], val) do
|
||||
case extension.convert(val) do
|
||||
nil ->
|
||||
convert_with_type_extensions(other_extensions, val)
|
||||
|
||||
{:ok, converted} ->
|
||||
converted
|
||||
|
||||
{:error, reason} ->
|
||||
raise ArgumentError,
|
||||
"Failed conversion by TypeExtension #{extension}: #{inspect(val)}. Reason: #{inspect(reason)}."
|
||||
end
|
||||
end
|
||||
|
||||
defp type_extensions do
|
||||
Application.get_env(:exqlite, :type_extensions)
|
||||
end
|
||||
end
|
||||
106
phoenix/deps/exqlite/lib/exqlite/sqlite3_nif.ex
Normal file
106
phoenix/deps/exqlite/lib/exqlite/sqlite3_nif.ex
Normal file
@@ -0,0 +1,106 @@
|
||||
defmodule Exqlite.Sqlite3NIF do
|
||||
@moduledoc """
|
||||
This is the module where all of the NIF entry points reside. Calling this directly
|
||||
should be avoided unless you are aware of what you are doing.
|
||||
"""
|
||||
|
||||
@compile {:autoload, false}
|
||||
@on_load {:load_nif, 0}
|
||||
|
||||
@type db() :: reference()
|
||||
@type statement() :: reference()
|
||||
@type reason() :: :atom | String.Chars.t()
|
||||
@type row() :: list()
|
||||
|
||||
def load_nif() do
|
||||
path = :filename.join(:code.priv_dir(:exqlite), ~c"sqlite3_nif")
|
||||
:erlang.load_nif(path, 0)
|
||||
end
|
||||
|
||||
@spec open(String.t(), integer()) :: {:ok, db()} | {:error, reason()}
|
||||
def open(_path, _flags), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec close(db()) :: :ok | {:error, reason()}
|
||||
def close(_conn), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec interrupt(db()) :: :ok | {:error, reason()}
|
||||
def interrupt(_conn), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec execute(db(), String.t()) :: :ok | {:error, reason()}
|
||||
def execute(_conn, _sql), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec changes(db()) :: {:ok, integer()} | {:error, reason()}
|
||||
def changes(_conn), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec prepare(db(), String.t()) :: {:ok, statement()} | {:error, reason()}
|
||||
def prepare(_conn, _sql), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec step(db(), statement()) :: :done | :busy | {:row, row()} | {:error, reason()}
|
||||
def step(_conn, _statement), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec multi_step(db(), statement(), integer()) ::
|
||||
:busy | {:rows, [row()]} | {:done, [row()]} | {:error, reason()}
|
||||
def multi_step(_conn, _statement, _chunk_size), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec columns(db(), statement()) :: {:ok, list(binary())} | {:error, reason()}
|
||||
def columns(_conn, _statement), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec last_insert_rowid(db()) :: {:ok, integer()}
|
||||
def last_insert_rowid(_conn), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec transaction_status(db()) :: {:ok, :idle | :transaction}
|
||||
def transaction_status(_conn), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec serialize(db(), String.t()) :: {:ok, binary()} | {:error, reason()}
|
||||
def serialize(_conn, _database), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec deserialize(db(), String.t(), binary()) :: :ok | {:error, reason()}
|
||||
def deserialize(_conn, _database, _serialized), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec release(db(), statement()) :: :ok | {:error, reason()}
|
||||
def release(_conn, _statement), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec enable_load_extension(db(), integer()) :: :ok | {:error, reason()}
|
||||
def enable_load_extension(_conn, _flag), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec set_update_hook(db(), pid()) :: :ok | {:error, reason()}
|
||||
def set_update_hook(_conn, _pid), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec set_authorizer(db(), [atom()]) :: :ok | {:error, reason()}
|
||||
def set_authorizer(_conn, _deny_list), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec set_log_hook(pid()) :: :ok | {:error, reason()}
|
||||
def set_log_hook(_pid), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec bind_parameter_count(statement) :: integer
|
||||
def bind_parameter_count(_stmt), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec bind_parameter_index(statement, String.t()) :: integer
|
||||
def bind_parameter_index(_stmt, _name), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec bind_text(statement, non_neg_integer, String.t()) :: integer()
|
||||
def bind_text(_stmt, _index, _text), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec bind_blob(statement, non_neg_integer, binary) :: integer()
|
||||
def bind_blob(_stmt, _index, _blob), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec bind_integer(statement, non_neg_integer, integer) :: integer()
|
||||
def bind_integer(_stmt, _index, _integer), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec bind_float(statement, non_neg_integer, float) :: integer()
|
||||
def bind_float(_stmt, _index, _float), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec bind_null(statement, non_neg_integer) :: integer()
|
||||
def bind_null(_stmt, _index), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec reset(statement) :: :ok
|
||||
def reset(_stmt), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec errmsg(db | statement) :: String.t() | nil
|
||||
def errmsg(_db_or_stmt), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
@spec errstr(integer) :: String.t()
|
||||
def errstr(_rc), do: :erlang.nif_error(:not_loaded)
|
||||
|
||||
# add statement inspection tooling https://sqlite.org/c3ref/expanded_sql.html
|
||||
end
|
||||
42
phoenix/deps/exqlite/lib/exqlite/stream.ex
Normal file
42
phoenix/deps/exqlite/lib/exqlite/stream.ex
Normal file
@@ -0,0 +1,42 @@
|
||||
defmodule Exqlite.Stream do
|
||||
@moduledoc false
|
||||
defstruct [:conn, :query, :params, :options]
|
||||
@type t :: %Exqlite.Stream{}
|
||||
|
||||
defimpl Enumerable do
|
||||
def reduce(%Exqlite.Stream{query: %Exqlite.Query{} = query} = stream, acc, fun) do
|
||||
# Possibly need to pass a chunk size option along so that we can let
|
||||
# the NIF chunk it.
|
||||
%Exqlite.Stream{conn: conn, params: params, options: opts} = stream
|
||||
|
||||
stream = %DBConnection.Stream{
|
||||
conn: conn,
|
||||
query: query,
|
||||
params: params,
|
||||
opts: opts
|
||||
}
|
||||
|
||||
DBConnection.reduce(stream, acc, fun)
|
||||
end
|
||||
|
||||
def reduce(%Exqlite.Stream{query: statement} = stream, acc, fun) do
|
||||
%Exqlite.Stream{conn: conn, params: params, options: opts} = stream
|
||||
query = %Exqlite.Query{name: "", statement: statement}
|
||||
|
||||
stream = %DBConnection.PrepareStream{
|
||||
conn: conn,
|
||||
query: query,
|
||||
params: params,
|
||||
opts: opts
|
||||
}
|
||||
|
||||
DBConnection.reduce(stream, acc, fun)
|
||||
end
|
||||
|
||||
def member?(_, _), do: {:error, __MODULE__}
|
||||
|
||||
def count(_), do: {:error, __MODULE__}
|
||||
|
||||
def slice(_), do: {:error, __MODULE__}
|
||||
end
|
||||
end
|
||||
14
phoenix/deps/exqlite/lib/exqlite/type_extension.ex
Normal file
14
phoenix/deps/exqlite/lib/exqlite/type_extension.ex
Normal file
@@ -0,0 +1,14 @@
|
||||
defmodule Exqlite.TypeExtension do
|
||||
@moduledoc """
|
||||
A behaviour that defines the API for extensions providing custom data loaders and dumpers
|
||||
for Ecto schemas.
|
||||
"""
|
||||
|
||||
@doc """
|
||||
Takes a value and convers it to data suitable for storage in the database.
|
||||
|
||||
Returns a tagged :ok/:error tuple. If the value is not convertable by this
|
||||
extension, returns nil.
|
||||
"""
|
||||
@callback convert(value :: term) :: {:ok, term} | {:error, reason :: term} | nil
|
||||
end
|
||||
156
phoenix/deps/exqlite/mix.exs
Normal file
156
phoenix/deps/exqlite/mix.exs
Normal file
@@ -0,0 +1,156 @@
|
||||
defmodule Exqlite.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
@version "0.36.0"
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :exqlite,
|
||||
version: @version,
|
||||
elixir: "~> 1.14",
|
||||
compilers: [:elixir_make] ++ Mix.compilers(),
|
||||
make_targets: ["all"],
|
||||
make_clean: ["clean"],
|
||||
make_force_build: Application.get_env(:exqlite, :force_build, false),
|
||||
make_precompiler: make_precompiler(),
|
||||
make_precompiler_url:
|
||||
"https://github.com/elixir-sqlite/exqlite/releases/download/v#{@version}/@{artefact_filename}",
|
||||
make_precompiler_filename: "sqlite3_nif",
|
||||
make_precompiler_nif_versions: make_precompiler_nif_versions(),
|
||||
make_env: Application.get_env(:exqlite, :make_env, %{}),
|
||||
cc_precompiler: cc_precompiler(),
|
||||
start_permanent: Mix.env() == :prod,
|
||||
aliases: aliases(),
|
||||
deps: deps(),
|
||||
package: package(),
|
||||
description: description(),
|
||||
test_paths: test_paths(System.get_env("EXQLITE_INTEGRATION")),
|
||||
elixirc_paths: elixirc_paths(Mix.env()),
|
||||
dialyzer: dialyzer(),
|
||||
|
||||
# Docs
|
||||
name: "Exqlite",
|
||||
source_url: "https://github.com/elixir-sqlite/exqlite",
|
||||
homepage_url: "https://github.com/elixir-sqlite/exqlite",
|
||||
docs: docs()
|
||||
]
|
||||
end
|
||||
|
||||
# Run "mix help compile.app" to learn about applications.
|
||||
def application do
|
||||
[
|
||||
extra_applications: [:logger]
|
||||
]
|
||||
end
|
||||
|
||||
# Run "mix help deps" to learn about dependencies.
|
||||
defp deps do
|
||||
[
|
||||
{:db_connection, "~> 2.1"},
|
||||
{:ex_sqlean, "~> 0.8.5", only: [:dev, :test]},
|
||||
{:elixir_make, "~> 0.8", runtime: false},
|
||||
{:cc_precompiler, "~> 0.1", runtime: false},
|
||||
{:ex_doc, "~> 0.27", only: :dev, runtime: false},
|
||||
{:temp, "~> 0.4", only: [:dev, :test]},
|
||||
{:credo, "~> 1.6", only: [:dev, :test], runtime: false},
|
||||
{:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false},
|
||||
{:table, "~> 0.1.0", optional: true}
|
||||
]
|
||||
end
|
||||
|
||||
defp aliases do
|
||||
[
|
||||
lint: ["format --check-formatted", "credo --all", "dialyzer"]
|
||||
]
|
||||
end
|
||||
|
||||
defp description do
|
||||
"An Elixir SQLite3 library"
|
||||
end
|
||||
|
||||
defp make_precompiler do
|
||||
if System.get_env("EXQLITE_USE_SYSTEM") != nil do
|
||||
nil
|
||||
else
|
||||
{:nif, CCPrecompiler}
|
||||
end
|
||||
end
|
||||
|
||||
defp package do
|
||||
[
|
||||
files: ~w(
|
||||
lib
|
||||
.formatter.exs
|
||||
mix.exs
|
||||
README.md
|
||||
LICENSE
|
||||
.clang-format
|
||||
c_src
|
||||
Makefile*
|
||||
checksum.exs
|
||||
),
|
||||
name: "exqlite",
|
||||
licenses: ["MIT"],
|
||||
links: %{
|
||||
"GitHub" => "https://github.com/elixir-sqlite/exqlite",
|
||||
"Changelog" => "https://github.com/elixir-sqlite/exqlite/blob/main/CHANGELOG.md"
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
defp docs do
|
||||
[
|
||||
main: "readme",
|
||||
extras: docs_extras(),
|
||||
source_ref: "v#{@version}",
|
||||
source_url: "https://github.com/elixir-sqlite/exqlite"
|
||||
]
|
||||
end
|
||||
|
||||
defp docs_extras do
|
||||
[
|
||||
"README.md": [title: "Readme"],
|
||||
"guides/windows.md": [],
|
||||
"CHANGELOG.md": []
|
||||
]
|
||||
end
|
||||
|
||||
defp elixirc_paths(:test), do: ["lib", "test/support"]
|
||||
defp elixirc_paths(_), do: ["lib"]
|
||||
|
||||
defp test_paths(nil), do: ["test"]
|
||||
defp test_paths(_any), do: ["integration_test/exqlite"]
|
||||
|
||||
defp dialyzer do
|
||||
[
|
||||
plt_add_deps: :apps_direct,
|
||||
plt_add_apps: ~w(table)a
|
||||
]
|
||||
end
|
||||
|
||||
def make_precompiler_nif_versions do
|
||||
[
|
||||
versions: ["2.16", "2.17"]
|
||||
]
|
||||
end
|
||||
|
||||
defp cc_precompiler do
|
||||
[
|
||||
cleanup: "clean",
|
||||
compilers: %{
|
||||
{:unix, :linux} => %{
|
||||
:include_default_ones => true,
|
||||
"x86_64-linux-musl" => "x86_64-linux-musl-",
|
||||
"aarch64-linux-musl" => "aarch64-linux-musl-",
|
||||
"riscv64-linux-musl" => "riscv64-linux-musl-"
|
||||
},
|
||||
{:unix, :darwin} => %{
|
||||
:include_default_ones => true
|
||||
},
|
||||
{:win32, :nt} => %{
|
||||
:include_default_ones => true
|
||||
}
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user