Version History
1.0.87.0 - June XX, 2013 (release scheduled)
+ - Add all the necessary infrastructure to allow virtual tables to be implemented in managed code. Fix for [9a544991be].
- The DbType to type name translation needs to prioritize the Entity Framework type names. Fix for [47f4bac575].
- Add DateTimeFormatString connection string property to allow the DateTime format string used for all parsing and formatting to be overridden.
- Disable use of the new connection string parsing algorithm when the No_SQLiteConnectionNewParser environment variable is set. Pursuant to [bbdda6eae2].
1.0.86.0 - May 23, 2013
Index: Doc/buildChm.tcl
==================================================================
--- Doc/buildChm.tcl
+++ Doc/buildChm.tcl
@@ -80,12 +80,14 @@
puts stdout "Cannot find XML doc file: $xmlDocFile"
exit 1
}
set data [readFile $xmlDocFile]
+set count 0
+
set pattern { cref="([A-Z]):System\.Data\.SQLite\.}
-set count [regsub -all -- $pattern $data { cref="\1:system.Data.SQLite.} data]
+incr count [regsub -all -- $pattern $data { cref="\1:system.Data.SQLite.} data]
if {$count > 0} then {
writeFile $xmlDocFile $data
} else {
puts stdout "*WARNING* File \"$xmlDocFile\" does not match: $pattern"
@@ -102,19 +104,30 @@
puts stdout $result; if {$code != 0} then {exit $code}
set fileNames [list SQLite.NET.hhp SQLite.NET.hhc]
-set exps(.hhc,1) {
}
+foreach fileName [glob -nocomplain [file join $outputPath *.html]] {
+ lappend fileNames [file tail $fileName]
+}
+
+set patterns(.hhc,1) {}
+
+set patterns(.hhp,1) {Default topic=~System\.Data\.SQLite\.html}
+
+set patterns(.hhp,2) \
+ {"~System\.Data\.SQLite\.html","~System\.Data\.SQLite\.html",,,,,}
-set exps(.hhp,1) {Default topic=~System\.Data\.SQLite\.html}
-set exps(.hhp,2) {"~System\.Data\.SQLite\.html","~System\.Data\.SQLite\.html",,,,,}
+set patterns(.html,1) \
+ {"http://msdn\.microsoft\.com/en-us/library/(System\.Data\.SQLite\.(?:.*?))\(VS\.\d+\)\.aspx"}
set subSpecs(.hhc,1) [readFileAsSubSpec [file join $path SQLite.NET.hhc]]
set subSpecs(.hhp,1) {Default topic=welcome.html}
set subSpecs(.hhp,2) {"welcome.html","welcome.html",,,,,}
+
+set subSpecs(.html,1) {"System.Data.SQLite~\1.html"}
foreach fileName $fileNames {
set fileName [file join $path $outputPath $fileName]
#
@@ -133,24 +146,24 @@
#
# NOTE: No replacements have been performed yet.
#
set count 0
- foreach name [lsort [array names exps [file extension $fileName],*]] {
- set exp $exps($name)
+ foreach name [lsort [array names patterns [file extension $fileName],*]] {
+ set pattern $patterns($name)
set subSpec ""
if {[info exists subSpecs($name)]} then {
set subSpec $subSpecs($name)
}
- set expCount [regsub -- $exp $data $subSpec data]
+ set patternCount [regsub -all -- $pattern $data $subSpec data]
- if {$expCount > 0} then {
- incr count $expCount
+ if {$patternCount > 0} then {
+ incr count $patternCount
} else {
- puts stdout "*WARNING* File \"$fileName\" does not match: $exp"
+ puts stdout "*WARNING* File \"$fileName\" does not match: $pattern"
}
}
#
# NOTE: If we actually performed some replacements, rewrite the file.
Index: SQLite.Interop/SQLite.Interop.2005.vcproj
==================================================================
--- SQLite.Interop/SQLite.Interop.2005.vcproj
+++ SQLite.Interop/SQLite.Interop.2005.vcproj
@@ -51,10 +51,11 @@
Name="VCMIDLTool"
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
true
Disabled
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;_DEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_DEBUG_DEFINES);$(INTEROP_EXTRA_DEFINES);$(INTEROP_DEBUG_DEFINES);%(PreprocessorDefinitions)
false
Default
MultiThreadedDebugDLL
Level4
@@ -169,10 +170,11 @@
Disabled
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;x64;_DEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_DEBUG_DEFINES);$(INTEROP_EXTRA_DEFINES);$(INTEROP_DEBUG_DEFINES);%(PreprocessorDefinitions)
false
Default
MultiThreadedDebugDLL
Level4
@@ -211,10 +213,11 @@
Disabled
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;_DEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_DEBUG_DEFINES);$(INTEROP_EXTRA_DEFINES);$(INTEROP_DEBUG_DEFINES);%(PreprocessorDefinitions)
false
Default
MultiThreadedDebugDLL
Level4
@@ -246,10 +249,11 @@
Disabled
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;x64;_DEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_DEBUG_DEFINES);$(INTEROP_EXTRA_DEFINES);$(INTEROP_DEBUG_DEFINES);%(PreprocessorDefinitions)
false
Default
MultiThreadedDebugDLL
Level4
@@ -283,10 +287,11 @@
Full
true
Speed
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;NDEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_RELEASE_DEFINES);$(INTEROP_EXTRA_DEFINES);%(PreprocessorDefinitions)
false
Default
true
MultiThreadedDLL
@@ -327,10 +332,11 @@
Full
true
Speed
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;x64;NDEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_RELEASE_DEFINES);$(INTEROP_EXTRA_DEFINES);%(PreprocessorDefinitions)
false
Default
true
MultiThreadedDLL
@@ -371,10 +377,11 @@
Full
true
Speed
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;NDEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_RELEASE_DEFINES);$(INTEROP_EXTRA_DEFINES);%(PreprocessorDefinitions)
false
Default
true
MultiThreadedDLL
@@ -409,10 +416,11 @@
Full
true
Speed
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;x64;NDEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_RELEASE_DEFINES);$(INTEROP_EXTRA_DEFINES);%(PreprocessorDefinitions)
false
Default
true
MultiThreadedDLL
@@ -452,10 +460,13 @@
true
true
+
+ true
+
true
Index: SQLite.Interop/SQLite.Interop.2010.vcxproj.filters
==================================================================
--- SQLite.Interop/SQLite.Interop.2010.vcxproj.filters
+++ SQLite.Interop/SQLite.Interop.2010.vcxproj.filters
@@ -32,10 +32,13 @@
Source Files
Source Files
+
+
+ Source Files
Source Files
Index: SQLite.Interop/SQLite.Interop.2012.vcxproj
==================================================================
--- SQLite.Interop/SQLite.Interop.2012.vcxproj
+++ SQLite.Interop/SQLite.Interop.2012.vcxproj
@@ -134,10 +134,11 @@
true
Disabled
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;_DEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_DEBUG_DEFINES);$(INTEROP_EXTRA_DEFINES);$(INTEROP_DEBUG_DEFINES);%(PreprocessorDefinitions)
false
Default
MultiThreadedDebugDLL
Level4
@@ -176,10 +177,11 @@
Disabled
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;x64;_DEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_DEBUG_DEFINES);$(INTEROP_EXTRA_DEFINES);$(INTEROP_DEBUG_DEFINES);%(PreprocessorDefinitions)
false
Default
MultiThreadedDebugDLL
Level4
@@ -218,10 +220,11 @@
Disabled
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;_DEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_DEBUG_DEFINES);$(INTEROP_EXTRA_DEFINES);$(INTEROP_DEBUG_DEFINES);%(PreprocessorDefinitions)
false
Default
MultiThreadedDebugDLL
Level4
@@ -253,10 +256,11 @@
Disabled
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;x64;_DEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_DEBUG_DEFINES);$(INTEROP_EXTRA_DEFINES);$(INTEROP_DEBUG_DEFINES);%(PreprocessorDefinitions)
false
Default
MultiThreadedDebugDLL
Level4
@@ -290,10 +294,11 @@
Full
true
Speed
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;NDEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_RELEASE_DEFINES);$(INTEROP_EXTRA_DEFINES);%(PreprocessorDefinitions)
false
Default
true
MultiThreadedDLL
@@ -334,10 +339,11 @@
Full
true
Speed
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;x64;NDEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_RELEASE_DEFINES);$(INTEROP_EXTRA_DEFINES);%(PreprocessorDefinitions)
false
Default
true
MultiThreadedDLL
@@ -378,10 +384,11 @@
Full
true
Speed
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;NDEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_RELEASE_DEFINES);$(INTEROP_EXTRA_DEFINES);%(PreprocessorDefinitions)
false
Default
true
MultiThreadedDLL
@@ -416,10 +423,11 @@
Full
true
Speed
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;x64;NDEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_RELEASE_DEFINES);$(INTEROP_EXTRA_DEFINES);%(PreprocessorDefinitions)
false
Default
true
MultiThreadedDLL
@@ -459,10 +467,13 @@
true
true
+
+ true
+
true
Index: SQLite.Interop/SQLite.Interop.2012.vcxproj.filters
==================================================================
--- SQLite.Interop/SQLite.Interop.2012.vcxproj.filters
+++ SQLite.Interop/SQLite.Interop.2012.vcxproj.filters
@@ -32,10 +32,13 @@
Source Files
Source Files
+
+
+ Source Files
Source Files
Index: SQLite.Interop/SQLite.Interop.CE.2005.vcproj
==================================================================
--- SQLite.Interop/SQLite.Interop.CE.2005.vcproj
+++ SQLite.Interop/SQLite.Interop.CE.2005.vcproj
@@ -55,10 +55,11 @@
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
true
Disabled
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;_DEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_DEBUG_DEFINES);$(INTEROP_EXTRA_DEFINES);$(INTEROP_DEBUG_DEFINES);%(PreprocessorDefinitions)
false
Default
MultiThreadedDebug
Level4
@@ -169,10 +170,11 @@
Disabled
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;x64;_DEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_DEBUG_DEFINES);$(INTEROP_EXTRA_DEFINES);$(INTEROP_DEBUG_DEFINES);%(PreprocessorDefinitions)
false
Default
MultiThreadedDebug
Level4
@@ -211,10 +213,11 @@
Disabled
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;_DEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_DEBUG_DEFINES);$(INTEROP_EXTRA_DEFINES);$(INTEROP_DEBUG_DEFINES);%(PreprocessorDefinitions)
false
Default
MultiThreadedDebug
Level4
@@ -246,10 +249,11 @@
Disabled
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;x64;_DEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_DEBUG_DEFINES);$(INTEROP_EXTRA_DEFINES);$(INTEROP_DEBUG_DEFINES);%(PreprocessorDefinitions)
false
Default
MultiThreadedDebug
Level4
@@ -283,10 +287,11 @@
Full
true
Speed
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;NDEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_RELEASE_DEFINES);$(INTEROP_EXTRA_DEFINES);%(PreprocessorDefinitions)
false
Default
true
MultiThreaded
@@ -327,10 +332,11 @@
Full
true
Speed
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;x64;NDEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_RELEASE_DEFINES);$(INTEROP_EXTRA_DEFINES);%(PreprocessorDefinitions)
false
Default
true
MultiThreaded
@@ -371,10 +377,11 @@
Full
true
Speed
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;NDEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_RELEASE_DEFINES);$(INTEROP_EXTRA_DEFINES);%(PreprocessorDefinitions)
false
Default
true
MultiThreaded
@@ -409,10 +416,11 @@
Full
true
Speed
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;x64;NDEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_RELEASE_DEFINES);$(INTEROP_EXTRA_DEFINES);%(PreprocessorDefinitions)
false
Default
true
MultiThreaded
@@ -452,10 +460,13 @@
true
true
+
+ true
+
true
Index: SQLite.Interop/SQLite.Interop.Static.2010.vcxproj.filters
==================================================================
--- SQLite.Interop/SQLite.Interop.Static.2010.vcxproj.filters
+++ SQLite.Interop/SQLite.Interop.Static.2010.vcxproj.filters
@@ -32,10 +32,13 @@
Source Files
Source Files
+
+
+ Source Files
Source Files
Index: SQLite.Interop/SQLite.Interop.Static.2012.vcxproj
==================================================================
--- SQLite.Interop/SQLite.Interop.Static.2012.vcxproj
+++ SQLite.Interop/SQLite.Interop.Static.2012.vcxproj
@@ -134,10 +134,11 @@
true
Disabled
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;_DEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_DEBUG_DEFINES);$(INTEROP_EXTRA_DEFINES);$(INTEROP_DEBUG_DEFINES);%(PreprocessorDefinitions)
false
Default
MultiThreadedDebug
Level4
@@ -176,10 +177,11 @@
Disabled
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;x64;_DEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_DEBUG_DEFINES);$(INTEROP_EXTRA_DEFINES);$(INTEROP_DEBUG_DEFINES);%(PreprocessorDefinitions)
false
Default
MultiThreadedDebug
Level4
@@ -218,10 +220,11 @@
Disabled
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;_DEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_DEBUG_DEFINES);$(INTEROP_EXTRA_DEFINES);$(INTEROP_DEBUG_DEFINES);%(PreprocessorDefinitions)
false
Default
MultiThreadedDebug
Level4
@@ -253,10 +256,11 @@
Disabled
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;x64;_DEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_DEBUG_DEFINES);$(INTEROP_EXTRA_DEFINES);$(INTEROP_DEBUG_DEFINES);%(PreprocessorDefinitions)
false
Default
MultiThreadedDebug
Level4
@@ -290,10 +294,11 @@
Full
true
Speed
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;NDEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_RELEASE_DEFINES);$(INTEROP_EXTRA_DEFINES);%(PreprocessorDefinitions)
false
Default
true
MultiThreaded
@@ -334,10 +339,11 @@
Full
true
Speed
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;x64;NDEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_RELEASE_DEFINES);$(INTEROP_EXTRA_DEFINES);%(PreprocessorDefinitions)
false
Default
true
MultiThreaded
@@ -378,10 +384,11 @@
Full
true
Speed
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;NDEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_RELEASE_DEFINES);$(INTEROP_EXTRA_DEFINES);%(PreprocessorDefinitions)
false
Default
true
MultiThreaded
@@ -416,10 +423,11 @@
Full
true
Speed
+ $(INTEROP_INCLUDE_DIRECTORIES);%(AdditionalIncludeDirectories)
WIN32;x64;NDEBUG;_WINDOWS;_USRDLL;$(SQLITE_COMMON_DEFINES);$(SQLITE_EXTRA_DEFINES);$(SQLITE_RELEASE_DEFINES);$(INTEROP_EXTRA_DEFINES);%(PreprocessorDefinitions)
false
Default
true
MultiThreaded
@@ -459,10 +467,13 @@
true
true
+
+ true
+
true
Index: SQLite.Interop/SQLite.Interop.Static.2012.vcxproj.filters
==================================================================
--- SQLite.Interop/SQLite.Interop.Static.2012.vcxproj.filters
+++ SQLite.Interop/SQLite.Interop.Static.2012.vcxproj.filters
@@ -32,10 +32,13 @@
Source Files
Source Files
+
+
+ Source Files
Source Files
Index: SQLite.Interop/props/SQLite.Interop.2005.vsprops
==================================================================
--- SQLite.Interop/props/SQLite.Interop.2005.vsprops
+++ SQLite.Interop/props/SQLite.Interop.2005.vsprops
@@ -35,18 +35,23 @@
+
+
2010
087
1.0
1.0.87.0
1,0,87,0
+ src\core
INTEROP_DEBUG=0x31F;INTEROP_LOG=1;INTEROP_TEST_EXTENSION=1
- INTEROP_EXTENSION_FUNCTIONS=1;INTEROP_CODEC=1
+ INTEROP_EXTENSION_FUNCTIONS=1;INTEROP_CODEC=1;INTEROP_VIRTUAL_TABLE=1
/ASSEMBLYRESOURCE:..\System.Data.SQLite\SQLiteCommand.bmp,System.Data.SQLite.SQLiteCommand.bmp /ASSEMBLYRESOURCE:..\System.Data.SQLite\SQLiteConnection.bmp,System.Data.SQLite.SQLiteConnection.bmp /ASSEMBLYRESOURCE:..\System.Data.SQLite\SQLiteDataAdapter.bmp,System.Data.SQLite.SQLiteDataAdapter.bmp
$(ProjectDir)..\System.Data.SQLite\System.Data.SQLite.snk
SQLite.Interop
System.Data.SQLite
@@ -39,10 +40,14 @@
true
$(INTEROP_RC_VERSION)
true
+
+
+ $(INTEROP_INCLUDE_DIRECTORIES)
+ true
$(INTEROP_DEBUG_DEFINES)
true
Index: SQLite.Interop/props/SQLite.Interop.2012.props
==================================================================
--- SQLite.Interop/props/SQLite.Interop.2012.props
+++ SQLite.Interop/props/SQLite.Interop.2012.props
@@ -12,12 +12,13 @@
2012
087
1.0
1.0.87.0
1,0,87,0
+ src\core
INTEROP_DEBUG=0x31F;INTEROP_LOG=1;INTEROP_TEST_EXTENSION=1
- INTEROP_EXTENSION_FUNCTIONS=1;INTEROP_CODEC=1
+ INTEROP_EXTENSION_FUNCTIONS=1;INTEROP_CODEC=1;INTEROP_VIRTUAL_TABLE=1
/ASSEMBLYRESOURCE:..\System.Data.SQLite\SQLiteCommand.bmp,System.Data.SQLite.SQLiteCommand.bmp /ASSEMBLYRESOURCE:..\System.Data.SQLite\SQLiteConnection.bmp,System.Data.SQLite.SQLiteConnection.bmp /ASSEMBLYRESOURCE:..\System.Data.SQLite\SQLiteDataAdapter.bmp,System.Data.SQLite.SQLiteDataAdapter.bmp
$(ProjectDir)..\System.Data.SQLite\System.Data.SQLite.snk
SQLite.Interop
System.Data.SQLite
@@ -39,10 +40,14 @@
true
$(INTEROP_RC_VERSION)
true
+
+
+ $(INTEROP_INCLUDE_DIRECTORIES)
+ true
$(INTEROP_DEBUG_DEFINES)
true
ADDED SQLite.Interop/src/ext/vtshim.c
Index: SQLite.Interop/src/ext/vtshim.c
==================================================================
--- /dev/null
+++ SQLite.Interop/src/ext/vtshim.c
@@ -0,0 +1,547 @@
+/*
+** 2013-06-12
+**
+** 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.
+**
+*************************************************************************
+**
+** A shim that sits between the SQLite virtual table interface and
+** runtimes with garbage collector based memory management.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include
+#include
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/* Forward references */
+typedef struct vtshim_aux vtshim_aux;
+typedef struct vtshim_vtab vtshim_vtab;
+typedef struct vtshim_cursor vtshim_cursor;
+
+
+/* The vtshim_aux argument is the auxiliary parameter that is passed
+** into sqlite3_create_module_v2().
+*/
+struct vtshim_aux {
+ void *pChildAux; /* pAux for child virtual tables */
+ void (*xChildDestroy)(void*); /* Destructor for pChildAux */
+ sqlite3_module *pMod; /* Methods for child virtual tables */
+ sqlite3 *db; /* The database to which we are attached */
+ char *zName; /* Name of the module */
+ int bDisposed; /* True if disposed */
+ vtshim_vtab *pAllVtab; /* List of all vtshim_vtab objects */
+ sqlite3_module sSelf; /* Methods used by this shim */
+};
+
+/* A vtshim virtual table object */
+struct vtshim_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ sqlite3_vtab *pChild; /* Child virtual table */
+ vtshim_aux *pAux; /* Pointer to vtshim_aux object */
+ vtshim_cursor *pAllCur; /* List of all cursors */
+ vtshim_vtab **ppPrev; /* Previous on list */
+ vtshim_vtab *pNext; /* Next on list */
+};
+
+/* A vtshim cursor object */
+struct vtshim_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3_vtab_cursor *pChild; /* Cursor generated by the managed subclass */
+ vtshim_cursor **ppPrev; /* Previous on list of all cursors */
+ vtshim_cursor *pNext; /* Next on list of all cursors */
+};
+
+/* Macro used to copy the child vtable error message to outer vtable */
+#define VTSHIM_COPY_ERRMSG() \
+ do { \
+ sqlite3_free(pVtab->base.zErrMsg); \
+ pVtab->base.zErrMsg = sqlite3_mprintf("%s", pVtab->pChild->zErrMsg); \
+ } while (0)
+
+/* Methods for the vtshim module */
+static int vtshimCreate(
+ sqlite3 *db,
+ void *ppAux,
+ int argc,
+ const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ vtshim_aux *pAux = (vtshim_aux*)ppAux;
+ vtshim_vtab *pNew;
+ int rc;
+
+ assert( db==pAux->db );
+ if( pAux->bDisposed ){
+ if( pzErr ){
+ *pzErr = sqlite3_mprintf("virtual table was disposed: \"%s\"",
+ pAux->zName);
+ }
+ return SQLITE_ERROR;
+ }
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ rc = pAux->pMod->xCreate(db, pAux->pChildAux, argc, argv,
+ &pNew->pChild, pzErr);
+ if( rc ){
+ sqlite3_free(pNew);
+ *ppVtab = 0;
+ }
+ pNew->pAux = pAux;
+ pNew->ppPrev = &pAux->pAllVtab;
+ pNew->pNext = pAux->pAllVtab;
+ if( pAux->pAllVtab ) pAux->pAllVtab->ppPrev = &pNew->pNext;
+ pAux->pAllVtab = pNew;
+ return rc;
+}
+
+static int vtshimConnect(
+ sqlite3 *db,
+ void *ppAux,
+ int argc,
+ const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ vtshim_aux *pAux = (vtshim_aux*)ppAux;
+ vtshim_vtab *pNew;
+ int rc;
+
+ assert( db==pAux->db );
+ if( pAux->bDisposed ){
+ if( pzErr ){
+ *pzErr = sqlite3_mprintf("virtual table was disposed: \"%s\"",
+ pAux->zName);
+ }
+ return SQLITE_ERROR;
+ }
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ rc = pAux->pMod->xConnect(db, pAux->pChildAux, argc, argv,
+ &pNew->pChild, pzErr);
+ if( rc ){
+ sqlite3_free(pNew);
+ *ppVtab = 0;
+ }
+ pNew->pAux = pAux;
+ pNew->ppPrev = &pAux->pAllVtab;
+ pNew->pNext = pAux->pAllVtab;
+ if( pAux->pAllVtab ) pAux->pAllVtab->ppPrev = &pNew->pNext;
+ pAux->pAllVtab = pNew;
+ return rc;
+}
+
+static int vtshimBestIndex(
+ sqlite3_vtab *pBase,
+ sqlite3_index_info *pIdxInfo
+){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xBestIndex(pVtab->pChild, pIdxInfo);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimDisconnect(sqlite3_vtab *pBase){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc = SQLITE_OK;
+ if( !pAux->bDisposed ){
+ rc = pAux->pMod->xDisconnect(pVtab->pChild);
+ }
+ if( pVtab->pNext ) pVtab->pNext->ppPrev = pVtab->ppPrev;
+ *pVtab->ppPrev = pVtab->pNext;
+ sqlite3_free(pVtab);
+ return rc;
+}
+
+static int vtshimDestroy(sqlite3_vtab *pBase){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc = SQLITE_OK;
+ if( !pAux->bDisposed ){
+ rc = pAux->pMod->xDestroy(pVtab->pChild);
+ }
+ if( pVtab->pNext ) pVtab->pNext->ppPrev = pVtab->ppPrev;
+ *pVtab->ppPrev = pVtab->pNext;
+ sqlite3_free(pVtab);
+ return rc;
+}
+
+static int vtshimOpen(sqlite3_vtab *pBase, sqlite3_vtab_cursor **ppCursor){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ vtshim_cursor *pCur;
+ int rc;
+ *ppCursor = 0;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ rc = pAux->pMod->xOpen(pVtab->pChild, &pCur->pChild);
+ if( rc ){
+ sqlite3_free(pCur);
+ VTSHIM_COPY_ERRMSG();
+ return rc;
+ }
+ pCur->pChild->pVtab = pVtab->pChild;
+ *ppCursor = &pCur->base;
+ pCur->ppPrev = &pVtab->pAllCur;
+ if( pVtab->pAllCur ) pVtab->pAllCur->ppPrev = &pCur->pNext;
+ pCur->pNext = pVtab->pAllCur;
+ pVtab->pAllCur = pCur;
+ return SQLITE_OK;
+}
+
+static int vtshimClose(sqlite3_vtab_cursor *pX){
+ vtshim_cursor *pCur = (vtshim_cursor*)pX;
+ vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc = SQLITE_OK;
+ if( !pAux->bDisposed ){
+ rc = pAux->pMod->xClose(pCur->pChild);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ }
+ if( pCur->pNext ) pCur->pNext->ppPrev = pCur->ppPrev;
+ *pCur->ppPrev = pCur->pNext;
+ sqlite3_free(pCur);
+ return rc;
+}
+
+static int vtshimFilter(
+ sqlite3_vtab_cursor *pX,
+ int idxNum,
+ const char *idxStr,
+ int argc,
+ sqlite3_value **argv
+){
+ vtshim_cursor *pCur = (vtshim_cursor*)pX;
+ vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xFilter(pCur->pChild, idxNum, idxStr, argc, argv);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimNext(sqlite3_vtab_cursor *pX){
+ vtshim_cursor *pCur = (vtshim_cursor*)pX;
+ vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xNext(pCur->pChild);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimEof(sqlite3_vtab_cursor *pX){
+ vtshim_cursor *pCur = (vtshim_cursor*)pX;
+ vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return 1;
+ rc = pAux->pMod->xEof(pCur->pChild);
+ VTSHIM_COPY_ERRMSG();
+ return rc;
+}
+
+static int vtshimColumn(sqlite3_vtab_cursor *pX, sqlite3_context *ctx, int i){
+ vtshim_cursor *pCur = (vtshim_cursor*)pX;
+ vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xColumn(pCur->pChild, ctx, i);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimRowid(sqlite3_vtab_cursor *pX, sqlite3_int64 *pRowid){
+ vtshim_cursor *pCur = (vtshim_cursor*)pX;
+ vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xRowid(pCur->pChild, pRowid);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimUpdate(
+ sqlite3_vtab *pBase,
+ int argc,
+ sqlite3_value **argv,
+ sqlite3_int64 *pRowid
+){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xUpdate(pVtab->pChild, argc, argv, pRowid);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimBegin(sqlite3_vtab *pBase){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xBegin(pVtab->pChild);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimSync(sqlite3_vtab *pBase){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xSync(pVtab->pChild);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimCommit(sqlite3_vtab *pBase){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xCommit(pVtab->pChild);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimRollback(sqlite3_vtab *pBase){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xRollback(pVtab->pChild);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimFindFunction(
+ sqlite3_vtab *pBase,
+ int nArg,
+ const char *zName,
+ void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
+ void **ppArg
+){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return 0;
+ rc = pAux->pMod->xFindFunction(pVtab->pChild, nArg, zName, pxFunc, ppArg);
+ VTSHIM_COPY_ERRMSG();
+ return rc;
+}
+
+static int vtshimRename(sqlite3_vtab *pBase, const char *zNewName){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xRename(pVtab->pChild, zNewName);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimSavepoint(sqlite3_vtab *pBase, int n){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xSavepoint(pVtab->pChild, n);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimRelease(sqlite3_vtab *pBase, int n){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xRelease(pVtab->pChild, n);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimRollbackTo(sqlite3_vtab *pBase, int n){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xRollbackTo(pVtab->pChild, n);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+/* The destructor function for a disposible module */
+static void vtshimAuxDestructor(void *pXAux){
+ vtshim_aux *pAux = (vtshim_aux*)pXAux;
+ assert( pAux->pAllVtab==0 );
+ if( !pAux->bDisposed && pAux->xChildDestroy ){
+ pAux->xChildDestroy(pAux->pChildAux);
+ }
+ sqlite3_free(pAux->zName);
+ sqlite3_free(pAux->pMod);
+ sqlite3_free(pAux);
+}
+
+static int vtshimCopyModule(
+ const sqlite3_module *pMod, /* Source module to be copied */
+ sqlite3_module **ppMod /* Destination for copied module */
+){
+ sqlite3_module *p;
+ if( !pMod || !ppMod ) return SQLITE_ERROR;
+ p = sqlite3_malloc( sizeof(*p) );
+ if( p==0 ) return SQLITE_NOMEM;
+ memcpy(p, pMod, sizeof(*p));
+ *ppMod = p;
+ return SQLITE_OK;
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+void *sqlite3_create_disposable_module(
+ sqlite3 *db, /* SQLite connection to register module with */
+ const char *zName, /* Name of the module */
+ const sqlite3_module *p, /* Methods for the module */
+ void *pClientData, /* Client data for xCreate/xConnect */
+ void(*xDestroy)(void*) /* Module destructor function */
+){
+ vtshim_aux *pAux;
+ sqlite3_module *pMod;
+ int rc;
+ pAux = sqlite3_malloc( sizeof(*pAux) );
+ if( pAux==0 ){
+ if( xDestroy ) xDestroy(pClientData);
+ return 0;
+ }
+ rc = vtshimCopyModule(p, &pMod);
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(pAux);
+ return 0;
+ }
+ pAux->pChildAux = pClientData;
+ pAux->xChildDestroy = xDestroy;
+ pAux->pMod = pMod;
+ pAux->db = db;
+ pAux->zName = sqlite3_mprintf("%s", zName);
+ pAux->bDisposed = 0;
+ pAux->pAllVtab = 0;
+ pAux->sSelf.iVersion = p->iVersion<=2 ? p->iVersion : 2;
+ pAux->sSelf.xCreate = p->xCreate ? vtshimCreate : 0;
+ pAux->sSelf.xConnect = p->xConnect ? vtshimConnect : 0;
+ pAux->sSelf.xBestIndex = p->xBestIndex ? vtshimBestIndex : 0;
+ pAux->sSelf.xDisconnect = p->xDisconnect ? vtshimDisconnect : 0;
+ pAux->sSelf.xDestroy = p->xDestroy ? vtshimDestroy : 0;
+ pAux->sSelf.xOpen = p->xOpen ? vtshimOpen : 0;
+ pAux->sSelf.xClose = p->xClose ? vtshimClose : 0;
+ pAux->sSelf.xFilter = p->xFilter ? vtshimFilter : 0;
+ pAux->sSelf.xNext = p->xNext ? vtshimNext : 0;
+ pAux->sSelf.xEof = p->xEof ? vtshimEof : 0;
+ pAux->sSelf.xColumn = p->xColumn ? vtshimColumn : 0;
+ pAux->sSelf.xRowid = p->xRowid ? vtshimRowid : 0;
+ pAux->sSelf.xUpdate = p->xUpdate ? vtshimUpdate : 0;
+ pAux->sSelf.xBegin = p->xBegin ? vtshimBegin : 0;
+ pAux->sSelf.xSync = p->xSync ? vtshimSync : 0;
+ pAux->sSelf.xCommit = p->xCommit ? vtshimCommit : 0;
+ pAux->sSelf.xRollback = p->xRollback ? vtshimRollback : 0;
+ pAux->sSelf.xFindFunction = p->xFindFunction ? vtshimFindFunction : 0;
+ pAux->sSelf.xRename = p->xRename ? vtshimRename : 0;
+ if( p->iVersion>=2 ){
+ pAux->sSelf.xSavepoint = p->xSavepoint ? vtshimSavepoint : 0;
+ pAux->sSelf.xRelease = p->xRelease ? vtshimRelease : 0;
+ pAux->sSelf.xRollbackTo = p->xRollbackTo ? vtshimRollbackTo : 0;
+ }else{
+ pAux->sSelf.xSavepoint = 0;
+ pAux->sSelf.xRelease = 0;
+ pAux->sSelf.xRollbackTo = 0;
+ }
+ rc = sqlite3_create_module_v2(db, zName, &pAux->sSelf,
+ pAux, vtshimAuxDestructor);
+ return rc==SQLITE_OK ? (void*)pAux : 0;
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+void sqlite3_dispose_module(void *pX){
+ vtshim_aux *pAux = (vtshim_aux*)pX;
+ if( !pAux->bDisposed ){
+ vtshim_vtab *pVtab;
+ vtshim_cursor *pCur;
+ for(pVtab=pAux->pAllVtab; pVtab; pVtab=pVtab->pNext){
+ for(pCur=pVtab->pAllCur; pCur; pCur=pCur->pNext){
+ pAux->pMod->xClose(pCur->pChild);
+ }
+ pAux->pMod->xDisconnect(pVtab->pChild);
+ }
+ pAux->bDisposed = 1;
+ if( pAux->xChildDestroy ) pAux->xChildDestroy(pAux->pChildAux);
+ }
+}
+
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_vtshim_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi);
+ return SQLITE_OK;
+}
Index: SQLite.Interop/src/win/interop.c
==================================================================
--- SQLite.Interop/src/win/interop.c
+++ SQLite.Interop/src/win/interop.c
@@ -6,10 +6,14 @@
********************************************************/
#define SQLITE_API __declspec(dllexport)
#include "../core/sqlite3.c"
+
+#if defined(INTEROP_VIRTUAL_TABLE)
+#include "../ext/vtshim.c"
+#endif
#if defined(INTEROP_EXTENSION_FUNCTIONS)
#include "../contrib/extension-functions.c"
extern int RegisterExtensionFunctions(sqlite3 *db);
#endif
@@ -74,10 +78,14 @@
SQLITE_PRIVATE void sqlite3InteropLogCallback(void *pArg, int iCode, const char *zMsg){
sqlite3InteropDebug("INTEROP_LOG (%d) %s\n", iCode, zMsg);
}
#endif
+
+SQLITE_API int WINAPI sqlite3_malloc_size_interop(void *p){
+ return sqlite3MallocSize(p);
+}
#if defined(INTEROP_LEGACY_CLOSE) || SQLITE_VERSION_NUMBER < 3007014
SQLITE_PRIVATE void * sqlite3DbMallocZero_interop(sqlite3 *db, int n)
{
void *p;
@@ -323,10 +331,72 @@
*plen = (*pztail != 0) ? wcslen((wchar_t *)*pztail) * sizeof(wchar_t) : 0;
return n;
}
+
+SQLITE_API void *WINAPI sqlite3_create_disposable_module_interop(
+ sqlite3 *db,
+ const char *zName,
+ sqlite3_module *pModule,
+ int iVersion,
+ int (*xCreate)(sqlite3*, void *, int, const char *const*, sqlite3_vtab **, char**),
+ int (*xConnect)(sqlite3*, void *, int, const char *const*, sqlite3_vtab **, char**),
+ int (*xBestIndex)(sqlite3_vtab *, sqlite3_index_info*),
+ int (*xDisconnect)(sqlite3_vtab *),
+ int (*xDestroy)(sqlite3_vtab *),
+ int (*xOpen)(sqlite3_vtab *, sqlite3_vtab_cursor **),
+ int (*xClose)(sqlite3_vtab_cursor*),
+ int (*xFilter)(sqlite3_vtab_cursor*, int, const char *, int, sqlite3_value **),
+ int (*xNext)(sqlite3_vtab_cursor*),
+ int (*xEof)(sqlite3_vtab_cursor*),
+ int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int),
+ int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *),
+ int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *),
+ int (*xBegin)(sqlite3_vtab *),
+ int (*xSync)(sqlite3_vtab *),
+ int (*xCommit)(sqlite3_vtab *),
+ int (*xRollback)(sqlite3_vtab *),
+ int (*xFindFunction)(sqlite3_vtab *, int, const char *, void (**pxFunc)(sqlite3_context*, int, sqlite3_value**), void **ppArg),
+ int (*xRename)(sqlite3_vtab *, const char *),
+ int (*xSavepoint)(sqlite3_vtab *, int),
+ int (*xRelease)(sqlite3_vtab *, int),
+ int (*xRollbackTo)(sqlite3_vtab *, int),
+ void *pClientData,
+ void(*xDestroyModule)(void*)
+){
+ memset(pModule, 0, sizeof(*pModule));
+ pModule->iVersion = iVersion;
+ pModule->xCreate = xCreate;
+ pModule->xConnect = xConnect;
+ pModule->xBestIndex = xBestIndex;
+ pModule->xDisconnect = xDisconnect;
+ pModule->xDestroy = xDestroy;
+ pModule->xOpen = xOpen;
+ pModule->xClose = xClose;
+ pModule->xFilter = xFilter;
+ pModule->xNext = xNext;
+ pModule->xEof = xEof;
+ pModule->xColumn = xColumn;
+ pModule->xRowid = xRowid;
+ pModule->xUpdate = xUpdate;
+ pModule->xBegin = xBegin;
+ pModule->xSync = xSync;
+ pModule->xCommit = xCommit;
+ pModule->xRollback = xRollback;
+ pModule->xFindFunction = xFindFunction;
+ pModule->xRename = xRename;
+ pModule->xSavepoint = xSavepoint;
+ pModule->xRelease = xRelease;
+ pModule->xRollbackTo = xRollbackTo;
+ return sqlite3_create_disposable_module(db, zName, pModule, pClientData, xDestroyModule);
+}
+
+SQLITE_API void WINAPI sqlite3_dispose_module_interop(void *pModule)
+{
+ sqlite3_dispose_module(pModule);
+}
SQLITE_API int WINAPI sqlite3_bind_double_interop(sqlite3_stmt *stmt, int iCol, double *val)
{
return sqlite3_bind_double(stmt,iCol,*val);
}
Index: SQLite.NET.Settings.targets
==================================================================
--- SQLite.NET.Settings.targets
+++ SQLite.NET.Settings.targets
@@ -196,10 +196,19 @@
These counts are intended to be used by the test suite to detect
possible resource leaks.
-->
false
+
+ false
+
true
false
+
+ true
+
Index: Setup/set_user_mistachkin_Debug.bat
==================================================================
--- Setup/set_user_mistachkin_Debug.bat
+++ Setup/set_user_mistachkin_Debug.bat
@@ -15,5 +15,6 @@
SET MSBUILD_ARGS=/p:CheckState=true
SET MSBUILD_ARGS=%MSBUILD_ARGS% /p:CountHandle=true
SET MSBUILD_ARGS=%MSBUILD_ARGS% /p:TraceConnection=true
SET MSBUILD_ARGS=%MSBUILD_ARGS% /p:TraceHandle=true
SET MSBUILD_ARGS=%MSBUILD_ARGS% /p:TraceStatement=true
+SET MSBUILD_ARGS=%MSBUILD_ARGS% /p:TrackMemoryBytes=true
Index: System.Data.SQLite/SQLite3.cs
==================================================================
--- System.Data.SQLite/SQLite3.cs
+++ System.Data.SQLite/SQLite3.cs
@@ -75,13 +75,60 @@
///
/// The user-defined functions registered on this connection
///
protected SQLiteFunction[] _functionsArray;
- internal SQLite3(SQLiteDateFormats fmt, DateTimeKind kind, string fmtString)
+#if INTEROP_VIRTUAL_TABLE
+ ///
+ /// The modules created using this connection.
+ ///
+ protected Dictionary _modules;
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Constructs the object used to interact with the SQLite core library
+ /// using the UTF-8 text encoding.
+ ///
+ ///
+ /// The DateTime format to be used when converting string values to a
+ /// DateTime and binding DateTime parameters.
+ ///
+ ///
+ /// The to be used when creating DateTime
+ /// values.
+ ///
+ ///
+ /// The format string to be used when parsing and formatting DateTime
+ /// values.
+ ///
+ ///
+ /// The native handle to be associated with the database connection.
+ ///
+ ///
+ /// The fully qualified file name associated with .
+ ///
+ ///
+ /// Non-zero if the newly created object instance will need to dispose
+ /// of when it is no longer needed.
+ ///
+ internal SQLite3(
+ SQLiteDateFormats fmt,
+ DateTimeKind kind,
+ string fmtString,
+ IntPtr db,
+ string fileName,
+ bool ownHandle
+ )
: base(fmt, kind, fmtString)
{
+ if (db != IntPtr.Zero)
+ {
+ _sql = new SQLiteConnectionHandle(db, ownHandle);
+ _fileName = fileName;
+ }
}
///////////////////////////////////////////////////////////////////////////////////////////////
#region IDisposable "Pattern" Members
@@ -110,10 +157,31 @@
//}
//////////////////////////////////////
// release unmanaged resources here...
//////////////////////////////////////
+
+#if INTEROP_VIRTUAL_TABLE
+ //
+ // NOTE: If any modules were created, attempt to dispose of
+ // them now. This code is designed to avoid throwing
+ // exceptions unless the Dispose method of the module
+ // itself throws an exception.
+ //
+ if (_modules != null)
+ {
+ foreach (KeyValuePair pair in _modules)
+ {
+ SQLiteModule module = pair.Value;
+
+ if (module == null)
+ continue;
+
+ module.Dispose();
+ }
+ }
+#endif
Close(false); /* Disposing, cannot throw. */
disposed = true;
}
@@ -133,10 +201,16 @@
// resources belonging to the previously-registered functions.
internal override void Close(bool canThrow)
{
if (_sql != null)
{
+ if (!_sql.OwnHandle)
+ {
+ _sql = null;
+ return;
+ }
+
if (_usePool)
{
if (SQLiteBase.ResetConnection(_sql, _sql, canThrow))
{
SQLiteConnectionPool.Add(_fileName, _sql, _poolVersion);
@@ -244,14 +318,16 @@
{
get
{
#if !PLATFORM_COMPACTFRAMEWORK
return UnsafeNativeMethods.sqlite3_last_insert_rowid(_sql);
-#else
+#elif !SQLITE_STANDARD
long rowId = 0;
UnsafeNativeMethods.sqlite3_last_insert_rowid_interop(_sql, ref rowId);
return rowId;
+#else
+ throw new NotImplementedException();
#endif
}
}
internal override int Changes
@@ -270,14 +346,16 @@
{
get
{
#if !PLATFORM_COMPACTFRAMEWORK
return UnsafeNativeMethods.sqlite3_memory_used();
-#else
+#elif !SQLITE_STANDARD
long bytes = 0;
UnsafeNativeMethods.sqlite3_memory_used_interop(ref bytes);
return bytes;
+#else
+ throw new NotImplementedException();
#endif
}
}
internal override long MemoryHighwater
@@ -284,17 +362,34 @@
{
get
{
#if !PLATFORM_COMPACTFRAMEWORK
return UnsafeNativeMethods.sqlite3_memory_highwater(0);
-#else
+#elif !SQLITE_STANDARD
long bytes = 0;
UnsafeNativeMethods.sqlite3_memory_highwater_interop(0, ref bytes);
return bytes;
+#else
+ throw new NotImplementedException();
#endif
}
}
+
+ ///
+ /// Returns non-zero if the underlying native connection handle is owned
+ /// by this instance.
+ ///
+ internal override bool OwnHandle
+ {
+ get
+ {
+ if (_sql == null)
+ throw new SQLiteException("no connection handle available");
+
+ return _sql.OwnHandle;
+ }
+ }
internal override SQLiteErrorCode SetMemoryStatus(bool value)
{
return StaticSetMemoryStatus(value);
}
@@ -323,11 +418,24 @@
return (_sql != null) && !_sql.IsInvalid && !_sql.IsClosed;
}
internal override void Open(string strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, int maxPoolSize, bool usePool)
{
- if (_sql != null) return;
+ //
+ // NOTE: If the database connection is currently open, attempt to
+ // close it now. This must be done because the file name or
+ // other parameters that may impact the underlying database
+ // connection may have changed.
+ //
+ if (_sql != null) Close(true);
+
+ //
+ // NOTE: If the connection was not closed successfully, throw an
+ // exception now.
+ //
+ if (_sql != null)
+ throw new SQLiteException("connection handle is still active");
_usePool = usePool;
_fileName = strFilename;
if (usePool)
@@ -364,11 +472,11 @@
#if !NET_COMPACT_20 && TRACE_CONNECTION
Trace.WriteLine(String.Format("Open: {0}", db));
#endif
if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, null);
- _sql = new SQLiteConnectionHandle(db);
+ _sql = new SQLiteConnectionHandle(db, true);
}
lock (_sql) { /* HACK: Force the SyncBlock to be "created" now. */ }
}
// Bind functions to this connection. If any previous functions of the same name
// were already bound, then the new bindings replace the old.
@@ -473,19 +581,19 @@
tmp._sqlite_stmt = null;
// Reapply parameters
stmt.BindParameters();
}
- return (SQLiteErrorCode)(-1); // Reset was OK, with schema change
+ return SQLiteErrorCode.Unknown; // Reset was OK, with schema change
}
else if (n == SQLiteErrorCode.Locked || n == SQLiteErrorCode.Busy)
return n;
if (n != SQLiteErrorCode.Ok)
throw new SQLiteException(n, GetLastError());
- return SQLiteErrorCode.Ok; // We reset OK, no schema changes
+ return n; // We reset OK, no schema changes
}
internal override string GetLastError()
{
return SQLiteBase.GetLastError(_sql, _sql);
@@ -658,10 +766,11 @@
protected static void LogBind(SQLiteStatementHandle handle, int index)
{
IntPtr handleIntPtr = handle;
SQLiteLog.LogMessage(String.Format(
+ CultureInfo.CurrentCulture,
"Binding statement {0} paramter #{1} as NULL...",
handleIntPtr, index));
}
protected static void LogBind(SQLiteStatementHandle handle, int index, ValueType value)
@@ -739,12 +848,14 @@
LogBind(handle, index, value);
}
#if !PLATFORM_COMPACTFRAMEWORK
SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_bind_double(handle, index, value);
-#else
+#elif !SQLITE_STANDARD
SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_bind_double_interop(handle, index, ref value);
+#else
+ throw new NotImplementedException();
#endif
if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError());
}
internal override void Bind_Int32(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, int value)
@@ -777,12 +888,14 @@
{
long value2 = value;
#if !PLATFORM_COMPACTFRAMEWORK
n = UnsafeNativeMethods.sqlite3_bind_int64(handle, index, value2);
-#else
+#elif !SQLITE_STANDARD
n = UnsafeNativeMethods.sqlite3_bind_int64_interop(handle, index, ref value2);
+#else
+ throw new NotImplementedException();
#endif
}
else
{
n = UnsafeNativeMethods.sqlite3_bind_uint(handle, index, value);
@@ -799,12 +912,14 @@
{
LogBind(handle, index, value);
}
SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_bind_int64(handle, index, value);
-#else
+#elif !SQLITE_STANDARD
SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_bind_int64_interop(handle, index, ref value);
+#else
+ throw new NotImplementedException();
#endif
if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError());
}
internal override void Bind_UInt64(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, ulong value)
@@ -816,12 +931,14 @@
{
LogBind(handle, index, value);
}
SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_bind_uint64(handle, index, value);
-#else
+#elif !SQLITE_STANDARD
SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_bind_uint64_interop(handle, index, ref value);
+#else
+ throw new NotImplementedException();
#endif
if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError());
}
internal override void Bind_Text(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, string value)
@@ -870,12 +987,14 @@
{
LogBind(handle, index, value);
}
SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_bind_int64(handle, index, value);
-#else
+#elif !SQLITE_STANDARD
SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_bind_int64_interop(handle, index, ref value);
+#else
+ throw new NotImplementedException();
#endif
if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError());
break;
}
case SQLiteDateFormats.JulianDay:
@@ -887,12 +1006,14 @@
{
LogBind(handle, index, value);
}
SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_bind_double(handle, index, value);
-#else
+#elif !SQLITE_STANDARD
SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_bind_double_interop(handle, index, ref value);
+#else
+ throw new NotImplementedException();
#endif
if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError());
break;
}
case SQLiteDateFormats.UnixEpoch:
@@ -904,12 +1025,14 @@
{
LogBind(handle, index, value);
}
SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_bind_int64(handle, index, value);
-#else
+#elif !SQLITE_STANDARD
SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_bind_int64_interop(handle, index, ref value);
+#else
+ throw new NotImplementedException();
#endif
if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError());
break;
}
default:
@@ -968,10 +1091,11 @@
if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind)
{
IntPtr handleIntPtr = handle;
SQLiteLog.LogMessage(String.Format(
+ CultureInfo.CurrentCulture,
"Statement {0} paramter count is {1}.",
handleIntPtr, value));
}
return value;
@@ -992,10 +1116,11 @@
if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind)
{
IntPtr handleIntPtr = handle;
SQLiteLog.LogMessage(String.Format(
+ CultureInfo.CurrentCulture,
"Statement {0} paramter #{1} name is {{{2}}}.",
handleIntPtr, index, name));
}
return name;
@@ -1009,10 +1134,11 @@
if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind)
{
IntPtr handleIntPtr = handle;
SQLiteLog.LogMessage(String.Format(
+ CultureInfo.CurrentCulture,
"Statement {0} paramter index of name {{{1}}} is #{2}.",
handleIntPtr, paramName, index));
}
return index;
@@ -1148,12 +1274,14 @@
internal override double GetDouble(SQLiteStatement stmt, int index)
{
double value;
#if !PLATFORM_COMPACTFRAMEWORK
value = UnsafeNativeMethods.sqlite3_column_double(stmt._sqlite_stmt, index);
-#else
+#elif !SQLITE_STANDARD
UnsafeNativeMethods.sqlite3_column_double_interop(stmt._sqlite_stmt, index, out value);
+#else
+ throw new NotImplementedException();
#endif
return value;
}
internal override sbyte GetSByte(SQLiteStatement stmt, int index)
@@ -1189,12 +1317,14 @@
internal override long GetInt64(SQLiteStatement stmt, int index)
{
long value;
#if !PLATFORM_COMPACTFRAMEWORK
value = UnsafeNativeMethods.sqlite3_column_int64(stmt._sqlite_stmt, index);
-#else
+#elif !SQLITE_STANDARD
UnsafeNativeMethods.sqlite3_column_int64_interop(stmt._sqlite_stmt, index, out value);
+#else
+ throw new NotImplementedException();
#endif
return value;
}
internal override ulong GetUInt64(SQLiteStatement stmt, int index)
@@ -1408,12 +1538,14 @@
internal override double GetParamValueDouble(IntPtr ptr)
{
double value;
#if !PLATFORM_COMPACTFRAMEWORK
value = UnsafeNativeMethods.sqlite3_value_double(ptr);
-#else
+#elif !SQLITE_STANDARD
UnsafeNativeMethods.sqlite3_value_double_interop(ptr, out value);
+#else
+ throw new NotImplementedException();
#endif
return value;
}
internal override int GetParamValueInt32(IntPtr ptr)
@@ -1424,12 +1556,14 @@
internal override long GetParamValueInt64(IntPtr ptr)
{
Int64 value;
#if !PLATFORM_COMPACTFRAMEWORK
value = UnsafeNativeMethods.sqlite3_value_int64(ptr);
-#else
+#elif !SQLITE_STANDARD
UnsafeNativeMethods.sqlite3_value_int64_interop(ptr, out value);
+#else
+ throw new NotImplementedException();
#endif
return value;
}
internal override string GetParamValueText(IntPtr ptr)
@@ -1455,12 +1589,14 @@
internal override void ReturnDouble(IntPtr context, double value)
{
#if !PLATFORM_COMPACTFRAMEWORK
UnsafeNativeMethods.sqlite3_result_double(context, value);
-#else
+#elif !SQLITE_STANDARD
UnsafeNativeMethods.sqlite3_result_double_interop(context, ref value);
+#else
+ throw new NotImplementedException();
#endif
}
internal override void ReturnError(IntPtr context, string value)
{
@@ -1474,12 +1610,14 @@
internal override void ReturnInt64(IntPtr context, long value)
{
#if !PLATFORM_COMPACTFRAMEWORK
UnsafeNativeMethods.sqlite3_result_int64(context, value);
-#else
+#elif !SQLITE_STANDARD
UnsafeNativeMethods.sqlite3_result_int64_interop(context, ref value);
+#else
+ throw new NotImplementedException();
#endif
}
internal override void ReturnNull(IntPtr context)
{
@@ -1489,15 +1627,164 @@
internal override void ReturnText(IntPtr context, string value)
{
byte[] b = ToUTF8(value);
UnsafeNativeMethods.sqlite3_result_text(context, ToUTF8(value), b.Length - 1, (IntPtr)(-1));
}
+
+#if INTEROP_VIRTUAL_TABLE
+ ///
+ /// Calls the native SQLite core library in order to create a disposable
+ /// module containing the implementation of a virtual table.
+ ///
+ ///
+ /// The module object to be used when creating the native disposable module.
+ ///
+ internal override void CreateModule(SQLiteModule module)
+ {
+ if (module == null)
+ throw new ArgumentNullException("module");
+
+ if (_sql == null)
+ throw new SQLiteException("connection has an invalid handle");
+
+ SetLoadExtension(true);
+ LoadExtension(UnsafeNativeMethods.SQLITE_DLL, "sqlite3_vtshim_init");
+
+ IntPtr pName = IntPtr.Zero;
+
+ try
+ {
+ pName = SQLiteString.Utf8IntPtrFromString(module.Name);
+
+ UnsafeNativeMethods.sqlite3_module nativeModule =
+ module.CreateNativeModule();
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ if (UnsafeNativeMethods.sqlite3_create_disposable_module(
+ _sql, pName, ref nativeModule, IntPtr.Zero,
+ null) != IntPtr.Zero)
+#elif !SQLITE_STANDARD
+ if (UnsafeNativeMethods.sqlite3_create_disposable_module_interop(
+ _sql, pName, module.CreateNativeModuleInterop(),
+ nativeModule.iVersion, nativeModule.xCreate,
+ nativeModule.xConnect, nativeModule.xBestIndex,
+ nativeModule.xDisconnect, nativeModule.xDestroy,
+ nativeModule.xOpen, nativeModule.xClose,
+ nativeModule.xFilter, nativeModule.xNext,
+ nativeModule.xEof, nativeModule.xColumn,
+ nativeModule.xRowId, nativeModule.xUpdate,
+ nativeModule.xBegin, nativeModule.xSync,
+ nativeModule.xCommit, nativeModule.xRollback,
+ nativeModule.xFindFunction, nativeModule.xRename,
+ nativeModule.xSavepoint, nativeModule.xRelease,
+ nativeModule.xRollbackTo, IntPtr.Zero, null) != IntPtr.Zero)
+#else
+ throw new NotImplementedException();
+#endif
+#if !PLATFORM_COMPACTFRAMEWORK || !SQLITE_STANDARD
+ {
+ if (_modules == null)
+ _modules = new Dictionary();
+
+ _modules.Add(module.Name, module);
+ }
+ else
+ {
+ throw new SQLiteException(GetLastError());
+ }
+#endif
+ }
+ finally
+ {
+ if (pName != IntPtr.Zero)
+ {
+ SQLiteMemory.Free(pName);
+ pName = IntPtr.Zero;
+ }
+ }
+ }
+
+ ///
+ /// Calls the native SQLite core library in order to cleanup the resources
+ /// associated with a module containing the implementation of a virtual table.
+ ///
+ ///
+ /// The module object previously passed to the
+ /// method.
+ ///
+ internal override void DisposeModule(SQLiteModule module)
+ {
+ if (module == null)
+ throw new ArgumentNullException("module");
+
+ module.Dispose();
+ }
+#endif
internal override IntPtr AggregateContext(IntPtr context)
{
return UnsafeNativeMethods.sqlite3_aggregate_context(context, 1);
}
+
+#if INTEROP_VIRTUAL_TABLE
+ ///
+ /// Calls the native SQLite core library in order to declare a virtual table
+ /// in response to a call into the xCreate or xConnect virtual table methods.
+ ///
+ ///
+ /// The virtual table module that is to be responsible for the virtual table
+ /// being declared.
+ ///
+ ///
+ /// The string containing the SQL statement describing the virtual table to
+ /// be declared.
+ ///
+ ///
+ /// Upon success, the contents of this parameter are undefined. Upon failure,
+ /// it should contain an appropriate error message.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ internal override SQLiteErrorCode DeclareVirtualTable(
+ SQLiteModule module,
+ string strSql,
+ ref string error
+ )
+ {
+ if (_sql == null)
+ {
+ error = "connection has an invalid handle";
+ return SQLiteErrorCode.Error;
+ }
+
+ IntPtr pSql = IntPtr.Zero;
+
+ try
+ {
+ pSql = SQLiteString.Utf8IntPtrFromString(strSql);
+
+ SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_declare_vtab(
+ _sql, pSql);
+
+ if ((n == SQLiteErrorCode.Ok) && (module != null))
+ module.Declared = true;
+
+ if (n != SQLiteErrorCode.Ok) error = GetLastError();
+
+ return n;
+ }
+ finally
+ {
+ if (pSql != IntPtr.Zero)
+ {
+ SQLiteMemory.Free(pSql);
+ pSql = IntPtr.Zero;
+ }
+ }
+ }
+#endif
///
/// Enables or disabled extension loading by SQLite.
///
///
Index: System.Data.SQLite/SQLite3_UTF16.cs
==================================================================
--- System.Data.SQLite/SQLite3_UTF16.cs
+++ System.Data.SQLite/SQLite3_UTF16.cs
@@ -19,12 +19,45 @@
///
/// Alternate SQLite3 object, overriding many text behaviors to support UTF-16 (Unicode)
///
internal sealed class SQLite3_UTF16 : SQLite3
{
- internal SQLite3_UTF16(SQLiteDateFormats fmt, DateTimeKind kind, string fmtString)
- : base(fmt, kind, fmtString)
+ ///
+ /// Constructs the object used to interact with the SQLite core library
+ /// using the UTF-8 text encoding.
+ ///
+ ///
+ /// The DateTime format to be used when converting string values to a
+ /// DateTime and binding DateTime parameters.
+ ///
+ ///
+ /// The to be used when creating DateTime
+ /// values.
+ ///
+ ///
+ /// The format string to be used when parsing and formatting DateTime
+ /// values.
+ ///
+ ///
+ /// The native handle to be associated with the database connection.
+ ///
+ ///
+ /// The fully qualified file name associated with .
+ ///
+ ///
+ /// Non-zero if the newly created object instance will need to dispose
+ /// of when it is no longer needed.
+ ///
+ internal SQLite3_UTF16(
+ SQLiteDateFormats fmt,
+ DateTimeKind kind,
+ string fmtString,
+ IntPtr db,
+ string fileName,
+ bool ownHandle
+ )
+ : base(fmt, kind, fmtString, db, fileName, ownHandle)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -91,11 +124,24 @@
return Marshal.PtrToStringUni(b, nbytelen / 2);
}
internal override void Open(string strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, int maxPoolSize, bool usePool)
{
- if (_sql != null) return;
+ //
+ // NOTE: If the database connection is currently open, attempt to
+ // close it now. This must be done because the file name or
+ // other parameters that may impact the underlying database
+ // connection may have changed.
+ //
+ if (_sql != null) Close(true);
+
+ //
+ // NOTE: If the connection was not closed successfully, throw an
+ // exception now.
+ //
+ if (_sql != null)
+ throw new SQLiteException("connection handle is still active");
_usePool = usePool;
_fileName = strFilename;
if (usePool)
@@ -141,11 +187,11 @@
#if !NET_COMPACT_20 && TRACE_CONNECTION
Trace.WriteLine(String.Format("Open16: {0}", db));
#endif
if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, null);
- _sql = new SQLiteConnectionHandle(db);
+ _sql = new SQLiteConnectionHandle(db, true);
}
lock (_sql) { /* HACK: Force the SyncBlock to be "created" now. */ }
}
_functionsArray = SQLiteFunction.BindFunctions(this, connectionFlags);
SetTimeout(0);
Index: System.Data.SQLite/SQLiteBase.cs
==================================================================
--- System.Data.SQLite/SQLiteBase.cs
+++ System.Data.SQLite/SQLiteBase.cs
@@ -17,10 +17,20 @@
/// This internal class provides the foundation of SQLite support. It defines all the abstract members needed to implement
/// a SQLite data provider, and inherits from SQLiteConvert which allows for simple translations of string to and from SQLite.
///
internal abstract class SQLiteBase : SQLiteConvert, IDisposable
{
+ #region Private Constants
+ ///
+ /// The error code used for logging exceptions caught in user-provided
+ /// code.
+ ///
+ internal const int COR_E_EXCEPTION = unchecked((int)0x80131500);
+ #endregion
+
+ /////////////////////////////////////////////////////////////////////////
+
internal SQLiteBase(SQLiteDateFormats fmt, DateTimeKind kind, string fmtString)
: base(fmt, kind, fmtString) { }
///
/// Returns a string representing the active version of SQLite
@@ -46,10 +56,14 @@
///
/// Returns the maximum amount of memory (in bytes) used by the SQLite core library since the high-water mark was last reset.
/// This is not really a per-connection value, it is global to the process.
///
internal abstract long MemoryHighwater { get; }
+ ///
+ /// Returns non-zero if the underlying native connection handle is owned by this instance.
+ ///
+ internal abstract bool OwnHandle { get; }
///
/// Sets the status of the memory usage tracking subsystem in the SQLite core library. By default, this is enabled.
/// If this is disabled, memory usage tracking will not be performed. This is not really a per-connection value, it is
/// global to the process.
///
@@ -198,10 +212,52 @@
internal abstract void ReturnError(IntPtr context, string value);
internal abstract void ReturnInt32(IntPtr context, Int32 value);
internal abstract void ReturnInt64(IntPtr context, Int64 value);
internal abstract void ReturnNull(IntPtr context);
internal abstract void ReturnText(IntPtr context, string value);
+
+#if INTEROP_VIRTUAL_TABLE
+ ///
+ /// Calls the native SQLite core library in order to create a disposable
+ /// module containing the implementation of a virtual table.
+ ///
+ ///
+ /// The module object to be used when creating the native disposable module.
+ ///
+ internal abstract void CreateModule(SQLiteModule module);
+
+ ///
+ /// Calls the native SQLite core library in order to cleanup the resources
+ /// associated with a module containing the implementation of a virtual table.
+ ///
+ ///
+ /// The module object previously passed to the
+ /// method.
+ ///
+ internal abstract void DisposeModule(SQLiteModule module);
+
+ ///
+ /// Calls the native SQLite core library in order to declare a virtual table
+ /// in response to a call into the xCreate or xConnect virtual table methods.
+ ///
+ ///
+ /// The virtual table module that is to be responsible for the virtual table
+ /// being declared.
+ ///
+ ///
+ /// The string containing the SQL statement describing the virtual table to
+ /// be declared.
+ ///
+ ///
+ /// Upon success, the contents of this parameter are undefined. Upon failure,
+ /// it should contain an appropriate error message.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ internal abstract SQLiteErrorCode DeclareVirtualTable(SQLiteModule module, string strSql, ref string error);
+#endif
///
/// Enables or disabled extension loading by SQLite.
///
///
@@ -803,10 +859,22 @@
/// plain text (i.e. no numeric, date/time, or other conversions should
/// be attempted).
///
GetAllAsText = 0x100,
+ ///
+ /// Prevent this object instance from
+ /// loading extensions.
+ ///
+ NoLoadExtension = 0x200,
+
+ ///
+ /// Prevent this object instance from
+ /// creating virtual table modules.
+ ///
+ NoCreateModule = 0x400,
+
///
/// When binding and returning column values, always treat them as though
/// they were plain text (i.e. no numeric, date/time, or other conversions
/// should be attempted).
///
Index: System.Data.SQLite/SQLiteConnection.cs
==================================================================
--- System.Data.SQLite/SQLiteConnection.cs
+++ System.Data.SQLite/SQLiteConnection.cs
@@ -401,10 +401,11 @@
///
/// Whether or not the connection is enlisted in a distrubuted transaction
///
internal SQLiteEnlistment _enlistment;
#endif
+
///
/// The base SQLite object to interop with
///
internal SQLiteBase _sql;
///
@@ -472,11 +473,11 @@
///
///
/// Default constructor
///
public SQLiteConnection()
- : this("")
+ : this((string)null)
{
}
///
/// Initializes the connection with the specified connection string.
@@ -485,16 +486,44 @@
public SQLiteConnection(string connectionString)
: this(connectionString, false)
{
// do nothing.
}
+
+ ///
+ /// Initializes the connection with a pre-existing native connection handle.
+ ///
+ ///
+ /// The native connection handle to use.
+ ///
+ ///
+ /// The file name corresponding to the native connection handle.
+ ///
+ ///
+ /// Non-zero if this instance owns the native connection handle and
+ /// should dispose of it when it is no longer needed.
+ ///
+ internal SQLiteConnection(IntPtr db, string fileName, bool ownHandle)
+ : this()
+ {
+ _sql = new SQLite3(
+ SQLiteDateFormats.Default, DateTimeKind.Unspecified, null,
+ db, fileName, ownHandle);
+
+ _flags = SQLiteConnectionFlags.None;
+
+ _connectionState = (db != IntPtr.Zero) ?
+ ConnectionState.Open : ConnectionState.Closed;
+
+ _connectionString = null; /* unknown */
+ }
///
/// Initializes the connection with the specified connection string.
///
///
- /// The connection string to use on.
+ /// The connection string to use.
///
///
/// Non-zero to parse the connection string using the built-in (i.e.
/// framework provided) parser when opening the connection.
///
@@ -541,12 +570,11 @@
#endif
_parseViaFramework = parseViaFramework;
_flags = SQLiteConnectionFlags.Default;
_connectionState = ConnectionState.Closed;
- _connectionString = "";
- //_commandList = new List();
+ _connectionString = null;
if (connectionString != null)
ConnectionString = connectionString;
}
@@ -555,24 +583,22 @@
/// function will open its own connection, enumerate any attached databases of the original connection, and automatically
/// attach to them.
///
/// The connection to copy the settings from.
public SQLiteConnection(SQLiteConnection connection)
- : this(connection.ConnectionString)
+ : this(connection.ConnectionString, connection.ParseViaFramework)
{
- string str;
-
if (connection.State == ConnectionState.Open)
{
Open();
// Reattach all attached databases from the existing connection
using (DataTable tbl = connection.GetSchema("Catalogs"))
{
foreach (DataRow row in tbl.Rows)
{
- str = row[0].ToString();
+ string str = row[0].ToString();
if (String.Compare(str, "main", StringComparison.OrdinalIgnoreCase) != 0
&& String.Compare(str, "temp", StringComparison.OrdinalIgnoreCase) != 0)
{
using (SQLiteCommand cmd = CreateCommand())
{
@@ -685,11 +711,11 @@
public static object CreateHandle(
IntPtr nativeHandle
)
{
if (nativeHandle == IntPtr.Zero) return null;
- return new SQLiteConnectionHandle(nativeHandle);
+ return new SQLiteConnectionHandle(nativeHandle, true);
}
///////////////////////////////////////////////////////////////////////////////////////////////
#region Backup API Members
@@ -833,10 +859,64 @@
throw new InvalidOperationException("The connection handle is invalid.");
if (handle.IsClosed)
throw new InvalidOperationException("The connection handle is closed.");
}
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ private static SortedList ParseConnectionString(
+ string connectionString,
+ bool parseViaFramework
+ )
+ {
+ return parseViaFramework ?
+ ParseConnectionStringViaFramework(connectionString, false) :
+ ParseConnectionString(connectionString);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ private void SetupSQLiteBase(SortedList opts)
+ {
+ object enumValue;
+
+ enumValue = TryParseEnum(
+ typeof(SQLiteDateFormats), FindKey(opts, "DateTimeFormat",
+ DefaultDateTimeFormat.ToString()), true);
+
+ SQLiteDateFormats dateFormat = (enumValue is SQLiteDateFormats) ?
+ (SQLiteDateFormats)enumValue : DefaultDateTimeFormat;
+
+ enumValue = TryParseEnum(
+ typeof(DateTimeKind), FindKey(opts, "DateTimeKind",
+ DefaultDateTimeKind.ToString()), true);
+
+ DateTimeKind kind = (enumValue is DateTimeKind) ?
+ (DateTimeKind)enumValue : DefaultDateTimeKind;
+
+ string dateTimeFormat = FindKey(opts, "DateTimeFormatString",
+ DefaultDateTimeFormatString);
+
+ //
+ // NOTE: SQLite automatically sets the encoding of the database
+ // to UTF16 if called from sqlite3_open16().
+ //
+ if (SQLiteConvert.ToBoolean(FindKey(opts, "UseUTF16Encoding",
+ DefaultUseUTF16Encoding.ToString())))
+ {
+ _sql = new SQLite3_UTF16(
+ dateFormat, kind, dateTimeFormat, IntPtr.Zero, null,
+ false);
+ }
+ else
+ {
+ _sql = new SQLite3(
+ dateFormat, kind, dateTimeFormat, IntPtr.Zero, null,
+ false);
+ }
+ }
///////////////////////////////////////////////////////////////////////////////////////////////
#region IDisposable "Pattern" Members
private bool disposed;
@@ -1437,11 +1517,11 @@
#endif
arParts = SQLiteConvert.NewSplit(s, ';', true, ref error);
if (arParts == null)
{
- throw new ArgumentException(String.Format(
+ throw new ArgumentException(String.Format(CultureInfo.CurrentCulture,
"Invalid ConnectionString format, cannot parse: {0}", (error != null) ?
error : "could not split connection string into properties"));
}
int x = (arParts != null) ? arParts.Length : 0;
@@ -1647,12 +1727,16 @@
{
CheckDisposed();
if (_sql == null)
throw new InvalidOperationException(String.Format(
+ CultureInfo.CurrentCulture,
"Database connection not valid for {0} extensions.",
enable ? "enabling" : "disabling"));
+
+ if ((_flags & SQLiteConnectionFlags.NoLoadExtension) == SQLiteConnectionFlags.NoLoadExtension)
+ throw new SQLiteException("Loading extensions is disabled for this database connection.");
_sql.SetLoadExtension(enable);
}
///
@@ -1689,12 +1773,40 @@
if (_sql == null)
throw new InvalidOperationException(
"Database connection not valid for loading extensions.");
+ if ((_flags & SQLiteConnectionFlags.NoLoadExtension) == SQLiteConnectionFlags.NoLoadExtension)
+ throw new SQLiteException("Loading extensions is disabled for this database connection.");
+
_sql.LoadExtension(fileName, procName);
}
+
+#if INTEROP_VIRTUAL_TABLE
+ ///
+ /// Creates a disposable module containing the implementation of a virtual
+ /// table.
+ ///
+ ///
+ /// The module object to be used when creating the disposable module.
+ ///
+ public void CreateModule(
+ SQLiteModule module
+ )
+ {
+ CheckDisposed();
+
+ if (_sql == null)
+ throw new InvalidOperationException(
+ "Database connection not valid for creating modules.");
+
+ if ((_flags & SQLiteConnectionFlags.NoCreateModule) == SQLiteConnectionFlags.NoCreateModule)
+ throw new SQLiteException("Creating modules is disabled for this database connection.");
+
+ _sql.CreateModule(module);
+ }
+#endif
///
/// Parses a string containing a sequence of zero or more hexadecimal
/// encoded byte values and returns the resulting byte array. The
/// "0x" prefix is not allowed on the input string.
@@ -1788,10 +1900,11 @@
if (!TryParseByte(value,
NumberStyles.HexNumber, out result[index / 2]))
{
error = String.Format(
+ CultureInfo.CurrentCulture,
"string contains \"{0}\", which cannot be converted to a byte value",
value);
return null;
}
@@ -1813,13 +1926,12 @@
if (_connectionState != ConnectionState.Closed)
throw new InvalidOperationException();
Close();
- SortedList opts = _parseViaFramework ?
- ParseConnectionStringViaFramework(_connectionString, false) :
- ParseConnectionString(_connectionString);
+ SortedList opts = ParseConnectionString(
+ _connectionString, _parseViaFramework);
OnChanged(this, new ConnectionEventArgs(
SQLiteConnectionEventType.ConnectionString, null, null, null, _connectionString, opts));
object enumValue;
@@ -1882,38 +1994,11 @@
_baseSchemaName = FindKey(opts, "BaseSchemaName", DefaultBaseSchemaName);
if (_sql == null)
{
- enumValue = TryParseEnum(typeof(SQLiteDateFormats), FindKey(opts,
- "DateTimeFormat", DefaultDateTimeFormat.ToString()), true);
-
- SQLiteDateFormats dateFormat = (enumValue is SQLiteDateFormats) ?
- (SQLiteDateFormats)enumValue : DefaultDateTimeFormat;
-
- enumValue = TryParseEnum(typeof(DateTimeKind), FindKey(opts,
- "DateTimeKind", DefaultDateTimeKind.ToString()), true);
-
- DateTimeKind kind = (enumValue is DateTimeKind) ?
- (DateTimeKind)enumValue : DefaultDateTimeKind;
-
- string dateTimeFormat = FindKey(opts, "DateTimeFormatString",
- DefaultDateTimeFormatString);
-
- //
- // NOTE: SQLite automatically sets the encoding of the database to
- // UTF16 if called from sqlite3_open16().
- //
- if (SQLiteConvert.ToBoolean(FindKey(opts, "UseUTF16Encoding",
- DefaultUseUTF16Encoding.ToString())))
- {
- _sql = new SQLite3_UTF16(dateFormat, kind, dateTimeFormat);
- }
- else
- {
- _sql = new SQLite3(dateFormat, kind, dateTimeFormat);
- }
+ SetupSQLiteBase(opts);
}
SQLiteOpenFlagsEnum flags = SQLiteOpenFlagsEnum.None;
if (!SQLiteConvert.ToBoolean(FindKey(opts, "FailIfMissing", DefaultFailIfMissing.ToString())))
@@ -1946,10 +2031,11 @@
byte[] hexPasswordBytes = FromHexString(hexPassword, ref error);
if (hexPasswordBytes == null)
{
throw new FormatException(String.Format(
+ CultureInfo.CurrentCulture,
"Cannot parse 'HexPassword' property value into byte values: {0}",
error));
}
_sql.SetPassword(hexPasswordBytes);
@@ -2129,10 +2215,27 @@
public SQLiteConnectionFlags Flags
{
get { CheckDisposed(); return _flags; }
set { CheckDisposed(); _flags = value; }
}
+
+ ///
+ /// Returns non-zero if the underlying native connection handle is
+ /// owned by this instance.
+ ///
+ public bool OwnHandle
+ {
+ get
+ {
+ CheckDisposed();
+
+ if (_sql == null)
+ throw new InvalidOperationException("Database connection not valid for checking handle.");
+
+ return _sql.OwnHandle;
+ }
+ }
///
/// Returns the version of the underlying SQLite database engine
///
#if !PLATFORM_COMPACTFRAMEWORK
@@ -2308,44 +2411,14 @@
CheckDisposed();
// make sure we have an instance of the base class
if (_sql == null)
{
- SortedList opts = _parseViaFramework ?
- ParseConnectionStringViaFramework(_connectionString, false) :
- ParseConnectionString(_connectionString);
-
- object enumValue;
-
- enumValue = TryParseEnum(typeof(SQLiteDateFormats), FindKey(opts,
- "DateTimeFormat", DefaultDateTimeFormat.ToString()), true);
-
- SQLiteDateFormats dateFormat = (enumValue is SQLiteDateFormats) ?
- (SQLiteDateFormats)enumValue : DefaultDateTimeFormat;
-
- enumValue = TryParseEnum(typeof(DateTimeKind), FindKey(opts,
- "DateTimeKind", DefaultDateTimeKind.ToString()), true);
-
- DateTimeKind kind = (enumValue is DateTimeKind) ?
- (DateTimeKind)enumValue : DefaultDateTimeKind;
-
- string dateTimeFormat = FindKey(opts, "DateTimeFormatString",
- DefaultDateTimeFormatString);
-
- //
- // NOTE: SQLite automatically sets the encoding of the database to
- // UTF16 if called from sqlite3_open16().
- //
- if (SQLiteConvert.ToBoolean(FindKey(opts,
- "UseUTF16Encoding", DefaultUseUTF16Encoding.ToString())))
- {
- _sql = new SQLite3_UTF16(dateFormat, kind, dateTimeFormat);
- }
- else
- {
- _sql = new SQLite3(dateFormat, kind, dateTimeFormat);
- }
+ SortedList opts = ParseConnectionString(
+ _connectionString, _parseViaFramework);
+
+ SetupSQLiteBase(opts);
}
if (_sql != null) return _sql.Shutdown();
throw new InvalidOperationException("Database connection not active.");
}
Index: System.Data.SQLite/SQLiteConvert.cs
==================================================================
--- System.Data.SQLite/SQLiteConvert.cs
+++ System.Data.SQLite/SQLiteConvert.cs
@@ -946,10 +946,11 @@
string defaultTypeName = String.Empty;
#if !NET_COMPACT_20 && TRACE_WARNING
Trace.WriteLine(String.Format(
+ CultureInfo.CurrentCulture,
"WARNING: Type mapping failed, returning default name \"{0}\" for type {1}.",
defaultTypeName, typ));
#endif
return defaultTypeName;
@@ -1150,10 +1151,11 @@
DbType defaultDbType = DbType.Object;
#if !NET_COMPACT_20 && TRACE_WARNING
Trace.WriteLine(String.Format(
+ CultureInfo.CurrentCulture,
"WARNING: Type mapping failed, returning default type {0} for name \"{1}\".",
defaultDbType, Name));
#endif
return defaultDbType;
@@ -1197,11 +1199,11 @@
///
/// Used internally by this provider
///
DateTime = 10,
///
- /// Used internally
+ /// Used internally by this provider
///
None = 11,
}
///
Index: System.Data.SQLite/SQLiteDataReader.cs
==================================================================
--- System.Data.SQLite/SQLiteDataReader.cs
+++ System.Data.SQLite/SQLiteDataReader.cs
@@ -234,11 +234,11 @@
if (_command == null)
throw new InvalidOperationException("DataReader has been closed");
if (_version == 0)
- throw new SQLiteException(SQLiteErrorCode.Abort, "Execution was aborted by the user");
+ throw new SQLiteException("Execution was aborted by the user");
if (_command.Connection.State != ConnectionState.Open || _command.Connection._version != _version)
throw new InvalidOperationException("Connection was closed, statement was terminated");
}
Index: System.Data.SQLite/SQLiteDefineConstants.cs
==================================================================
--- System.Data.SQLite/SQLiteDefineConstants.cs
+++ System.Data.SQLite/SQLiteDefineConstants.cs
@@ -45,10 +45,14 @@
#endif
#if INTEROP_TEST_EXTENSION
"INTEROP_TEST_EXTENSION",
#endif
+
+#if INTEROP_VIRTUAL_TABLE
+ "INTEROP_VIRTUAL_TABLE",
+#endif
#if NET_20
"NET_20",
#endif
@@ -109,10 +113,14 @@
#endif
#if TRACE_WARNING
"TRACE_WARNING",
#endif
+
+#if TRACK_MEMORY_BYTES
+ "TRACK_MEMORY_BYTES",
+#endif
#if USE_INTEROP_DLL
"USE_INTEROP_DLL",
#endif
Index: System.Data.SQLite/SQLiteException.cs
==================================================================
--- System.Data.SQLite/SQLiteException.cs
+++ System.Data.SQLite/SQLiteException.cs
@@ -65,11 +65,11 @@
/// Public constructor that uses the base class constructor for the error
/// message.
///
/// Error message text.
public SQLiteException(string message)
- : base(message)
+ : this(SQLiteErrorCode.Unknown, message)
{
}
///
/// Public constructor that uses the default base class constructor.
@@ -198,10 +198,15 @@
/// SQLITE_ROW, and SQLITE_DONE). Therefore, the name of this enumeration is
/// something of a misnomer.
///
public enum SQLiteErrorCode
{
+ ///
+ /// The error code is unknown. This error code
+ /// is only used by the managed wrapper itself.
+ ///
+ Unknown = -1,
///
/// Successful result
///
Ok /* 0 */,
///
Index: System.Data.SQLite/SQLiteFunction.cs
==================================================================
--- System.Data.SQLite/SQLiteFunction.cs
+++ System.Data.SQLite/SQLiteFunction.cs
@@ -36,20 +36,10 @@
internal object _data;
}
/////////////////////////////////////////////////////////////////////////
- #region Private Constants
- ///
- /// The error code used for logging exceptions caught in user-provided
- /// code.
- ///
- private const int COR_E_EXCEPTION = unchecked((int)0x80131500);
- #endregion
-
- /////////////////////////////////////////////////////////////////////////
-
///
/// The base connection this function is attached to
///
internal SQLiteBase _base;
@@ -388,12 +378,12 @@
try
{
if ((_flags & SQLiteConnectionFlags.LogCallbackException) ==
SQLiteConnectionFlags.LogCallbackException)
{
- SQLiteLog.LogMessage(COR_E_EXCEPTION, String.Format(
- CultureInfo.CurrentCulture,
+ SQLiteLog.LogMessage(SQLiteBase.COR_E_EXCEPTION,
+ String.Format(CultureInfo.CurrentCulture,
"Caught exception in \"Invoke\" method: {0}",
e)); /* throw */
}
}
catch
@@ -426,12 +416,12 @@
try
{
if ((_flags & SQLiteConnectionFlags.LogCallbackException) ==
SQLiteConnectionFlags.LogCallbackException)
{
- SQLiteLog.LogMessage(COR_E_EXCEPTION, String.Format(
- CultureInfo.CurrentCulture,
+ SQLiteLog.LogMessage(SQLiteBase.COR_E_EXCEPTION,
+ String.Format(CultureInfo.CurrentCulture,
"Caught exception in \"Compare\" (UTF8) method: {0}",
e)); /* throw */
}
}
catch
@@ -473,12 +463,12 @@
try
{
if ((_flags & SQLiteConnectionFlags.LogCallbackException) ==
SQLiteConnectionFlags.LogCallbackException)
{
- SQLiteLog.LogMessage(COR_E_EXCEPTION, String.Format(
- CultureInfo.CurrentCulture,
+ SQLiteLog.LogMessage(SQLiteBase.COR_E_EXCEPTION,
+ String.Format(CultureInfo.CurrentCulture,
"Caught exception in \"Compare\" (UTF16) method: {0}",
e)); /* throw */
}
}
catch
@@ -546,12 +536,12 @@
try
{
if ((_flags & SQLiteConnectionFlags.LogCallbackException) ==
SQLiteConnectionFlags.LogCallbackException)
{
- SQLiteLog.LogMessage(COR_E_EXCEPTION, String.Format(
- CultureInfo.CurrentCulture,
+ SQLiteLog.LogMessage(SQLiteBase.COR_E_EXCEPTION,
+ String.Format(CultureInfo.CurrentCulture,
"Caught exception in \"Step\" method: {1}",
e)); /* throw */
}
}
catch
@@ -601,12 +591,12 @@
try
{
if ((_flags & SQLiteConnectionFlags.LogCallbackException) ==
SQLiteConnectionFlags.LogCallbackException)
{
- SQLiteLog.LogMessage(COR_E_EXCEPTION, String.Format(
- CultureInfo.CurrentCulture,
+ SQLiteLog.LogMessage(SQLiteBase.COR_E_EXCEPTION,
+ String.Format(CultureInfo.CurrentCulture,
"Caught exception in \"Final\" method: {1}",
e)); /* throw */
}
}
catch
@@ -844,17 +834,17 @@
}
///
/// An internal callback delegate declaration.
///
- /// Raw context pointer for the user function
- /// Count of arguments to the function
- /// A pointer to the array of argument pointers
+ /// Raw native context pointer for the user function.
+ /// Total number of arguments to the user function.
+ /// Raw native pointer to the array of raw native argument pointers.
#if !PLATFORM_COMPACTFRAMEWORK
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
#endif
- internal delegate void SQLiteCallback(IntPtr context, int nArgs, IntPtr argsptr);
+ public delegate void SQLiteCallback(IntPtr context, int argc, IntPtr argv);
///
/// An internal final callback delegate declaration.
///
/// Raw context pointer for the user function
#if !PLATFORM_COMPACTFRAMEWORK
Index: System.Data.SQLite/SQLiteLog.cs
==================================================================
--- System.Data.SQLite/SQLiteLog.cs
+++ System.Data.SQLite/SQLiteLog.cs
@@ -8,10 +8,11 @@
namespace System.Data.SQLite
{
using System;
using System.Data.Common;
using System.Diagnostics;
+ using System.Globalization;
///
/// Event data for logging event handlers.
///
public class LogEventArgs : EventArgs
@@ -178,12 +179,15 @@
//
// NOTE: Create an instance of the SQLite wrapper class.
//
if (_sql == null)
- _sql = new SQLite3(SQLiteDateFormats.Default,
- DateTimeKind.Unspecified, null);
+ {
+ _sql = new SQLite3(
+ SQLiteDateFormats.Default, DateTimeKind.Unspecified,
+ null, IntPtr.Zero, null, false);
+ }
//
// NOTE: Create a single "global" (i.e. per-process) callback
// to register with SQLite. This callback will pass the
// event on to any registered handler. We only want to
@@ -521,11 +525,12 @@
if (errorCode is SQLiteErrorCode)
success = ((SQLiteErrorCode)errorCode == SQLiteErrorCode.Ok);
else if (errorCode is int)
success = ((int)errorCode == 0);
- Trace.WriteLine(String.Format("SQLite {0} ({1}): {2}",
+ Trace.WriteLine(String.Format(
+ CultureInfo.CurrentCulture, "SQLite {0} ({1}): {2}",
success ? "message" : "error", errorCode, message));
#endif
}
}
}
ADDED System.Data.SQLite/SQLiteModule.cs
Index: System.Data.SQLite/SQLiteModule.cs
==================================================================
--- /dev/null
+++ System.Data.SQLite/SQLiteModule.cs
@@ -0,0 +1,7866 @@
+/********************************************************
+ * ADO.NET 2.0 Data Provider for SQLite Version 3.X
+ * Written by Joe Mistachkin (joe@mistachkin.com)
+ *
+ * Released to the public domain, use at your own risk!
+ ********************************************************/
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace System.Data.SQLite
+{
+ #region SQLiteContext Helper Class
+ ///
+ /// This class represents a context from the SQLite core library that can
+ /// be passed to the sqlite3_result_*() and associated functions.
+ ///
+ public sealed class SQLiteContext : ISQLiteNativeHandle
+ {
+ #region Private Data
+ ///
+ /// The native context handle.
+ ///
+ private IntPtr pContext;
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Private Constructors
+ ///
+ /// Constructs an instance of this class using the specified native
+ /// context handle.
+ ///
+ ///
+ /// The native context handle to use.
+ ///
+ internal SQLiteContext(IntPtr pContext)
+ {
+ this.pContext = pContext;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region ISQLiteNativeHandle Members
+ ///
+ /// Returns the underlying SQLite native handle associated with this
+ /// object instance.
+ ///
+ public IntPtr NativeHandle
+ {
+ get { return pContext; }
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Public Methods
+ ///
+ /// Sets the context result to NULL.
+ ///
+ public void SetNull()
+ {
+ if (pContext == IntPtr.Zero)
+ throw new InvalidOperationException();
+
+ UnsafeNativeMethods.sqlite3_result_null(pContext);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Sets the context result to the specified
+ /// value.
+ ///
+ ///
+ /// The value to use.
+ ///
+ public void SetDouble(double value)
+ {
+ if (pContext == IntPtr.Zero)
+ throw new InvalidOperationException();
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ UnsafeNativeMethods.sqlite3_result_double(pContext, value);
+#elif !SQLITE_STANDARD
+ UnsafeNativeMethods.sqlite3_result_double_interop(pContext, ref value);
+#else
+ throw new NotImplementedException();
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Sets the context result to the specified
+ /// value.
+ ///
+ ///
+ /// The value to use.
+ ///
+ public void SetInt(int value)
+ {
+ if (pContext == IntPtr.Zero)
+ throw new InvalidOperationException();
+
+ UnsafeNativeMethods.sqlite3_result_int(pContext, value);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Sets the context result to the specified
+ /// value.
+ ///
+ ///
+ /// The value to use.
+ ///
+ public void SetInt64(long value)
+ {
+ if (pContext == IntPtr.Zero)
+ throw new InvalidOperationException();
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ UnsafeNativeMethods.sqlite3_result_int64(pContext, value);
+#elif !SQLITE_STANDARD
+ UnsafeNativeMethods.sqlite3_result_int64_interop(pContext, ref value);
+#else
+ throw new NotImplementedException();
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Sets the context result to the specified
+ /// value.
+ ///
+ ///
+ /// The value to use. This value will be
+ /// converted to the UTF-8 encoding prior to being used.
+ ///
+ public void SetString(string value)
+ {
+ if (pContext == IntPtr.Zero)
+ throw new InvalidOperationException();
+
+ byte[] bytes = SQLiteString.GetUtf8BytesFromString(value);
+
+ if (bytes == null)
+ throw new ArgumentNullException("value");
+
+ UnsafeNativeMethods.sqlite3_result_text(
+ pContext, bytes, bytes.Length, (IntPtr)(-1));
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Sets the context result to the specified
+ /// value containing an error message.
+ ///
+ ///
+ /// The value containing the error message text.
+ /// This value will be converted to the UTF-8 encoding prior to being
+ /// used.
+ ///
+ public void SetError(string value)
+ {
+ if (pContext == IntPtr.Zero)
+ throw new InvalidOperationException();
+
+ byte[] bytes = SQLiteString.GetUtf8BytesFromString(value);
+
+ if (bytes == null)
+ throw new ArgumentNullException("value");
+
+ UnsafeNativeMethods.sqlite3_result_error(
+ pContext, bytes, bytes.Length);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Sets the context result to the specified
+ /// value.
+ ///
+ ///
+ /// The value to use.
+ ///
+ public void SetErrorCode(SQLiteErrorCode value)
+ {
+ if (pContext == IntPtr.Zero)
+ throw new InvalidOperationException();
+
+ UnsafeNativeMethods.sqlite3_result_error_code(pContext, value);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Sets the context result to contain the error code SQLITE_TOOBIG.
+ ///
+ public void SetErrorTooBig()
+ {
+ if (pContext == IntPtr.Zero)
+ throw new InvalidOperationException();
+
+ UnsafeNativeMethods.sqlite3_result_error_toobig(pContext);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Sets the context result to contain the error code SQLITE_NOMEM.
+ ///
+ public void SetErrorNoMemory()
+ {
+ if (pContext == IntPtr.Zero)
+ throw new InvalidOperationException();
+
+ UnsafeNativeMethods.sqlite3_result_error_nomem(pContext);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Sets the context result to the specified array
+ /// value.
+ ///
+ ///
+ /// The array value to use.
+ ///
+ public void SetBlob(byte[] value)
+ {
+ if (pContext == IntPtr.Zero)
+ throw new InvalidOperationException();
+
+ if (value == null)
+ throw new ArgumentNullException("value");
+
+ UnsafeNativeMethods.sqlite3_result_blob(
+ pContext, value, value.Length, (IntPtr)(-1));
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Sets the context result to a BLOB of zeros of the specified size.
+ ///
+ ///
+ /// The number of zero bytes to use for the BLOB context result.
+ ///
+ public void SetZeroBlob(int value)
+ {
+ if (pContext == IntPtr.Zero)
+ throw new InvalidOperationException();
+
+ UnsafeNativeMethods.sqlite3_result_zeroblob(pContext, value);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Sets the context result to the specified .
+ ///
+ ///
+ /// The to use.
+ ///
+ public void SetValue(SQLiteValue value)
+ {
+ if (pContext == IntPtr.Zero)
+ throw new InvalidOperationException();
+
+ if (value == null)
+ throw new ArgumentNullException("value");
+
+ UnsafeNativeMethods.sqlite3_result_value(
+ pContext, value.NativeHandle);
+ }
+ #endregion
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region SQLiteValue Helper Class
+ ///
+ /// This class represents a value from the SQLite core library that can be
+ /// passed to the sqlite3_value_*() and associated functions.
+ ///
+ public sealed class SQLiteValue : ISQLiteNativeHandle
+ {
+ #region Private Data
+ ///
+ /// The native value handle.
+ ///
+ private IntPtr pValue;
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Private Constructors
+ ///
+ /// Constructs an instance of this class using the specified native
+ /// value handle.
+ ///
+ ///
+ /// The native value handle to use.
+ ///
+ internal SQLiteValue(IntPtr pValue)
+ {
+ this.pValue = pValue;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Private Methods
+ ///
+ /// Invalidates the native value handle, thereby preventing further
+ /// access to it from this object instance.
+ ///
+ private void PreventNativeAccess()
+ {
+ pValue = IntPtr.Zero;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region ISQLiteNativeHandle Members
+ ///
+ /// Returns the underlying SQLite native handle associated with this
+ /// object instance.
+ ///
+ public IntPtr NativeHandle
+ {
+ get { return pValue; }
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Public Properties
+ private bool persisted;
+ ///
+ /// Returns non-zero if the native SQLite value has been successfully
+ /// persisted as a managed value within this object instance (i.e. the
+ /// property may then be read successfully).
+ ///
+ public bool Persisted
+ {
+ get { return persisted; }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ private object value;
+ ///
+ /// If the managed value for this object instance is available (i.e. it
+ /// has been previously persisted via the ) method,
+ /// that value is returned; otherwise, an exception is thrown. The
+ /// returned value may be null.
+ ///
+ public object Value
+ {
+ get
+ {
+ if (!persisted)
+ {
+ throw new InvalidOperationException(
+ "value was not persisted");
+ }
+
+ return value;
+ }
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Public Methods
+ ///
+ /// Gets and returns the type affinity associated with this value.
+ ///
+ ///
+ /// The type affinity associated with this value.
+ ///
+ public TypeAffinity GetTypeAffinity()
+ {
+ if (pValue == IntPtr.Zero) return TypeAffinity.None;
+ return UnsafeNativeMethods.sqlite3_value_type(pValue);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Gets and returns the number of bytes associated with this value, if
+ /// it refers to a UTF-8 encoded string.
+ ///
+ ///
+ /// The number of bytes associated with this value. The returned value
+ /// may be zero.
+ ///
+ public int GetBytes()
+ {
+ if (pValue == IntPtr.Zero) return 0;
+ return UnsafeNativeMethods.sqlite3_value_bytes(pValue);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Gets and returns the associated with this
+ /// value.
+ ///
+ ///
+ /// The associated with this value.
+ ///
+ public int GetInt()
+ {
+ if (pValue == IntPtr.Zero) return default(int);
+ return UnsafeNativeMethods.sqlite3_value_int(pValue);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Gets and returns the associated with
+ /// this value.
+ ///
+ ///
+ /// The associated with this value.
+ ///
+ public long GetInt64()
+ {
+ if (pValue == IntPtr.Zero) return default(long);
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ return UnsafeNativeMethods.sqlite3_value_int64(pValue);
+#elif !SQLITE_STANDARD
+ long value;
+ UnsafeNativeMethods.sqlite3_value_int64_interop(pValue, out value);
+ return value;
+#else
+ throw new NotImplementedException();
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Gets and returns the associated with this
+ /// value.
+ ///
+ ///
+ /// The associated with this value.
+ ///
+ public double GetDouble()
+ {
+ if (pValue == IntPtr.Zero) return default(double);
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ return UnsafeNativeMethods.sqlite3_value_double(pValue);
+#elif !SQLITE_STANDARD
+ double value;
+ UnsafeNativeMethods.sqlite3_value_double_interop(pValue, out value);
+ return value;
+#else
+ throw new NotImplementedException();
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Gets and returns the associated with this
+ /// value.
+ ///
+ ///
+ /// The associated with this value. The value is
+ /// converted from the UTF-8 encoding prior to being returned.
+ ///
+ public string GetString()
+ {
+ if (pValue == IntPtr.Zero) return null;
+ return SQLiteString.StringFromUtf8IntPtr(pValue, GetBytes());
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Gets and returns the array associated with this
+ /// value.
+ ///
+ ///
+ /// The array associated with this value.
+ ///
+ public byte[] GetBlob()
+ {
+ if (pValue == IntPtr.Zero) return null;
+ return SQLiteBytes.FromIntPtr(pValue, GetBytes());
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Uses the native value handle to obtain and store the managed value
+ /// for this object instance, thus saving it for later use. The type
+ /// of the managed value is determined by the type affinity of the
+ /// native value. If the type affinity is not recognized by this
+ /// method, no work is done and false is returned.
+ ///
+ ///
+ /// Non-zero if the native value was persisted successfully.
+ ///
+ public bool Persist()
+ {
+ switch (GetTypeAffinity())
+ {
+ case TypeAffinity.Uninitialized:
+ {
+ value = null;
+ PreventNativeAccess();
+ return (persisted = true);
+ }
+ case TypeAffinity.Int64:
+ {
+ value = GetInt64();
+ PreventNativeAccess();
+ return (persisted = true);
+ }
+ case TypeAffinity.Double:
+ {
+ value = GetDouble();
+ PreventNativeAccess();
+ return (persisted = true);
+ }
+ case TypeAffinity.Text:
+ {
+ value = GetString();
+ PreventNativeAccess();
+ return (persisted = true);
+ }
+ case TypeAffinity.Blob:
+ {
+ value = GetBytes();
+ PreventNativeAccess();
+ return (persisted = true);
+ }
+ case TypeAffinity.Null:
+ {
+ value = DBNull.Value;
+ PreventNativeAccess();
+ return (persisted = true);
+ }
+ default:
+ {
+ return false;
+ }
+ }
+ }
+ #endregion
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region SQLiteIndexConstraintOp Enumeration
+ ///
+ /// These are the allowed values for the operators that are part of a
+ /// constraint term in the WHERE clause of a query that uses a virtual
+ /// table.
+ ///
+ public enum SQLiteIndexConstraintOp : byte
+ {
+ ///
+ /// This value represents the equality operator.
+ ///
+ EqualTo = 2,
+
+ ///
+ /// This value represents the greater than operator.
+ ///
+ GreaterThan = 4,
+
+ ///
+ /// This value represents the less than or equal to operator.
+ ///
+ LessThanOrEqualTo = 8,
+
+ ///
+ /// This value represents the less than operator.
+ ///
+ LessThan = 16,
+
+ ///
+ /// This value represents the greater than or equal to operator.
+ ///
+ GreaterThanOrEqualTo = 32,
+
+ ///
+ /// This value represents the MATCH operator.
+ ///
+ Match = 64
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region SQLiteIndexConstraint Helper Class
+ ///
+ /// This class represents the native sqlite3_index_constraint structure
+ /// from the SQLite core library.
+ ///
+ public sealed class SQLiteIndexConstraint
+ {
+ #region Internal Constructors
+ ///
+ /// Constructs an instance of this class using the specified native
+ /// sqlite3_index_constraint structure.
+ ///
+ ///
+ /// The native sqlite3_index_constraint structure to use.
+ ///
+ internal SQLiteIndexConstraint(
+ UnsafeNativeMethods.sqlite3_index_constraint constraint
+ )
+ : this(constraint.iColumn, constraint.op, constraint.usable,
+ constraint.iTermOffset)
+ {
+ // do nothing.
+ }
+ #endregion
+
+ //////////////////////////////////////////////////////////////////////
+
+ #region Private Constructors
+ ///
+ /// Constructs an instance of this class using the specified field
+ /// values.
+ ///
+ ///
+ /// Column on left-hand side of constraint.
+ ///
+ ///
+ /// Constraint operator ().
+ ///
+ ///
+ /// True if this constraint is usable.
+ ///
+ ///
+ /// Used internally -
+ /// should ignore.
+ ///
+ private SQLiteIndexConstraint(
+ int iColumn,
+ SQLiteIndexConstraintOp op,
+ byte usable,
+ int iTermOffset
+ )
+ {
+ this.iColumn = iColumn;
+ this.op = op;
+ this.usable = usable;
+ this.iTermOffset = iTermOffset;
+ }
+ #endregion
+
+ //////////////////////////////////////////////////////////////////////
+
+ #region Public Fields
+ ///
+ /// Column on left-hand side of constraint.
+ ///
+ public int iColumn;
+
+ //////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Constraint operator ().
+ ///
+ public SQLiteIndexConstraintOp op;
+
+ //////////////////////////////////////////////////////////////////////
+
+ ///
+ /// True if this constraint is usable.
+ ///
+ public byte usable;
+
+ //////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Used internally -
+ /// should ignore.
+ ///
+ public int iTermOffset;
+ #endregion
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region SQLiteIndexOrderBy Helper Class
+ ///
+ /// This class represents the native sqlite3_index_orderby structure from
+ /// the SQLite core library.
+ ///
+ public sealed class SQLiteIndexOrderBy
+ {
+ #region Internal Constructors
+ ///
+ /// Constructs an instance of this class using the specified native
+ /// sqlite3_index_orderby structure.
+ ///
+ ///
+ /// The native sqlite3_index_orderby structure to use.
+ ///
+ internal SQLiteIndexOrderBy(
+ UnsafeNativeMethods.sqlite3_index_orderby orderBy
+ )
+ : this(orderBy.iColumn, orderBy.desc)
+ {
+ // do nothing.
+ }
+ #endregion
+
+ //////////////////////////////////////////////////////////////////////
+
+ #region Private Constructors
+ ///
+ /// Constructs an instance of this class using the specified field
+ /// values.
+ ///
+ ///
+ /// Column number.
+ ///
+ ///
+ /// True for DESC. False for ASC.
+ ///
+ private SQLiteIndexOrderBy(
+ int iColumn,
+ byte desc
+ )
+ {
+ this.iColumn = iColumn;
+ this.desc = desc;
+ }
+ #endregion
+
+ //////////////////////////////////////////////////////////////////////
+
+ #region Public Fields
+ ///
+ /// Column number.
+ ///
+ public int iColumn;
+
+ //////////////////////////////////////////////////////////////////////
+
+ ///
+ /// True for DESC. False for ASC.
+ ///
+ public byte desc;
+ #endregion
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region SQLiteIndexConstraintUsage Helper Class
+ ///
+ /// This class represents the native sqlite3_index_constraint_usage
+ /// structure from the SQLite core library.
+ ///
+ public sealed class SQLiteIndexConstraintUsage
+ {
+ #region Internal Constructors
+ ///
+ /// Constructs an instance of this class using the specified native
+ /// sqlite3_index_constraint_usage structure.
+ ///
+ ///
+ /// The native sqlite3_index_constraint_usage structure to use.
+ ///
+ internal SQLiteIndexConstraintUsage(
+ UnsafeNativeMethods.sqlite3_index_constraint_usage constraintUsage
+ )
+ : this(constraintUsage.argvIndex, constraintUsage.omit)
+ {
+ // do nothing.
+ }
+ #endregion
+
+ //////////////////////////////////////////////////////////////////////
+
+ #region Private Constructors
+ ///
+ /// Constructs an instance of this class using the specified field
+ /// values.
+ ///
+ ///
+ /// If greater than 0, constraint is part of argv to xFilter.
+ ///
+ ///
+ /// Do not code a test for this constraint.
+ ///
+ private SQLiteIndexConstraintUsage(
+ int argvIndex,
+ byte omit
+ )
+ {
+ this.argvIndex = argvIndex;
+ this.omit = omit;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Public Fields
+ ///
+ /// If greater than 0, constraint is part of argv to xFilter.
+ ///
+ public int argvIndex;
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Do not code a test for this constraint.
+ ///
+ public byte omit;
+ #endregion
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region SQLiteIndexInputs Helper Class
+ ///
+ /// This class represents the various inputs provided by the SQLite core
+ /// library to the method.
+ ///
+ public sealed class SQLiteIndexInputs
+ {
+ #region Internal Constructors
+ ///
+ /// Constructs an instance of this class.
+ ///
+ ///
+ /// The number of instances to
+ /// pre-allocate space for.
+ ///
+ ///
+ /// The number of instances to
+ /// pre-allocate space for.
+ ///
+ internal SQLiteIndexInputs(int nConstraint, int nOrderBy)
+ {
+ constraints = new SQLiteIndexConstraint[nConstraint];
+ orderBys = new SQLiteIndexOrderBy[nOrderBy];
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Public Properties
+ private SQLiteIndexConstraint[] constraints;
+ ///
+ /// An array of object instances,
+ /// each containing information supplied by the SQLite core library.
+ ///
+ public SQLiteIndexConstraint[] Constraints
+ {
+ get { return constraints; }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ private SQLiteIndexOrderBy[] orderBys;
+ ///
+ /// An array of object instances,
+ /// each containing information supplied by the SQLite core library.
+ ///
+ public SQLiteIndexOrderBy[] OrderBys
+ {
+ get { return orderBys; }
+ }
+ #endregion
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region SQLiteIndexOutputs Helper Class
+ ///
+ /// This class represents the various outputs provided to the SQLite core
+ /// library by the method.
+ ///
+ public sealed class SQLiteIndexOutputs
+ {
+ #region Internal Constructors
+ ///
+ /// Constructs an instance of this class.
+ ///
+ ///
+ /// The number of instances
+ /// to pre-allocate space for.
+ ///
+ internal SQLiteIndexOutputs(int nConstraint)
+ {
+ constraintUsages = new SQLiteIndexConstraintUsage[nConstraint];
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Public Properties
+ private SQLiteIndexConstraintUsage[] constraintUsages;
+ ///
+ /// An array of object
+ /// instances, each containing information to be supplied to the SQLite
+ /// core library.
+ ///
+ public SQLiteIndexConstraintUsage[] ConstraintUsages
+ {
+ get { return constraintUsages; }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ private int indexNumber;
+ ///
+ /// Number used to help identify the selected index. This value will
+ /// later be provided to the
+ /// method.
+ ///
+ public int IndexNumber
+ {
+ get { return indexNumber; }
+ set { indexNumber = value; }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ private string indexString;
+ ///
+ /// String used to help identify the selected index. This value will
+ /// later be provided to the
+ /// method.
+ ///
+ public string IndexString
+ {
+ get { return indexString; }
+ set { indexString = value; }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ private int needToFreeIndexString;
+ ///
+ /// Non-zero if the index string must be freed by the SQLite core
+ /// library.
+ ///
+ public int NeedToFreeIndexString
+ {
+ get { return needToFreeIndexString; }
+ set { needToFreeIndexString = value; }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ private int orderByConsumed;
+ ///
+ /// True if output is already ordered.
+ ///
+ public int OrderByConsumed
+ {
+ get { return orderByConsumed; }
+ set { orderByConsumed = value; }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ private double estimatedCost;
+ ///
+ /// Estimated cost of using this index.
+ ///
+ public double EstimatedCost
+ {
+ get { return estimatedCost; }
+ set { estimatedCost = value; }
+ }
+ #endregion
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region SQLiteIndex Helper Class
+ ///
+ /// This class represents the various inputs and outputs used with the
+ /// method.
+ ///
+ public sealed class SQLiteIndex
+ {
+ #region Internal Constructors
+ ///
+ /// Constructs an instance of this class.
+ ///
+ ///
+ /// The number of (and
+ /// ) instances to
+ /// pre-allocate space for.
+ ///
+ ///
+ /// The number of instances to
+ /// pre-allocate space for.
+ ///
+ internal SQLiteIndex(
+ int nConstraint,
+ int nOrderBy
+ )
+ {
+ inputs = new SQLiteIndexInputs(nConstraint, nOrderBy);
+ outputs = new SQLiteIndexOutputs(nConstraint);
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Public Properties
+ private SQLiteIndexInputs inputs;
+ ///
+ /// The object instance containing
+ /// the inputs to the
+ /// method.
+ ///
+ public SQLiteIndexInputs Inputs
+ {
+ get { return inputs; }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ private SQLiteIndexOutputs outputs;
+ ///
+ /// The object instance containing
+ /// the outputs from the
+ /// method.
+ ///
+ public SQLiteIndexOutputs Outputs
+ {
+ get { return outputs; }
+ }
+ #endregion
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region SQLiteVirtualTable Base Class
+ ///
+ /// This class represents a managed virtual table implementation. It is
+ /// not sealed and should be used as the base class for any user-defined
+ /// virtual table classes implemented in managed code.
+ ///
+ public class SQLiteVirtualTable :
+ ISQLiteNativeHandle, IDisposable /* NOT SEALED */
+ {
+ #region Private Constants
+ ///
+ /// The index within the array of strings provided to the
+ /// and
+ /// methods containing the
+ /// name of the module implementing this virtual table.
+ ///
+ private const int ModuleNameIndex = 0;
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// The index within the array of strings provided to the
+ /// and
+ /// methods containing the
+ /// name of the database containing this virtual table.
+ ///
+ private const int DatabaseNameIndex = 1;
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// The index within the array of strings provided to the
+ /// and
+ /// methods containing the
+ /// name of the virtual table.
+ ///
+ private const int TableNameIndex = 2;
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Public Constructors
+ ///
+ /// Constructs an instance of this class.
+ ///
+ ///
+ /// The original array of strings provided to the
+ /// and
+ /// methods.
+ ///
+ public SQLiteVirtualTable(
+ string[] arguments
+ )
+ {
+ this.arguments = arguments;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Public Properties
+ private string[] arguments;
+ ///
+ /// The original array of strings provided to the
+ /// and
+ /// methods.
+ ///
+ public virtual string[] Arguments
+ {
+ get { CheckDisposed(); return arguments; }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// The name of the module implementing this virtual table.
+ ///
+ public virtual string ModuleName
+ {
+ get
+ {
+ CheckDisposed();
+
+ string[] arguments = Arguments;
+
+ if ((arguments != null) &&
+ (arguments.Length > ModuleNameIndex))
+ {
+ return arguments[ModuleNameIndex];
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// The name of the database containing this virtual table.
+ ///
+ public virtual string DatabaseName
+ {
+ get
+ {
+ CheckDisposed();
+
+ string[] arguments = Arguments;
+
+ if ((arguments != null) &&
+ (arguments.Length > DatabaseNameIndex))
+ {
+ return arguments[DatabaseNameIndex];
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// The name of the virtual table.
+ ///
+ public virtual string TableName
+ {
+ get
+ {
+ CheckDisposed();
+
+ string[] arguments = Arguments;
+
+ if ((arguments != null) &&
+ (arguments.Length > TableNameIndex))
+ {
+ return arguments[TableNameIndex];
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Public Methods
+ ///
+ /// Attempts to record the renaming of the virtual table associated
+ /// with this object instance.
+ ///
+ ///
+ /// The new name for the virtual table.
+ ///
+ ///
+ /// Non-zero upon success.
+ ///
+ public virtual bool Rename(
+ string name
+ )
+ {
+ CheckDisposed();
+
+ if ((arguments != null) &&
+ (arguments.Length > TableNameIndex))
+ {
+ arguments[TableNameIndex] = name;
+ return true;
+ }
+
+ return false;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region ISQLiteNativeHandle Members
+ private IntPtr nativeHandle;
+ ///
+ /// Returns the underlying SQLite native handle associated with this
+ /// object instance.
+ ///
+ public virtual IntPtr NativeHandle
+ {
+ get { CheckDisposed(); return nativeHandle; }
+ internal set { nativeHandle = value; }
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region IDisposable Members
+ ///
+ /// Disposes of this object instance.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region IDisposable "Pattern" Members
+ private bool disposed;
+ ///
+ /// Throws an if this object
+ /// instance has been disposed.
+ ///
+ private void CheckDisposed() /* throw */
+ {
+#if THROW_ON_DISPOSED
+ if (disposed)
+ {
+ throw new ObjectDisposedException(
+ typeof(SQLiteVirtualTable).Name);
+ }
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Disposes of this object instance.
+ ///
+ ///
+ /// Non-zero if this method is being called from the
+ /// method. Zero if this method is being called
+ /// from the finalizer.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposed)
+ {
+ //if (disposing)
+ //{
+ // ////////////////////////////////////
+ // // dispose managed resources here...
+ // ////////////////////////////////////
+ //}
+
+ //////////////////////////////////////
+ // release unmanaged resources here...
+ //////////////////////////////////////
+
+ disposed = true;
+ }
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Destructor
+ ///
+ /// Finalizes this object instance.
+ ///
+ ~SQLiteVirtualTable()
+ {
+ Dispose(false);
+ }
+ #endregion
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region SQLiteVirtualTableCursor Base Class
+ ///
+ /// This class represents a managed virtual table cursor implementation.
+ /// It is not sealed and should be used as the base class for any
+ /// user-defined virtual table cursor classes implemented in managed code.
+ ///
+ public class SQLiteVirtualTableCursor :
+ ISQLiteNativeHandle, IDisposable /* NOT SEALED */
+ {
+ #region Public Constructors
+ ///
+ /// Constructs an instance of this class.
+ ///
+ ///
+ /// The object instance associated
+ /// with this object instance.
+ ///
+ public SQLiteVirtualTableCursor(
+ SQLiteVirtualTable table
+ )
+ {
+ this.table = table;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Public Properties
+ private SQLiteVirtualTable table;
+ ///
+ /// The object instance associated
+ /// with this object instance.
+ ///
+ public virtual SQLiteVirtualTable Table
+ {
+ get { CheckDisposed(); return table; }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ private int indexNumber;
+ ///
+ /// Number used to help identify the selected index. This value will
+ /// be set via the method.
+ ///
+ public virtual int IndexNumber
+ {
+ get { CheckDisposed(); return indexNumber; }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ private string indexString;
+ ///
+ /// String used to help identify the selected index. This value will
+ /// be set via the method.
+ ///
+ public virtual string IndexString
+ {
+ get { CheckDisposed(); return indexString; }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ private SQLiteValue[] values;
+ ///
+ /// The values used to filter the rows returned via this cursor object
+ /// instance. This value will be set via the
+ /// method.
+ ///
+ public virtual SQLiteValue[] Values
+ {
+ get { CheckDisposed(); return values; }
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Protected Methods
+ ///
+ /// Attempts to persist the specified object
+ /// instances in order to make them available after the
+ /// method returns.
+ ///
+ ///
+ /// The array of object instances to be
+ /// persisted.
+ ///
+ ///
+ /// The number of object instances that were
+ /// successfully persisted.
+ ///
+ protected virtual int TryPersistValues(
+ SQLiteValue[] values
+ )
+ {
+ int result = 0;
+
+ if (values != null)
+ {
+ foreach (SQLiteValue value in values)
+ {
+ if (value == null)
+ continue;
+
+ if (value.Persist())
+ result++;
+ }
+ }
+
+ return result;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Public Methods
+ ///
+ /// This method should normally be used by the
+ /// method in order to
+ /// perform filtering of the result rows and/or to record the filtering
+ /// criteria provided by the SQLite core library.
+ ///
+ ///
+ /// Number used to help identify the selected index.
+ ///
+ ///
+ /// String used to help identify the selected index.
+ ///
+ ///
+ /// The values corresponding to each column in the selected index.
+ ///
+ public virtual void Filter(
+ int indexNumber,
+ string indexString,
+ SQLiteValue[] values
+ )
+ {
+ CheckDisposed();
+
+ if ((values != null) &&
+ (TryPersistValues(values) != values.Length))
+ {
+ throw new SQLiteException(
+ "failed to persist one or more values");
+ }
+
+ this.indexNumber = indexNumber;
+ this.indexString = indexString;
+ this.values = values;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region ISQLiteNativeHandle Members
+ private IntPtr nativeHandle;
+ ///
+ /// Returns the underlying SQLite native handle associated with this
+ /// object instance.
+ ///
+ public virtual IntPtr NativeHandle
+ {
+ get { CheckDisposed(); return nativeHandle; }
+ internal set { nativeHandle = value; }
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region IDisposable Members
+ ///
+ /// Disposes of this object instance.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region IDisposable "Pattern" Members
+ private bool disposed;
+ ///
+ /// Throws an if this object
+ /// instance has been disposed.
+ ///
+ private void CheckDisposed() /* throw */
+ {
+#if THROW_ON_DISPOSED
+ if (disposed)
+ {
+ throw new ObjectDisposedException(
+ typeof(SQLiteVirtualTableCursor).Name);
+ }
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Disposes of this object instance.
+ ///
+ ///
+ /// Non-zero if this method is being called from the
+ /// method. Zero if this method is being called
+ /// from the finalizer.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposed)
+ {
+ //if (disposing)
+ //{
+ // ////////////////////////////////////
+ // // dispose managed resources here...
+ // ////////////////////////////////////
+ //}
+
+ //////////////////////////////////////
+ // release unmanaged resources here...
+ //////////////////////////////////////
+
+ disposed = true;
+ }
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Destructor
+ ///
+ /// Finalizes this object instance.
+ ///
+ ~SQLiteVirtualTableCursor()
+ {
+ Dispose(false);
+ }
+ #endregion
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region ISQLiteNativeHandle Interface
+ ///
+ /// This interface represents a native handle provided by the SQLite core
+ /// library.
+ ///
+ public interface ISQLiteNativeHandle
+ {
+ ///
+ /// The native handle value.
+ ///
+ IntPtr NativeHandle { get; }
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region ISQLiteNativeModule Interface
+ ///
+ /// This interface represents a virtual table implementation written in
+ /// native code.
+ ///
+ public interface ISQLiteNativeModule
+ {
+ ///
+ ///
+ /// This method is called to create a new instance of a virtual table
+ /// in response to a CREATE VIRTUAL TABLE statement. The db parameter
+ /// is a pointer to the SQLite database connection that is executing
+ /// the CREATE VIRTUAL TABLE statement. The pAux argument is the copy
+ /// of the client data pointer that was the fourth argument to the
+ /// sqlite3_create_module() or sqlite3_create_module_v2() call that
+ /// registered the virtual table module. The argv parameter is an
+ /// array of argc pointers to null terminated strings. The first
+ /// string, argv[0], is the name of the module being invoked. The
+ /// module name is the name provided as the second argument to
+ /// sqlite3_create_module() and as the argument to the USING clause of
+ /// the CREATE VIRTUAL TABLE statement that is running. The second,
+ /// argv[1], is the name of the database in which the new virtual table
+ /// is being created. The database name is "main" for the primary
+ /// database, or "temp" for TEMP database, or the name given at the
+ /// end of the ATTACH statement for attached databases. The third
+ /// element of the array, argv[2], is the name of the new virtual
+ /// table, as specified following the TABLE keyword in the CREATE
+ /// VIRTUAL TABLE statement. If present, the fourth and subsequent
+ /// strings in the argv[] array report the arguments to the module name
+ /// in the CREATE VIRTUAL TABLE statement.
+ ///
+ ///
+ /// The job of this method is to construct the new virtual table object
+ /// (an sqlite3_vtab object) and return a pointer to it in *ppVTab.
+ ///
+ ///
+ /// As part of the task of creating a new sqlite3_vtab structure, this
+ /// method must invoke sqlite3_declare_vtab() to tell the SQLite core
+ /// about the columns and datatypes in the virtual table. The
+ /// sqlite3_declare_vtab() API has the following prototype:
+ ///
+ ///
+ ///
+ /// int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable)
+ ///
+ ///
+ ///
+ /// The first argument to sqlite3_declare_vtab() must be the same
+ /// database connection pointer as the first parameter to this method.
+ /// The second argument to sqlite3_declare_vtab() must a
+ /// zero-terminated UTF-8 string that contains a well-formed CREATE
+ /// TABLE statement that defines the columns in the virtual table and
+ /// their data types. The name of the table in this CREATE TABLE
+ /// statement is ignored, as are all constraints. Only the column names
+ /// and datatypes matter. The CREATE TABLE statement string need not to
+ /// be held in persistent memory. The string can be deallocated and/or
+ /// reused as soon as the sqlite3_declare_vtab() routine returns.
+ ///
+ ///
+ ///
+ /// The native database connection handle.
+ ///
+ ///
+ /// The original native pointer value that was provided to the
+ /// sqlite3_create_module(), sqlite3_create_module_v2() or
+ /// sqlite3_create_disposable_module() functions.
+ ///
+ ///
+ /// The number of arguments from the CREATE VIRTUAL TABLE statement.
+ ///
+ ///
+ /// The array of string arguments from the CREATE VIRTUAL TABLE
+ /// statement.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to point to the newly
+ /// created native sqlite3_vtab derived structure.
+ ///
+ ///
+ /// Upon failure, this parameter must be modified to point to the error
+ /// message, with the underlying memory having been obtained from the
+ /// sqlite3_malloc() function.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xCreate(
+ IntPtr pDb,
+ IntPtr pAux,
+ int argc,
+ IntPtr argv,
+ ref IntPtr pVtab,
+ ref IntPtr pError
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// The xConnect method is very similar to xCreate. It has the same
+ /// parameters and constructs a new sqlite3_vtab structure just like
+ /// xCreate. And it must also call sqlite3_declare_vtab() like xCreate.
+ ///
+ ///
+ /// The difference is that xConnect is called to establish a new
+ /// connection to an existing virtual table whereas xCreate is called
+ /// to create a new virtual table from scratch.
+ ///
+ ///
+ /// The xCreate and xConnect methods are only different when the
+ /// virtual table has some kind of backing store that must be
+ /// initialized the first time the virtual table is created. The
+ /// xCreate method creates and initializes the backing store. The
+ /// xConnect method just connects to an existing backing store.
+ ///
+ ///
+ /// As an example, consider a virtual table implementation that
+ /// provides read-only access to existing comma-separated-value (CSV)
+ /// files on disk. There is no backing store that needs to be created
+ /// or initialized for such a virtual table (since the CSV files
+ /// already exist on disk) so the xCreate and xConnect methods will be
+ /// identical for that module.
+ ///
+ ///
+ /// Another example is a virtual table that implements a full-text
+ /// index. The xCreate method must create and initialize data
+ /// structures to hold the dictionary and posting lists for that index.
+ /// The xConnect method, on the other hand, only has to locate and use
+ /// an existing dictionary and posting lists that were created by a
+ /// prior xCreate call.
+ ///
+ ///
+ /// The xConnect method must return SQLITE_OK if it is successful in
+ /// creating the new virtual table, or SQLITE_ERROR if it is not
+ /// successful. If not successful, the sqlite3_vtab structure must not
+ /// be allocated. An error message may optionally be returned in *pzErr
+ /// if unsuccessful. Space to hold the error message string must be
+ /// allocated using an SQLite memory allocation function like
+ /// sqlite3_malloc() or sqlite3_mprintf() as the SQLite core will
+ /// attempt to free the space using sqlite3_free() after the error has
+ /// been reported up to the application.
+ ///
+ ///
+ /// The xConnect method is required for every virtual table
+ /// implementation, though the xCreate and xConnect pointers of the
+ /// sqlite3_module object may point to the same function the virtual
+ /// table does not need to initialize backing store.
+ ///
+ ///
+ ///
+ /// The native database connection handle.
+ ///
+ ///
+ /// The original native pointer value that was provided to the
+ /// sqlite3_create_module(), sqlite3_create_module_v2() or
+ /// sqlite3_create_disposable_module() functions.
+ ///
+ ///
+ /// The number of arguments from the CREATE VIRTUAL TABLE statement.
+ ///
+ ///
+ /// The array of string arguments from the CREATE VIRTUAL TABLE
+ /// statement.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to point to the newly
+ /// created native sqlite3_vtab derived structure.
+ ///
+ ///
+ /// Upon failure, this parameter must be modified to point to the error
+ /// message, with the underlying memory having been obtained from the
+ /// sqlite3_malloc() function.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xConnect(
+ IntPtr pDb,
+ IntPtr pAux,
+ int argc,
+ IntPtr argv,
+ ref IntPtr pVtab,
+ ref IntPtr pError
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// SQLite uses the xBestIndex method of a virtual table module to
+ /// determine the best way to access the virtual table. The xBestIndex
+ /// method has a prototype like this:
+ ///
+ ///
+ /// int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*);
+ ///
+ ///
+ /// The SQLite core communicates with the xBestIndex method by filling
+ /// in certain fields of the sqlite3_index_info structure and passing a
+ /// pointer to that structure into xBestIndex as the second parameter.
+ /// The xBestIndex method fills out other fields of this structure
+ /// which forms the reply. The sqlite3_index_info structure looks like
+ /// this:
+ ///
+ ///
+ /// struct sqlite3_index_info {
+ /// /* Inputs */
+ /// const int nConstraint; /* Number of entries in aConstraint */
+ /// const struct sqlite3_index_constraint {
+ /// int iColumn; /* Column on left-hand side of
+ /// * constraint */
+ /// unsigned char op; /* Constraint operator */
+ /// unsigned char usable; /* True if this constraint is usable */
+ /// int iTermOffset; /* Used internally - xBestIndex should
+ /// * ignore */
+ /// } *const aConstraint; /* Table of WHERE clause constraints */
+ /// const int nOrderBy; /* Number of terms in the ORDER BY
+ /// * clause */
+ /// const struct sqlite3_index_orderby {
+ /// int iColumn; /* Column number */
+ /// unsigned char desc; /* True for DESC. False for ASC. */
+ /// } *const aOrderBy; /* The ORDER BY clause */
+ /// /* Outputs */
+ /// struct sqlite3_index_constraint_usage {
+ /// int argvIndex; /* if greater than zero, constraint is
+ /// * part of argv to xFilter */
+ /// unsigned char omit; /* Do not code a test for this
+ /// * constraint */
+ /// } *const aConstraintUsage;
+ /// int idxNum; /* Number used to identify the index */
+ /// char *idxStr; /* String, possibly obtained from
+ /// * sqlite3_malloc() */
+ /// int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if
+ /// * true */
+ /// int orderByConsumed; /* True if output is already ordered */
+ /// double estimatedCost; /* Estimated cost of using this index */
+ /// };
+ ///
+ ///
+ /// In addition, there are some defined constants:
+ ///
+ ///
+ /// #define SQLITE_INDEX_CONSTRAINT_EQ 2
+ /// #define SQLITE_INDEX_CONSTRAINT_GT 4
+ /// #define SQLITE_INDEX_CONSTRAINT_LE 8
+ /// #define SQLITE_INDEX_CONSTRAINT_LT 16
+ /// #define SQLITE_INDEX_CONSTRAINT_GE 32
+ /// #define SQLITE_INDEX_CONSTRAINT_MATCH 64
+ ///
+ ///
+ /// The SQLite core calls the xBestIndex method when it is compiling a
+ /// query that involves a virtual table. In other words, SQLite calls
+ /// this method when it is running sqlite3_prepare() or the equivalent.
+ /// By calling this method, the SQLite core is saying to the virtual
+ /// table that it needs to access some subset of the rows in the
+ /// virtual table and it wants to know the most efficient way to do
+ /// that access. The xBestIndex method replies with information that
+ /// the SQLite core can then use to conduct an efficient search of the
+ /// virtual table.
+ ///
+ ///
+ /// While compiling a single SQL query, the SQLite core might call
+ /// xBestIndex multiple times with different settings in
+ /// sqlite3_index_info. The SQLite core will then select the
+ /// combination that appears to give the best performance.
+ ///
+ ///
+ /// Before calling this method, the SQLite core initializes an instance
+ /// of the sqlite3_index_info structure with information about the
+ /// query that it is currently trying to process. This information
+ /// derives mainly from the WHERE clause and ORDER BY or GROUP BY
+ /// clauses of the query, but also from any ON or USING clauses if the
+ /// query is a join. The information that the SQLite core provides to
+ /// the xBestIndex method is held in the part of the structure that is
+ /// marked as "Inputs". The "Outputs" section is initialized to zero.
+ ///
+ ///
+ /// The information in the sqlite3_index_info structure is ephemeral
+ /// and may be overwritten or deallocated as soon as the xBestIndex
+ /// method returns. If the xBestIndex method needs to remember any part
+ /// of the sqlite3_index_info structure, it should make a copy. Care
+ /// must be take to store the copy in a place where it will be
+ /// deallocated, such as in the idxStr field with needToFreeIdxStr set
+ /// to 1.
+ ///
+ ///
+ /// Note that xBestIndex will always be called before xFilter, since
+ /// the idxNum and idxStr outputs from xBestIndex are required inputs
+ /// to xFilter. However, there is no guarantee that xFilter will be
+ /// called following a successful xBestIndex.
+ ///
+ ///
+ /// The xBestIndex method is required for every virtual table
+ /// implementation.
+ ///
+ ///
+ /// 2.3.1 Inputs
+ ///
+ ///
+ /// The main thing that the SQLite core is trying to communicate to the
+ /// virtual table is the constraints that are available to limit the
+ /// number of rows that need to be searched. The aConstraint[] array
+ /// contains one entry for each constraint. There will be exactly
+ /// nConstraint entries in that array.
+ ///
+ ///
+ /// Each constraint will correspond to a term in the WHERE clause or in
+ /// a USING or ON clause that is of the form
+ ///
+ ///
+ /// column OP EXPR
+ ///
+ ///
+ /// Where "column" is a column in the virtual table, OP is an operator
+ /// like "=" or "<", and EXPR is an arbitrary expression. So, for
+ /// example, if the WHERE clause contained a term like this:
+ ///
+ ///
+ /// a = 5
+ ///
+ ///
+ /// Then one of the constraints would be on the "a" column with
+ /// operator "=" and an expression of "5". Constraints need not have a
+ /// literal representation of the WHERE clause. The query optimizer
+ /// might make transformations to the WHERE clause in order to extract
+ /// as many constraints as it can. So, for example, if the WHERE clause
+ /// contained something like this:
+ ///
+ ///
+ /// x BETWEEN 10 AND 100 AND 999>y
+ ///
+ ///
+ /// The query optimizer might translate this into three separate
+ /// constraints:
+ ///
+ ///
+ /// x >= 10
+ /// x <= 100
+ /// y < 999
+ ///
+ ///
+ /// For each constraint, the aConstraint[].iColumn field indicates
+ /// which column appears on the left-hand side of the constraint. The
+ /// first column of the virtual table is column 0. The rowid of the
+ /// virtual table is column -1. The aConstraint[].op field indicates
+ /// which operator is used. The SQLITE_INDEX_CONSTRAINT_* constants map
+ /// integer constants into operator values. Columns occur in the order
+ /// they were defined by the call to sqlite3_declare_vtab() in the
+ /// xCreate or xConnect method. Hidden columns are counted when
+ /// determining the column index.
+ ///
+ ///
+ /// The aConstraint[] array contains information about all constraints
+ /// that apply to the virtual table. But some of the constraints might
+ /// not be usable because of the way tables are ordered in a join. The
+ /// xBestIndex method must therefore only consider constraints that
+ /// have an aConstraint[].usable flag which is true.
+ ///
+ ///
+ /// In addition to WHERE clause constraints, the SQLite core also tells
+ /// the xBestIndex method about the ORDER BY clause. (In an aggregate
+ /// query, the SQLite core might put in GROUP BY clause information in
+ /// place of the ORDER BY clause information, but this fact should not
+ /// make any difference to the xBestIndex method.) If all terms of the
+ /// ORDER BY clause are columns in the virtual table, then nOrderBy
+ /// will be the number of terms in the ORDER BY clause and the
+ /// aOrderBy[] array will identify the column for each term in the
+ /// order by clause and whether or not that column is ASC or DESC.
+ ///
+ ///
+ /// 2.3.2 Outputs
+ ///
+ ///
+ /// Given all of the information above, the job of the xBestIndex
+ /// method it to figure out the best way to search the virtual table.
+ ///
+ ///
+ /// The xBestIndex method fills the idxNum and idxStr fields with
+ /// information that communicates an indexing strategy to the xFilter
+ /// method. The information in idxNum and idxStr is arbitrary as far as
+ /// the SQLite core is concerned. The SQLite core just copies the
+ /// information through to the xFilter method. Any desired meaning can
+ /// be assigned to idxNum and idxStr as long as xBestIndex and xFilter
+ /// agree on what that meaning is.
+ ///
+ ///
+ /// The idxStr value may be a string obtained from an SQLite memory
+ /// allocation function such as sqlite3_mprintf(). If this is the case,
+ /// then the needToFreeIdxStr flag must be set to true so that the
+ /// SQLite core will know to call sqlite3_free() on that string when it
+ /// has finished with it, and thus avoid a memory leak.
+ ///
+ ///
+ /// If the virtual table will output rows in the order specified by the
+ /// ORDER BY clause, then the orderByConsumed flag may be set to true.
+ /// If the output is not automatically in the correct order then
+ /// orderByConsumed must be left in its default false setting. This
+ /// will indicate to the SQLite core that it will need to do a separate
+ /// sorting pass over the data after it comes out of the virtual table.
+ ///
+ ///
+ /// The estimatedCost field should be set to the estimated number of
+ /// disk access operations required to execute this query against the
+ /// virtual table. The SQLite core will often call xBestIndex multiple
+ /// times with different constraints, obtain multiple cost estimates,
+ /// then choose the query plan that gives the lowest estimate.
+ ///
+ ///
+ /// The aConstraintUsage[] array contains one element for each of the
+ /// nConstraint constraints in the inputs section of the
+ /// sqlite3_index_info structure. The aConstraintUsage[] array is used
+ /// by xBestIndex to tell the core how it is using the constraints.
+ ///
+ ///
+ /// The xBestIndex method may set aConstraintUsage[].argvIndex entries
+ /// to values greater than one. Exactly one entry should be set to 1,
+ /// another to 2, another to 3, and so forth up to as many or as few as
+ /// the xBestIndex method wants. The EXPR of the corresponding
+ /// constraints will then be passed in as the argv[] parameters to
+ /// xFilter.
+ ///
+ ///
+ /// For example, if the aConstraint[3].argvIndex is set to 1, then when
+ /// xFilter is called, the argv[0] passed to xFilter will have the EXPR
+ /// value of the aConstraint[3] constraint.
+ ///
+ ///
+ /// By default, the SQLite core double checks all constraints on each
+ /// row of the virtual table that it receives. If such a check is
+ /// redundant, the xBestFilter method can suppress that double-check by
+ /// setting aConstraintUsage[].omit.
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// The native pointer to the sqlite3_index_info structure.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xBestIndex(
+ IntPtr pVtab,
+ IntPtr pIndex
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// This method releases a connection to a virtual table. Only the
+ /// sqlite3_vtab object is destroyed. The virtual table is not
+ /// destroyed and any backing store associated with the virtual table
+ /// persists. This method undoes the work of xConnect.
+ ///
+ ///
+ /// This method is a destructor for a connection to the virtual table.
+ /// Contrast this method with xDestroy. The xDestroy is a destructor
+ /// for the entire virtual table.
+ ///
+ ///
+ /// The xDisconnect method is required for every virtual table
+ /// implementation, though it is acceptable for the xDisconnect and
+ /// xDestroy methods to be the same function if that makes sense for
+ /// the particular virtual table.
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xDisconnect(
+ IntPtr pVtab
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// This method releases a connection to a virtual table, just like the
+ /// xDisconnect method, and it also destroys the underlying table
+ /// implementation. This method undoes the work of xCreate.
+ ///
+ ///
+ /// The xDisconnect method is called whenever a database connection
+ /// that uses a virtual table is closed. The xDestroy method is only
+ /// called when a DROP TABLE statement is executed against the virtual
+ /// table.
+ ///
+ ///
+ /// The xDestroy method is required for every virtual table
+ /// implementation, though it is acceptable for the xDisconnect and
+ /// xDestroy methods to be the same function if that makes sense for
+ /// the particular virtual table.
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xDestroy(
+ IntPtr pVtab
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// The xOpen method creates a new cursor used for accessing (read
+ /// and/or writing) a virtual table. A successful invocation of this
+ /// method will allocate the memory for the sqlite3_vtab_cursor (or a
+ /// subclass), initialize the new object, and make *ppCursor point to
+ /// the new object. The successful call then returns SQLITE_OK.
+ ///
+ ///
+ /// For every successful call to this method, the SQLite core will
+ /// later invoke the xClose method to destroy the allocated cursor.
+ ///
+ ///
+ /// The xOpen method need not initialize the pVtab field of the
+ /// sqlite3_vtab_cursor structure. The SQLite core will take care of
+ /// that chore automatically.
+ ///
+ ///
+ /// A virtual table implementation must be able to support an arbitrary
+ /// number of simultaneously open cursors.
+ ///
+ ///
+ /// When initially opened, the cursor is in an undefined state. The
+ /// SQLite core will invoke the xFilter method on the cursor prior to
+ /// any attempt to position or read from the cursor.
+ ///
+ ///
+ /// The xOpen method is required for every virtual table
+ /// implementation.
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to point to the newly
+ /// created native sqlite3_vtab_cursor derived structure.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xOpen(
+ IntPtr pVtab,
+ ref IntPtr pCursor
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// The xClose method closes a cursor previously opened by xOpen. The
+ /// SQLite core will always call xClose once for each cursor opened
+ /// using xOpen.
+ ///
+ ///
+ /// This method must release all resources allocated by the
+ /// corresponding xOpen call. The routine will not be called again even
+ /// if it returns an error. The SQLite core will not use the
+ /// sqlite3_vtab_cursor again after it has been closed.
+ ///
+ ///
+ /// The xClose method is required for every virtual table
+ /// implementation.
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab_cursor derived structure.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xClose(
+ IntPtr pCursor
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// This method begins a search of a virtual table. The first argument
+ /// is a cursor opened by xOpen. The next two argument define a
+ /// particular search index previously chosen by xBestIndex. The
+ /// specific meanings of idxNum and idxStr are unimportant as long as
+ /// xFilter and xBestIndex agree on what that meaning is.
+ ///
+ ///
+ /// The xBestIndex function may have requested the values of certain
+ /// expressions using the aConstraintUsage[].argvIndex values of the
+ /// sqlite3_index_info structure. Those values are passed to xFilter
+ /// using the argc and argv parameters.
+ ///
+ ///
+ /// If the virtual table contains one or more rows that match the
+ /// search criteria, then the cursor must be left point at the first
+ /// row. Subsequent calls to xEof must return false (zero). If there
+ /// are no rows match, then the cursor must be left in a state that
+ /// will cause the xEof to return true (non-zero). The SQLite engine
+ /// will use the xColumn and xRowid methods to access that row content.
+ /// The xNext method will be used to advance to the next row.
+ ///
+ ///
+ /// This method must return SQLITE_OK if successful, or an sqlite error
+ /// code if an error occurs.
+ ///
+ ///
+ /// The xFilter method is required for every virtual table
+ /// implementation.
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab_cursor derived structure.
+ ///
+ ///
+ /// Number used to help identify the selected index.
+ ///
+ ///
+ /// The native pointer to the UTF-8 encoded string containing the
+ /// string used to help identify the selected index.
+ ///
+ ///
+ /// The number of native pointers to sqlite3_value structures specified
+ /// in .
+ ///
+ ///
+ /// An array of native pointers to sqlite3_value structures containing
+ /// filtering criteria for the selected index.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xFilter(
+ IntPtr pCursor,
+ int idxNum,
+ IntPtr idxStr,
+ int argc,
+ IntPtr argv
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// The xNext method advances a virtual table cursor to the next row of
+ /// a result set initiated by xFilter. If the cursor is already
+ /// pointing at the last row when this routine is called, then the
+ /// cursor no longer points to valid data and a subsequent call to the
+ /// xEof method must return true (non-zero). If the cursor is
+ /// successfully advanced to another row of content, then subsequent
+ /// calls to xEof must return false (zero).
+ ///
+ ///
+ /// This method must return SQLITE_OK if successful, or an sqlite error
+ /// code if an error occurs.
+ ///
+ ///
+ /// The xNext method is required for every virtual table
+ /// implementation.
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab_cursor derived structure.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xNext(
+ IntPtr pCursor
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// The xEof method must return false (zero) if the specified cursor
+ /// currently points to a valid row of data, or true (non-zero)
+ /// otherwise. This method is called by the SQL engine immediately
+ /// after each xFilter and xNext invocation.
+ ///
+ ///
+ /// The xEof method is required for every virtual table implementation.
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab_cursor derived structure.
+ ///
+ ///
+ /// Non-zero if no more rows are available; zero otherwise.
+ ///
+ int xEof(
+ IntPtr pCursor
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// The SQLite core invokes this method in order to find the value for
+ /// the N-th column of the current row. N is zero-based so the first
+ /// column is numbered 0. The xColumn method may return its result back
+ /// to SQLite using one of the following interface:
+ ///
+ ///
+ /// sqlite3_result_blob()
+ /// sqlite3_result_double()
+ /// sqlite3_result_int()
+ /// sqlite3_result_int64()
+ /// sqlite3_result_null()
+ /// sqlite3_result_text()
+ /// sqlite3_result_text16()
+ /// sqlite3_result_text16le()
+ /// sqlite3_result_text16be()
+ /// sqlite3_result_zeroblob()
+ ///
+ ///
+ /// If the xColumn method implementation calls none of the functions
+ /// above, then the value of the column defaults to an SQL NULL.
+ ///
+ ///
+ /// To raise an error, the xColumn method should use one of the
+ /// result_text() methods to set the error message text, then return an
+ /// appropriate error code. The xColumn method must return SQLITE_OK on
+ /// success.
+ ///
+ ///
+ /// The xColumn method is required for every virtual table
+ /// implementation.
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab_cursor derived structure.
+ ///
+ ///
+ /// The native pointer to the sqlite3_context structure to be used
+ /// for returning the specified column value to the SQLite core
+ /// library.
+ ///
+ ///
+ /// The zero-based index corresponding to the column containing the
+ /// value to be returned.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xColumn(
+ IntPtr pCursor,
+ IntPtr pContext,
+ int index
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// A successful invocation of this method will cause *pRowid to be
+ /// filled with the rowid of row that the virtual table cursor pCur is
+ /// currently pointing at. This method returns SQLITE_OK on success. It
+ /// returns an appropriate error code on failure.
+ ///
+ ///
+ /// The xRowid method is required for every virtual table
+ /// implementation.
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab_cursor derived structure.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to contain the unique
+ /// integer row identifier for the current row for the specified cursor.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xRowId(
+ IntPtr pCursor,
+ ref long rowId
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// All changes to a virtual table are made using the xUpdate method.
+ /// This one method can be used to insert, delete, or update.
+ ///
+ ///
+ /// The argc parameter specifies the number of entries in the argv
+ /// array. The value of argc will be 1 for a pure delete operation or
+ /// N+2 for an insert or replace or update where N is the number of
+ /// columns in the table. In the previous sentence, N includes any
+ /// hidden columns.
+ ///
+ ///
+ /// Every argv entry will have a non-NULL value in C but may contain
+ /// the SQL value NULL. In other words, it is always true that
+ /// argv[i]!=0 for i between 0 and argc-1. However, it might be the
+ /// case that sqlite3_value_type(argv[i])==SQLITE_NULL.
+ ///
+ ///
+ /// The argv[0] parameter is the rowid of a row in the virtual table
+ /// to be deleted. If argv[0] is an SQL NULL, then no deletion occurs.
+ ///
+ ///
+ /// The argv[1] parameter is the rowid of a new row to be inserted into
+ /// the virtual table. If argv[1] is an SQL NULL, then the
+ /// implementation must choose a rowid for the newly inserted row.
+ /// Subsequent argv[] entries contain values of the columns of the
+ /// virtual table, in the order that the columns were declared. The
+ /// number of columns will match the table declaration that the
+ /// xConnect or xCreate method made using the sqlite3_declare_vtab()
+ /// call. All hidden columns are included.
+ ///
+ ///
+ /// When doing an insert without a rowid (argc>1, argv[1] is an SQL
+ /// NULL), the implementation must set *pRowid to the rowid of the
+ /// newly inserted row; this will become the value returned by the
+ /// sqlite3_last_insert_rowid() function. Setting this value in all the
+ /// other cases is a harmless no-op; the SQLite engine ignores the
+ /// *pRowid return value if argc==1 or argv[1] is not an SQL NULL.
+ ///
+ ///
+ /// Each call to xUpdate will fall into one of cases shown below. Note
+ /// that references to argv[i] mean the SQL value held within the
+ /// argv[i] object, not the argv[i] object itself.
+ ///
+ ///
+ /// argc = 1
+ ///
+ ///
+ /// The single row with rowid equal to argv[0] is deleted. No
+ /// insert occurs.
+ ///
+ ///
+ /// argc > 1
+ /// argv[0] = NULL
+ ///
+ ///
+ /// A new row is inserted with a rowid argv[1] and column
+ /// values in argv[2] and following. If argv[1] is an SQL NULL,
+ /// the a new unique rowid is generated automatically.
+ ///
+ ///
+ /// argc > 1
+ /// argv[0] ? NULL
+ /// argv[0] = argv[1]
+ ///
+ ///
+ /// The row with rowid argv[0] is updated with new values in
+ /// argv[2] and following parameters.
+ ///
+ ///
+ /// argc > 1
+ /// argv[0] ? NULL
+ /// argv[0] ? argv[1]
+ ///
+ ///
+ /// The row with rowid argv[0] is updated with rowid argv[1]
+ /// and new values in argv[2] and following parameters. This
+ /// will occur when an SQL statement updates a rowid, as in
+ /// the statement:
+ ///
+ ///
+ /// UPDATE table SET rowid=rowid+1 WHERE ...;
+ ///
+ ///
+ /// The xUpdate method must return SQLITE_OK if and only if it is
+ /// successful. If a failure occurs, the xUpdate must return an
+ /// appropriate error code. On a failure, the pVTab->zErrMsg element
+ /// may optionally be replaced with error message text stored in memory
+ /// allocated from SQLite using functions such as sqlite3_mprintf() or
+ /// sqlite3_malloc().
+ ///
+ ///
+ /// If the xUpdate method violates some constraint of the virtual table
+ /// (including, but not limited to, attempting to store a value of the
+ /// wrong datatype, attempting to store a value that is too large or
+ /// too small, or attempting to change a read-only value) then the
+ /// xUpdate must fail with an appropriate error code.
+ ///
+ ///
+ /// There might be one or more sqlite3_vtab_cursor objects open and in
+ /// use on the virtual table instance and perhaps even on the row of
+ /// the virtual table when the xUpdate method is invoked. The
+ /// implementation of xUpdate must be prepared for attempts to delete
+ /// or modify rows of the table out from other existing cursors. If the
+ /// virtual table cannot accommodate such changes, the xUpdate method
+ /// must return an error code.
+ ///
+ ///
+ /// The xUpdate method is optional. If the xUpdate pointer in the
+ /// sqlite3_module for a virtual table is a NULL pointer, then the
+ /// virtual table is read-only.
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// The number of new or modified column values contained in
+ /// .
+ ///
+ ///
+ /// The array of native pointers to sqlite3_value structures containing
+ /// the new or modified column values, if any.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to contain the unique
+ /// integer row identifier for the row that was inserted, if any.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xUpdate(
+ IntPtr pVtab,
+ int argc,
+ IntPtr argv,
+ ref long rowId
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// This method begins a transaction on a virtual table. This is method
+ /// is optional. The xBegin pointer of sqlite3_module may be NULL.
+ ///
+ ///
+ /// This method is always followed by one call to either the xCommit or
+ /// xRollback method. Virtual table transactions do not nest, so the
+ /// xBegin method will not be invoked more than once on a single
+ /// virtual table without an intervening call to either xCommit or
+ /// xRollback. Multiple calls to other methods can and likely will
+ /// occur in between the xBegin and the corresponding xCommit or
+ /// xRollback.
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xBegin(
+ IntPtr pVtab
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// This method signals the start of a two-phase commit on a virtual
+ /// table. This is method is optional. The xSync pointer of
+ /// sqlite3_module may be NULL.
+ ///
+ ///
+ /// This method is only invoked after call to the xBegin method and
+ /// prior to an xCommit or xRollback. In order to implement two-phase
+ /// commit, the xSync method on all virtual tables is invoked prior to
+ /// invoking the xCommit method on any virtual table. If any of the
+ /// xSync methods fail, the entire transaction is rolled back.
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xSync(
+ IntPtr pVtab
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// This method causes a virtual table transaction to commit. This is
+ /// method is optional. The xCommit pointer of sqlite3_module may be
+ /// NULL.
+ ///
+ ///
+ /// A call to this method always follows a prior call to xBegin and
+ /// xSync.
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xCommit(
+ IntPtr pVtab
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// This method causes a virtual table transaction to rollback. This is
+ /// method is optional. The xRollback pointer of sqlite3_module may be
+ /// NULL.
+ ///
+ ///
+ /// A call to this method always follows a prior call to xBegin.
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xRollback(
+ IntPtr pVtab
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// This method provides notification that the virtual table
+ /// implementation that the virtual table will be given a new name. If
+ /// this method returns SQLITE_OK then SQLite renames the table. If
+ /// this method returns an error code then the renaming is prevented.
+ ///
+ ///
+ /// The xRename method is required for every virtual table
+ /// implementation.
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// The number of arguments to the function being sought.
+ ///
+ ///
+ /// The name of the function being sought.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to contain the
+ /// delegate responsible for implementing the specified function.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to contain the
+ /// native user-data pointer associated with
+ /// .
+ ///
+ ///
+ /// Non-zero if the specified function was found; zero otherwise.
+ ///
+ int xFindFunction(
+ IntPtr pVtab,
+ int nArg,
+ IntPtr zName,
+ ref SQLiteCallback callback,
+ ref IntPtr pClientData
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// This method provides notification that the virtual table
+ /// implementation that the virtual table will be given a new name. If
+ /// this method returns SQLITE_OK then SQLite renames the table. If
+ /// this method returns an error code then the renaming is prevented.
+ ///
+ ///
+ /// The xRename method is required for every virtual table
+ /// implementation.
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// The native pointer to the UTF-8 encoded string containing the new
+ /// name for the virtual table.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xRename(
+ IntPtr pVtab,
+ IntPtr zNew
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// These methods provide the virtual table implementation an
+ /// opportunity to implement nested transactions. They are always
+ /// optional and will only be called in SQLite version 3.7.7 and later.
+ ///
+ ///
+ /// When xSavepoint(X,N) is invoked, that is a signal to the virtual
+ /// table X that it should save its current state as savepoint N. A
+ /// subsequent call to xRollbackTo(X,R) means that the state of the
+ /// virtual table should return to what it was when xSavepoint(X,R) was
+ /// last called. The call to xRollbackTo(X,R) will invalidate all
+ /// savepoints with N>R; none of the invalided savepoints will be
+ /// rolled back or released without first being reinitialized by a call
+ /// to xSavepoint(). A call to xRelease(X,M) invalidates all savepoints
+ /// where N>=M.
+ ///
+ ///
+ /// None of the xSavepoint(), xRelease(), or xRollbackTo() methods will
+ /// ever be called except in between calls to xBegin() and either
+ /// xCommit() or xRollback().
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// This is an integer identifier under which the the current state of
+ /// the virtual table should be saved.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xSavepoint(
+ IntPtr pVtab,
+ int iSavepoint
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// These methods provide the virtual table implementation an
+ /// opportunity to implement nested transactions. They are always
+ /// optional and will only be called in SQLite version 3.7.7 and later.
+ ///
+ ///
+ /// When xSavepoint(X,N) is invoked, that is a signal to the virtual
+ /// table X that it should save its current state as savepoint N. A
+ /// subsequent call to xRollbackTo(X,R) means that the state of the
+ /// virtual table should return to what it was when xSavepoint(X,R) was
+ /// last called. The call to xRollbackTo(X,R) will invalidate all
+ /// savepoints with N>R; none of the invalided savepoints will be
+ /// rolled back or released without first being reinitialized by a call
+ /// to xSavepoint(). A call to xRelease(X,M) invalidates all savepoints
+ /// where N>=M.
+ ///
+ ///
+ /// None of the xSavepoint(), xRelease(), or xRollbackTo() methods will
+ /// ever be called except in between calls to xBegin() and either
+ /// xCommit() or xRollback().
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// This is an integer used to indicate that any saved states with an
+ /// identifier greater than or equal to this should be deleted by the
+ /// virtual table.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xRelease(
+ IntPtr pVtab,
+ int iSavepoint
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ ///
+ /// These methods provide the virtual table implementation an
+ /// opportunity to implement nested transactions. They are always
+ /// optional and will only be called in SQLite version 3.7.7 and later.
+ ///
+ ///
+ /// When xSavepoint(X,N) is invoked, that is a signal to the virtual
+ /// table X that it should save its current state as savepoint N. A
+ /// subsequent call to xRollbackTo(X,R) means that the state of the
+ /// virtual table should return to what it was when xSavepoint(X,R) was
+ /// last called. The call to xRollbackTo(X,R) will invalidate all
+ /// savepoints with N>R; none of the invalided savepoints will be
+ /// rolled back or released without first being reinitialized by a call
+ /// to xSavepoint(). A call to xRelease(X,M) invalidates all savepoints
+ /// where N>=M.
+ ///
+ ///
+ /// None of the xSavepoint(), xRelease(), or xRollbackTo() methods will
+ /// ever be called except in between calls to xBegin() and either
+ /// xCommit() or xRollback().
+ ///
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// This is an integer identifier used to specify a specific saved
+ /// state for the virtual table for it to restore itself back to, which
+ /// should also have the effect of deleting all saved states with an
+ /// integer identifier greater than this one.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode xRollbackTo(
+ IntPtr pVtab,
+ int iSavepoint
+ );
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region ISQLiteManagedModule Interface
+ ///
+ /// This interface represents a virtual table implementation written in
+ /// managed code.
+ ///
+ public interface ISQLiteManagedModule
+ {
+ ///
+ /// Returns non-zero if the schema for the virtual table has been
+ /// declared.
+ ///
+ bool Declared { get; }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Returns the name of the module as it was registered with the SQLite
+ /// core library.
+ ///
+ string Name { get; }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated with
+ /// the virtual table.
+ ///
+ ///
+ /// The native user-data pointer associated with this module, as it was
+ /// provided to the SQLite core library when the native module instance
+ /// was created.
+ ///
+ ///
+ /// The module name, database name, virtual table name, and all other
+ /// arguments passed to the CREATE VIRTUAL TABLE statement.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to contain the
+ /// object instance associated with
+ /// the virtual table.
+ ///
+ ///
+ /// Upon failure, this parameter must be modified to contain an error
+ /// message.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode Create(
+ SQLiteConnection connection, /* in */
+ IntPtr pClientData, /* in */
+ string[] arguments, /* in */
+ ref SQLiteVirtualTable table, /* out */
+ ref string error /* out */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated with
+ /// the virtual table.
+ ///
+ ///
+ /// The native user-data pointer associated with this module, as it was
+ /// provided to the SQLite core library when the native module instance
+ /// was created.
+ ///
+ ///
+ /// The module name, database name, virtual table name, and all other
+ /// arguments passed to the CREATE VIRTUAL TABLE statement.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to contain the
+ /// object instance associated with
+ /// the virtual table.
+ ///
+ ///
+ /// Upon failure, this parameter must be modified to contain an error
+ /// message.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode Connect(
+ SQLiteConnection connection, /* in */
+ IntPtr pClientData, /* in */
+ string[] arguments, /* in */
+ ref SQLiteVirtualTable table, /* out */
+ ref string error /* out */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// The object instance containing all the
+ /// data for the inputs and outputs relating to index selection.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode BestIndex(
+ SQLiteVirtualTable table, /* in */
+ SQLiteIndex index /* in, out */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode Disconnect(
+ SQLiteVirtualTable table /* in */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode Destroy(
+ SQLiteVirtualTable table /* in */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to contain the
+ /// object instance associated
+ /// with the newly opened virtual table cursor.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode Open(
+ SQLiteVirtualTable table, /* in */
+ ref SQLiteVirtualTableCursor cursor /* out */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance
+ /// associated with the previously opened virtual table cursor to be
+ /// used.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode Close(
+ SQLiteVirtualTableCursor cursor /* in */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance
+ /// associated with the previously opened virtual table cursor to be
+ /// used.
+ ///
+ ///
+ /// Number used to help identify the selected index.
+ ///
+ ///
+ /// String used to help identify the selected index.
+ ///
+ ///
+ /// The values corresponding to each column in the selected index.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode Filter(
+ SQLiteVirtualTableCursor cursor, /* in */
+ int indexNumber, /* in */
+ string indexString, /* in */
+ SQLiteValue[] values /* in */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance
+ /// associated with the previously opened virtual table cursor to be
+ /// used.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode Next(
+ SQLiteVirtualTableCursor cursor /* in */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance
+ /// associated with the previously opened virtual table cursor to be
+ /// used.
+ ///
+ ///
+ /// Non-zero if no more rows are available; zero otherwise.
+ ///
+ bool Eof(
+ SQLiteVirtualTableCursor cursor /* in */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance
+ /// associated with the previously opened virtual table cursor to be
+ /// used.
+ ///
+ ///
+ /// The object instance to be used for
+ /// returning the specified column value to the SQLite core library.
+ ///
+ ///
+ /// The zero-based index corresponding to the column containing the
+ /// value to be returned.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode Column(
+ SQLiteVirtualTableCursor cursor, /* in */
+ SQLiteContext context, /* in */
+ int index /* in */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance
+ /// associated with the previously opened virtual table cursor to be
+ /// used.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to contain the unique
+ /// integer row identifier for the current row for the specified cursor.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode RowId(
+ SQLiteVirtualTableCursor cursor, /* in */
+ ref long rowId /* out */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// The array of object instances containing
+ /// the new or modified column values, if any.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to contain the unique
+ /// integer row identifier for the row that was inserted, if any.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode Update(
+ SQLiteVirtualTable table, /* in */
+ SQLiteValue[] values, /* in */
+ ref long rowId /* out */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode Begin(
+ SQLiteVirtualTable table /* in */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode Sync(
+ SQLiteVirtualTable table /* in */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode Commit(
+ SQLiteVirtualTable table /* in */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode Rollback(
+ SQLiteVirtualTable table /* in */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// The number of arguments to the function being sought.
+ ///
+ ///
+ /// The name of the function being sought.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to contain the
+ /// object instance responsible for
+ /// implementing the specified function.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to contain the
+ /// native user-data pointer associated with
+ /// .
+ ///
+ ///
+ /// Non-zero if the specified function was found; zero otherwise.
+ ///
+ bool FindFunction(
+ SQLiteVirtualTable table, /* in */
+ int argumentCount, /* in */
+ string name, /* in */
+ ref SQLiteFunction function, /* out */
+ ref IntPtr pClientData /* out */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// The new name for the virtual table.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode Rename(
+ SQLiteVirtualTable table, /* in */
+ string newName /* in */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// This is an integer identifier under which the the current state of
+ /// the virtual table should be saved.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode Savepoint(
+ SQLiteVirtualTable table, /* in */
+ int savepoint /* in */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// This is an integer used to indicate that any saved states with an
+ /// identifier greater than or equal to this should be deleted by the
+ /// virtual table.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode Release(
+ SQLiteVirtualTable table, /* in */
+ int savepoint /* in */
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// This is an integer identifier used to specify a specific saved
+ /// state for the virtual table for it to restore itself back to, which
+ /// should also have the effect of deleting all saved states with an
+ /// integer identifier greater than this one.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ SQLiteErrorCode RollbackTo(
+ SQLiteVirtualTable table, /* in */
+ int savepoint /* in */
+ );
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region SQLiteMemory Static Class
+ ///
+ /// This class contains static methods that are used to allocate,
+ /// manipulate, and free native memory provided by the SQLite core library.
+ ///
+ internal static class SQLiteMemory
+ {
+ #region Private Data
+#if TRACK_MEMORY_BYTES
+ ///
+ /// This object instance is used to synchronize access to the other
+ /// static fields of this class.
+ ///
+ private static object syncRoot = new object();
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// The total number of outstanding memory bytes allocated by this
+ /// class using the SQLite core library.
+ ///
+ private static int bytesAllocated;
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// The maximum number of outstanding memory bytes ever allocated by
+ /// this class using the SQLite core library.
+ ///
+ private static int maximumBytesAllocated;
+#endif
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Memory Allocation Helper Methods
+ ///
+ /// Allocates at least the specified number of bytes of native memory
+ /// via the SQLite core library sqlite3_malloc() function and returns
+ /// the resulting native pointer.
+ ///
+ ///
+ /// The number of bytes to allocate.
+ ///
+ ///
+ /// The native pointer that points to a block of memory of at least the
+ /// specified size -OR- if the memory could
+ /// not be allocated.
+ ///
+ public static IntPtr Allocate(int size)
+ {
+ IntPtr pMemory = UnsafeNativeMethods.sqlite3_malloc(size);
+
+#if TRACK_MEMORY_BYTES
+ if (pMemory != IntPtr.Zero)
+ {
+ int blockSize = Size(pMemory);
+
+ if (blockSize > 0)
+ {
+ lock (syncRoot)
+ {
+ bytesAllocated += blockSize;
+
+ if (bytesAllocated > maximumBytesAllocated)
+ maximumBytesAllocated = bytesAllocated;
+ }
+ }
+ }
+#endif
+
+ return pMemory;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Gets and returns the actual size of the specified memory block that
+ /// was previously obtained from the method.
+ ///
+ ///
+ /// The native pointer to the memory block previously obtained from the
+ /// method.
+ ///
+ ///
+ /// The actual size, in bytes, of the memory block specified via the
+ /// native pointer.
+ ///
+ public static int Size(IntPtr pMemory)
+ {
+#if !SQLITE_STANDARD
+ return UnsafeNativeMethods.sqlite3_malloc_size_interop(pMemory);
+#else
+ return 0;
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Frees a memory block previously obtained from the
+ /// method.
+ ///
+ ///
+ /// The native pointer to the memory block previously obtained from the
+ /// method.
+ ///
+ public static void Free(IntPtr pMemory)
+ {
+#if TRACK_MEMORY_BYTES
+ if (pMemory != IntPtr.Zero)
+ {
+ int blockSize = Size(pMemory);
+
+ if (blockSize > 0)
+ {
+ lock (syncRoot)
+ {
+ bytesAllocated -= blockSize;
+ }
+ }
+ }
+#endif
+
+ UnsafeNativeMethods.sqlite3_free(pMemory);
+ }
+ #endregion
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region SQLiteString Static Class
+ ///
+ /// This class contains static methods that are used to deal with native
+ /// UTF-8 string pointers to be used with the SQLite core library.
+ ///
+ internal static class SQLiteString
+ {
+ #region Private Constants
+ ///
+ /// This is the maximum possible length for the native UTF-8 encoded
+ /// strings used with the SQLite core library.
+ ///
+ private static int ThirtyBits = 0x3fffffff;
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This is the object instance used to handle
+ /// conversions from/to UTF-8.
+ ///
+ private static readonly Encoding Utf8Encoding = Encoding.UTF8;
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region UTF-8 Encoding Helper Methods
+ ///
+ /// Converts the specified managed string into the UTF-8 encoding and
+ /// returns the array of bytes containing its representation in that
+ /// encoding.
+ ///
+ ///
+ /// The managed string to convert.
+ ///
+ ///
+ /// The array of bytes containing the representation of the managed
+ /// string in the UTF-8 encoding or null upon failure.
+ ///
+ public static byte[] GetUtf8BytesFromString(
+ string value
+ )
+ {
+ if (value == null)
+ return null;
+
+ return Utf8Encoding.GetBytes(value);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Converts the specified array of bytes representing a string in the
+ /// UTF-8 encoding and returns a managed string.
+ ///
+ ///
+ /// The array of bytes to convert.
+ ///
+ ///
+ /// The managed string or null upon failure.
+ ///
+ public static string GetStringFromUtf8Bytes(
+ byte[] bytes
+ )
+ {
+ if (bytes == null)
+ return null;
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ return Utf8Encoding.GetString(bytes);
+#else
+ return Utf8Encoding.GetString(bytes, 0, bytes.Length);
+#endif
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region UTF-8 String Helper Methods
+ ///
+ /// Probes a native pointer to a string in the UTF-8 encoding for its
+ /// terminating NUL character, within the specified length limit.
+ ///
+ ///
+ /// The native NUL-terminated string pointer.
+ ///
+ ///
+ /// The maximum length of the native string, in bytes.
+ ///
+ ///
+ /// The length of the native string, in bytes -OR- zero if the length
+ /// could not be determined.
+ ///
+ public static int ProbeForUtf8ByteLength(
+ IntPtr pValue,
+ int limit
+ )
+ {
+ int length = 0;
+
+ if ((pValue != IntPtr.Zero) && (limit > 0))
+ {
+ do
+ {
+ if (Marshal.ReadByte(pValue, length) == 0)
+ break;
+
+ if (length >= limit)
+ break;
+
+ length++;
+ } while (true);
+ }
+
+ return length;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Converts the specified native NUL-terminated UTF-8 string pointer
+ /// into a managed string.
+ ///
+ ///
+ /// The native NUL-terminated UTF-8 string pointer.
+ ///
+ ///
+ /// The managed string or null upon failure.
+ ///
+ public static string StringFromUtf8IntPtr(
+ IntPtr pValue
+ )
+ {
+ return StringFromUtf8IntPtr(pValue,
+ ProbeForUtf8ByteLength(pValue, ThirtyBits));
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Converts the specified native UTF-8 string pointer of the specified
+ /// length into a managed string.
+ ///
+ ///
+ /// The native UTF-8 string pointer.
+ ///
+ ///
+ /// The length of the native string, in bytes.
+ ///
+ ///
+ /// The managed string or null upon failure.
+ ///
+ public static string StringFromUtf8IntPtr(
+ IntPtr pValue,
+ int length
+ )
+ {
+ if (pValue == IntPtr.Zero)
+ return null;
+
+ if (length > 0)
+ {
+ byte[] bytes = new byte[length];
+
+ Marshal.Copy(pValue, bytes, 0, length);
+
+ return GetStringFromUtf8Bytes(bytes);
+ }
+
+ return String.Empty;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Converts the specified managed string into a native NUL-terminated
+ /// UTF-8 string pointer using memory obtained from the SQLite core
+ /// library.
+ ///
+ ///
+ /// The managed string to convert.
+ ///
+ ///
+ /// The native NUL-terminated UTF-8 string pointer or
+ /// upon failure.
+ ///
+ public static IntPtr Utf8IntPtrFromString(
+ string value
+ )
+ {
+ if (value == null)
+ return IntPtr.Zero;
+
+ IntPtr result = IntPtr.Zero;
+ byte[] bytes = GetUtf8BytesFromString(value);
+
+ if (bytes == null)
+ return IntPtr.Zero;
+
+ int length = bytes.Length;
+
+ result = SQLiteMemory.Allocate(length + 1);
+
+ if (result == IntPtr.Zero)
+ return IntPtr.Zero;
+
+ Marshal.Copy(bytes, 0, result, length);
+ Marshal.WriteByte(result, length, 0);
+
+ return result;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region UTF-8 String Array Helper Methods
+ ///
+ /// Converts a logical array of native NUL-terminated UTF-8 string
+ /// pointers into an array of managed strings.
+ ///
+ ///
+ /// The number of elements in the logical array of native
+ /// NUL-terminated UTF-8 string pointers.
+ ///
+ ///
+ /// The native pointer to the logical array of native NUL-terminated
+ /// UTF-8 string pointers to convert.
+ ///
+ ///
+ /// The array of managed strings or null upon failure.
+ ///
+ public static string[] StringArrayFromUtf8SizeAndIntPtr(
+ int argc,
+ IntPtr argv
+ )
+ {
+ if (argc < 0)
+ return null;
+
+ if (argv == IntPtr.Zero)
+ return null;
+
+ string[] result = new string[argc];
+
+ for (int index = 0, offset = 0;
+ index < result.Length;
+ index++, offset += IntPtr.Size)
+ {
+ IntPtr pArg = SQLiteMarshal.ReadIntPtr(argv, offset);
+
+ result[index] = (pArg != IntPtr.Zero) ?
+ StringFromUtf8IntPtr(pArg) : null;
+ }
+
+ return result;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Converts an array of managed strings into an array of native
+ /// NUL-terminated UTF-8 string pointers.
+ ///
+ ///
+ /// The array of managed strings to convert.
+ ///
+ ///
+ /// The array of native NUL-terminated UTF-8 string pointers or null
+ /// upon failure.
+ ///
+ public static IntPtr[] Utf8IntPtrArrayFromStringArray(
+ string[] values
+ )
+ {
+ if (values == null)
+ return null;
+
+ IntPtr[] result = new IntPtr[values.Length];
+
+ for (int index = 0; index < result.Length; index++)
+ result[index] = Utf8IntPtrFromString(values[index]);
+
+ return result;
+ }
+ #endregion
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region SQLiteBytes Static Class
+ ///
+ /// This class contains static methods that are used to deal with native
+ /// pointers to memory blocks that logically contain arrays of bytes to be
+ /// used with the SQLite core library.
+ ///
+ internal static class SQLiteBytes
+ {
+ #region Byte Array Helper Methods
+ ///
+ /// Converts a native pointer to a logical array of bytes of the
+ /// specified length into a managed byte array.
+ ///
+ ///
+ /// The native pointer to the logical array of bytes to convert.
+ ///
+ ///
+ /// The length, in bytes, of the logical array of bytes to convert.
+ ///
+ ///
+ /// The managed byte array or null upon failure.
+ ///
+ public static byte[] FromIntPtr(
+ IntPtr pValue,
+ int length
+ )
+ {
+ if (pValue == IntPtr.Zero)
+ return null;
+
+ if (length == 0)
+ return new byte[0];
+
+ byte[] result = new byte[length];
+
+ Marshal.Copy(pValue, result, 0, length);
+
+ return result;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Converts a managed byte array into a native pointer to a logical
+ /// array of bytes.
+ ///
+ ///
+ /// The managed byte array to convert.
+ ///
+ ///
+ /// The native pointer to a logical byte array or null upon failure.
+ ///
+ public static IntPtr ToIntPtr(
+ byte[] value
+ )
+ {
+ if (value == null)
+ return IntPtr.Zero;
+
+ int length = value.Length;
+
+ if (length == 0)
+ return IntPtr.Zero;
+
+ IntPtr result = SQLiteMemory.Allocate(length);
+
+ if (result == IntPtr.Zero)
+ return IntPtr.Zero;
+
+ Marshal.Copy(value, 0, result, length);
+
+ return result;
+ }
+ #endregion
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region SQLiteMarshal Static Class
+ internal static class SQLiteMarshal
+ {
+ #region IntPtr Helper Methods
+ ///
+ /// Returns a new object instance based on the
+ /// specified object instance and an integer
+ /// offset.
+ ///
+ ///
+ /// The object instance representing the base
+ /// memory location.
+ ///
+ ///
+ /// The integer offset from the base memory location that the new
+ /// object instance should point to.
+ ///
+ ///
+ /// The new object instance.
+ ///
+ public static IntPtr IntPtrForOffset(
+ IntPtr pointer,
+ int offset
+ )
+ {
+ return new IntPtr(pointer.ToInt64() + offset);
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Marshal Read Helper Methods
+ ///
+ /// Reads a value from the specified memory
+ /// location.
+ ///
+ ///
+ /// The object instance representing the base
+ /// memory location.
+ ///
+ ///
+ /// The integer offset from the base memory location where the
+ /// value to be read is located.
+ ///
+ ///
+ /// The value at the specified memory location.
+ ///
+ public static int ReadInt32(
+ IntPtr pointer,
+ int offset
+ )
+ {
+#if !PLATFORM_COMPACTFRAMEWORK
+ return Marshal.ReadInt32(pointer, offset);
+#else
+ return Marshal.ReadInt32(IntPtrForOffset(pointer, offset));
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Reads a value from the specified memory
+ /// location.
+ ///
+ ///
+ /// The object instance representing the base
+ /// memory location.
+ ///
+ ///
+ /// The integer offset from the base memory location where the
+ /// to be read is located.
+ ///
+ ///
+ /// The value at the specified memory location.
+ ///
+ public static double ReadDouble(
+ IntPtr pointer,
+ int offset
+ )
+ {
+#if !PLATFORM_COMPACTFRAMEWORK
+ return BitConverter.Int64BitsToDouble(Marshal.ReadInt64(
+ pointer, offset));
+#else
+ return BitConverter.ToDouble(BitConverter.GetBytes(
+ Marshal.ReadInt64(IntPtrForOffset(pointer, offset))), 0);
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Reads an value from the specified memory
+ /// location.
+ ///
+ ///
+ /// The object instance representing the base
+ /// memory location.
+ ///
+ ///
+ /// The integer offset from the base memory location where the
+ /// value to be read is located.
+ ///
+ ///
+ /// The value at the specified memory location.
+ ///
+ public static IntPtr ReadIntPtr(
+ IntPtr pointer,
+ int offset
+ )
+ {
+#if !PLATFORM_COMPACTFRAMEWORK
+ return Marshal.ReadIntPtr(pointer, offset);
+#else
+ return Marshal.ReadIntPtr(IntPtrForOffset(pointer, offset));
+#endif
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Marshal Write Helper Methods
+ ///
+ /// Writes an value to the specified memory
+ /// location.
+ ///
+ ///
+ /// The object instance representing the base
+ /// memory location.
+ ///
+ ///
+ /// The integer offset from the base memory location where the
+ /// value to be written is located.
+ ///
+ ///
+ /// The value to write.
+ ///
+ public static void WriteInt32(
+ IntPtr pointer,
+ int offset,
+ int value
+ )
+ {
+#if !PLATFORM_COMPACTFRAMEWORK
+ Marshal.WriteInt32(pointer, offset, value);
+#else
+ Marshal.WriteInt32(IntPtrForOffset(pointer, offset), value);
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Writes a value to the specified memory
+ /// location.
+ ///
+ ///
+ /// The object instance representing the base
+ /// memory location.
+ ///
+ ///
+ /// The integer offset from the base memory location where the
+ /// value to be written is located.
+ ///
+ ///
+ /// The value to write.
+ ///
+ public static void WriteDouble(
+ IntPtr pointer,
+ int offset,
+ double value
+ )
+ {
+#if !PLATFORM_COMPACTFRAMEWORK
+ Marshal.WriteInt64(pointer, offset,
+ BitConverter.DoubleToInt64Bits(value));
+#else
+ Marshal.WriteInt64(IntPtrForOffset(pointer, offset),
+ BitConverter.ToInt64(BitConverter.GetBytes(value), 0));
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Writes a value to the specified memory
+ /// location.
+ ///
+ ///
+ /// The object instance representing the base
+ /// memory location.
+ ///
+ ///
+ /// The integer offset from the base memory location where the
+ /// value to be written is located.
+ ///
+ ///
+ /// The value to write.
+ ///
+ public static void WriteIntPtr(
+ IntPtr pointer,
+ int offset,
+ IntPtr value
+ )
+ {
+#if !PLATFORM_COMPACTFRAMEWORK
+ Marshal.WriteIntPtr(pointer, offset, value);
+#else
+ Marshal.WriteIntPtr(IntPtrForOffset(pointer, offset), value);
+#endif
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region SQLiteValue Helper Methods
+ ///
+ /// Converts a logical array of native pointers to native sqlite3_value
+ /// structures into a managed array of
+ /// object instances.
+ ///
+ ///
+ /// The number of elements in the logical array of native sqlite3_value
+ /// structures.
+ ///
+ ///
+ /// The native pointer to the logical array of native sqlite3_value
+ /// structures to convert.
+ ///
+ ///
+ /// The managed array of object instances or
+ /// null upon failure.
+ ///
+ public static SQLiteValue[] ValueArrayFromSizeAndIntPtr(
+ int argc,
+ IntPtr argv
+ )
+ {
+ if (argc < 0)
+ return null;
+
+ if (argv == IntPtr.Zero)
+ return null;
+
+ SQLiteValue[] result = new SQLiteValue[argc];
+
+ for (int index = 0, offset = 0;
+ index < result.Length;
+ index++, offset += IntPtr.Size)
+ {
+ IntPtr pArg = ReadIntPtr(argv, offset);
+
+ result[index] = (pArg != IntPtr.Zero) ?
+ new SQLiteValue(pArg) : null;
+ }
+
+ return result;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region SQLiteIndex Helper Methods
+ ///
+ /// Converts a native pointer to a native sqlite3_index_info structure
+ /// into a new object instance.
+ ///
+ ///
+ /// The native pointer to the native sqlite3_index_info structure to
+ /// convert.
+ ///
+ ///
+ /// Upon success, this parameter will be modified to contain the newly
+ /// created object instance.
+ ///
+ public static void IndexFromIntPtr(
+ IntPtr pIndex,
+ ref SQLiteIndex index
+ )
+ {
+ if (pIndex == IntPtr.Zero)
+ return;
+
+ int offset = 0;
+
+ int nConstraint = ReadInt32(pIndex, offset);
+
+ offset += sizeof(int);
+
+ IntPtr pConstraint = ReadIntPtr(pIndex, offset);
+
+ offset += IntPtr.Size;
+
+ int nOrderBy = ReadInt32(pIndex, offset);
+
+ offset += sizeof(int);
+
+ IntPtr pOrderBy = ReadIntPtr(pIndex, offset);
+
+ index = new SQLiteIndex(nConstraint, nOrderBy);
+
+ int sizeOfConstraintType = Marshal.SizeOf(typeof(
+ UnsafeNativeMethods.sqlite3_index_constraint));
+
+ for (int iConstraint = 0; iConstraint < nConstraint; iConstraint++)
+ {
+ UnsafeNativeMethods.sqlite3_index_constraint constraint =
+ new UnsafeNativeMethods.sqlite3_index_constraint();
+
+ Marshal.PtrToStructure(IntPtrForOffset(pConstraint,
+ iConstraint * sizeOfConstraintType), constraint);
+
+ index.Inputs.Constraints[iConstraint] =
+ new SQLiteIndexConstraint(constraint);
+ }
+
+ int sizeOfOrderByType = Marshal.SizeOf(typeof(
+ UnsafeNativeMethods.sqlite3_index_orderby));
+
+ for (int iOrderBy = 0; iOrderBy < nOrderBy; iOrderBy++)
+ {
+ UnsafeNativeMethods.sqlite3_index_orderby orderBy =
+ new UnsafeNativeMethods.sqlite3_index_orderby();
+
+ Marshal.PtrToStructure(IntPtrForOffset(pOrderBy,
+ iOrderBy * sizeOfOrderByType), orderBy);
+
+ index.Inputs.OrderBys[iOrderBy] =
+ new SQLiteIndexOrderBy(orderBy);
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Populates the outputs of a pre-allocated native sqlite3_index_info
+ /// structure using an existing object
+ /// instance.
+ ///
+ ///
+ /// The existing object instance containing
+ /// the output data to use.
+ ///
+ ///
+ /// The native pointer to the pre-allocated native sqlite3_index_info
+ /// structure.
+ ///
+ public static void IndexToIntPtr(
+ SQLiteIndex index,
+ IntPtr pIndex
+ )
+ {
+ if ((index == null) || (index.Inputs == null) ||
+ (index.Inputs.Constraints == null) ||
+ (index.Outputs == null) ||
+ (index.Outputs.ConstraintUsages == null))
+ {
+ return;
+ }
+
+ if (pIndex == IntPtr.Zero)
+ return;
+
+ int offset = 0;
+
+ int nConstraint = ReadInt32(pIndex, offset);
+
+ if (nConstraint != index.Inputs.Constraints.Length)
+ return;
+
+ if (nConstraint != index.Outputs.ConstraintUsages.Length)
+ return;
+
+ offset += sizeof(int) + IntPtr.Size + sizeof(int) + IntPtr.Size;
+
+ IntPtr pConstraintUsage = ReadIntPtr(pIndex, offset);
+
+ int sizeOfConstraintUsageType = Marshal.SizeOf(typeof(
+ UnsafeNativeMethods.sqlite3_index_constraint_usage));
+
+ for (int iConstraint = 0; iConstraint < nConstraint; iConstraint++)
+ {
+ UnsafeNativeMethods.sqlite3_index_constraint_usage constraintUsage =
+ new UnsafeNativeMethods.sqlite3_index_constraint_usage(
+ index.Outputs.ConstraintUsages[iConstraint]);
+
+ Marshal.StructureToPtr(
+ constraintUsage, IntPtrForOffset(pConstraintUsage,
+ iConstraint * sizeOfConstraintUsageType), false);
+
+ index.Outputs.ConstraintUsages[iConstraint] =
+ new SQLiteIndexConstraintUsage(constraintUsage);
+ }
+
+ offset += IntPtr.Size;
+
+ WriteInt32(pIndex, offset, index.Outputs.IndexNumber);
+
+ offset += sizeof(int);
+
+ WriteIntPtr(pIndex, offset, SQLiteString.Utf8IntPtrFromString(
+ index.Outputs.IndexString));
+
+ offset += IntPtr.Size;
+
+ WriteInt32(pIndex, offset, 1); /* NOTE: We just allocated it. */
+
+ offset += sizeof(int);
+
+ WriteInt32(pIndex, offset, index.Outputs.OrderByConsumed);
+
+ offset += sizeof(int);
+
+ WriteDouble(pIndex, offset, index.Outputs.EstimatedCost);
+ }
+ #endregion
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region SQLiteModule Base Class
+ ///
+ /// This class represents a managed virtual table module implementation.
+ /// It is not sealed and must be used as the base class for any
+ /// user-defined virtual table module classes implemented in managed code.
+ ///
+ public abstract class SQLiteModule :
+ ISQLiteManagedModule, /*ISQLiteNativeModule,*/
+ IDisposable /* NOT SEALED */
+ {
+ #region SQLiteNativeModule Private Class
+ private sealed class SQLiteNativeModule :
+ ISQLiteNativeModule, IDisposable
+ {
+ #region Private Constants
+ ///
+ /// This is the value that is always used for the "logErrors"
+ /// parameter to the various static error handling methods provided
+ /// by the class.
+ ///
+ private const bool DefaultLogErrors = true;
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// This is the error message text used when the contained
+ /// object instance is not available
+ /// for any reason.
+ ///
+ private const string ModuleNotAvailableErrorMessage =
+ "native module implementation not available";
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////
+
+ #region Private Data
+ ///
+ /// The object instance used to provide
+ /// an implementation of the
+ /// interface.
+ ///
+ private SQLiteModule module;
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////
+
+ #region Public Constructors
+ ///
+ /// Constructs an instance of this class.
+ ///
+ ///
+ /// The object instance used to provide
+ /// an implementation of the
+ /// interface.
+ ///
+ public SQLiteNativeModule(
+ SQLiteModule module
+ )
+ {
+ this.module = module;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////
+
+ #region Private Static Methods
+ ///
+ /// Sets the table error message to one that indicates the native
+ /// module implementation is not available.
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// The value of .
+ ///
+ private static SQLiteErrorCode ModuleNotAvailableTableError(
+ IntPtr pVtab
+ )
+ {
+ SetTableError(null, pVtab, DefaultLogErrors,
+ ModuleNotAvailableErrorMessage);
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// Sets the table error message to one that indicates the native
+ /// module implementation is not available.
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab_cursor derived
+ /// structure.
+ ///
+ ///
+ /// The value of .
+ ///
+ private static SQLiteErrorCode ModuleNotAvailableCursorError(
+ IntPtr pCursor
+ )
+ {
+ SetCursorError(null, pCursor, DefaultLogErrors,
+ ModuleNotAvailableErrorMessage);
+
+ return SQLiteErrorCode.Error;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////
+
+ #region ISQLiteNativeModule Members
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xCreate(
+ IntPtr pDb,
+ IntPtr pAux,
+ int argc,
+ IntPtr argv,
+ ref IntPtr pVtab,
+ ref IntPtr pError
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ {
+ pError = SQLiteString.Utf8IntPtrFromString(
+ ModuleNotAvailableErrorMessage);
+
+ return SQLiteErrorCode.Error;
+ }
+
+ return module.xCreate(
+ pDb, pAux, argc, argv, ref pVtab, ref pError);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xConnect(
+ IntPtr pDb,
+ IntPtr pAux,
+ int argc,
+ IntPtr argv,
+ ref IntPtr pVtab,
+ ref IntPtr pError
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ {
+ pError = SQLiteString.Utf8IntPtrFromString(
+ ModuleNotAvailableErrorMessage);
+
+ return SQLiteErrorCode.Error;
+ }
+
+ return module.xConnect(
+ pDb, pAux, argc, argv, ref pVtab, ref pError);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xBestIndex(
+ IntPtr pVtab,
+ IntPtr pIndex
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ return ModuleNotAvailableTableError(pVtab);
+
+ return module.xBestIndex(pVtab, pIndex);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xDisconnect(
+ IntPtr pVtab
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ return ModuleNotAvailableTableError(pVtab);
+
+ return module.xDisconnect(pVtab);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xDestroy(
+ IntPtr pVtab
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ return ModuleNotAvailableTableError(pVtab);
+
+ return module.xDestroy(pVtab);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xOpen(
+ IntPtr pVtab,
+ ref IntPtr pCursor
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ return ModuleNotAvailableTableError(pVtab);
+
+ return module.xOpen(pVtab, ref pCursor);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xClose(
+ IntPtr pCursor
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ return ModuleNotAvailableCursorError(pCursor);
+
+ return module.xClose(pCursor);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xFilter(
+ IntPtr pCursor,
+ int idxNum,
+ IntPtr idxStr,
+ int argc,
+ IntPtr argv
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ return ModuleNotAvailableCursorError(pCursor);
+
+ return module.xFilter(pCursor, idxNum, idxStr, argc, argv);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xNext(
+ IntPtr pCursor
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ return ModuleNotAvailableCursorError(pCursor);
+
+ return module.xNext(pCursor);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public int xEof(
+ IntPtr pCursor
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ {
+ ModuleNotAvailableCursorError(pCursor);
+ return 1;
+ }
+
+ return module.xEof(pCursor);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xColumn(
+ IntPtr pCursor,
+ IntPtr pContext,
+ int index
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ return ModuleNotAvailableCursorError(pCursor);
+
+ return module.xColumn(pCursor, pContext, index);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xRowId(
+ IntPtr pCursor,
+ ref long rowId
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ return ModuleNotAvailableCursorError(pCursor);
+
+ return module.xRowId(pCursor, ref rowId);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xUpdate(
+ IntPtr pVtab,
+ int argc,
+ IntPtr argv,
+ ref long rowId
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ return ModuleNotAvailableTableError(pVtab);
+
+ return module.xUpdate(pVtab, argc, argv, ref rowId);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xBegin(
+ IntPtr pVtab
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ return ModuleNotAvailableTableError(pVtab);
+
+ return module.xBegin(pVtab);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xSync(
+ IntPtr pVtab
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ return ModuleNotAvailableTableError(pVtab);
+
+ return module.xSync(pVtab);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xCommit(
+ IntPtr pVtab
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ return ModuleNotAvailableTableError(pVtab);
+
+ return module.xCommit(pVtab);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xRollback(
+ IntPtr pVtab
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ return ModuleNotAvailableTableError(pVtab);
+
+ return module.xRollback(pVtab);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public int xFindFunction(
+ IntPtr pVtab,
+ int nArg,
+ IntPtr zName,
+ ref SQLiteCallback callback,
+ ref IntPtr pClientData
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ {
+ ModuleNotAvailableTableError(pVtab);
+ return 0;
+ }
+
+ return module.xFindFunction(
+ pVtab, nArg, zName, ref callback, ref pClientData);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xRename(
+ IntPtr pVtab,
+ IntPtr zNew
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ return ModuleNotAvailableTableError(pVtab);
+
+ return module.xRename(pVtab, zNew);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xSavepoint(
+ IntPtr pVtab,
+ int iSavepoint
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ return ModuleNotAvailableTableError(pVtab);
+
+ return module.xSavepoint(pVtab, iSavepoint);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xRelease(
+ IntPtr pVtab,
+ int iSavepoint
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ return ModuleNotAvailableTableError(pVtab);
+
+ return module.xRelease(pVtab, iSavepoint);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public SQLiteErrorCode xRollbackTo(
+ IntPtr pVtab,
+ int iSavepoint
+ )
+ {
+ // CheckDisposed();
+
+ if (module == null)
+ return ModuleNotAvailableTableError(pVtab);
+
+ return module.xRollbackTo(pVtab, iSavepoint);
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////
+
+ #region IDisposable Members
+ ///
+ /// Disposes of this object instance.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////
+
+ #region IDisposable "Pattern" Members
+ private bool disposed;
+ ///
+ /// Throws an if this object
+ /// instance has been disposed.
+ ///
+ private void CheckDisposed() /* throw */
+ {
+#if THROW_ON_DISPOSED
+ if (disposed)
+ {
+ throw new ObjectDisposedException(
+ typeof(SQLiteNativeModule).Name);
+ }
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ ///
+ /// Disposes of this object instance.
+ ///
+ ///
+ /// Non-zero if this method is being called from the
+ /// method. Zero if this method is being
+ /// called from the finalizer.
+ ///
+ private /* protected virtual */ void Dispose(bool disposing)
+ {
+ if (!disposed)
+ {
+ //if (disposing)
+ //{
+ // ////////////////////////////////////
+ // // dispose managed resources here...
+ // ////////////////////////////////////
+ //}
+
+ //////////////////////////////////////
+ // release unmanaged resources here...
+ //////////////////////////////////////
+
+ //
+ // NOTE: The module is not owned by us; therefore, do not
+ // dispose it.
+ //
+ if (module != null)
+ module = null;
+
+ disposed = true;
+ }
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////
+
+ #region Destructor
+ ///
+ /// Finalizes this object instance.
+ ///
+ ~SQLiteNativeModule()
+ {
+ Dispose(false);
+ }
+ #endregion
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Private Constants
+ ///
+ /// The default estimated cost for use with the
+ /// method.
+ ///
+ private static readonly double DefaultEstimatedCost = double.MaxValue;
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// The default version of the native sqlite3_module structure in use.
+ ///
+ private static readonly int DefaultModuleVersion = 2;
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Private Data
+ ///
+ /// This field is used to store the native sqlite3_module structure
+ /// associated with this object instance.
+ ///
+ private UnsafeNativeMethods.sqlite3_module nativeModule;
+
+ ///////////////////////////////////////////////////////////////////////
+
+#if PLATFORM_COMPACTFRAMEWORK
+ ///
+ /// This field is used to hold the block of native memory that contains
+ /// the native sqlite3_module structure associated with this object
+ /// instance when running on the .NET Compact Framework.
+ ///
+ private IntPtr pNativeModule;
+#endif
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This field is used to store the virtual table instances associated
+ /// with this module. The native pointer to the sqlite3_vtab derived
+ /// structure is used to key into this collection.
+ ///
+ private Dictionary tables;
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This field is used to store the virtual table cursor instances
+ /// associated with this module. The native pointer to the
+ /// sqlite3_vtab_cursor derived structure is used to key into this
+ /// collection.
+ ///
+ private Dictionary cursors;
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Public Constructors
+ ///
+ /// Constructs an instance of this class.
+ ///
+ ///
+ /// The name of the module. This parameter cannot be null.
+ ///
+ public SQLiteModule(string name)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+
+ this.name = name;
+ this.tables = new Dictionary();
+ this.cursors = new Dictionary();
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Internal Methods
+ ///
+ /// Creates and returns the native sqlite_module structure using the
+ /// configured (or default)
+ /// interface implementation.
+ ///
+ ///
+ /// The native sqlite_module structure using the configured (or
+ /// default) interface
+ /// implementation.
+ ///
+ internal UnsafeNativeMethods.sqlite3_module CreateNativeModule()
+ {
+ return CreateNativeModule(GetNativeModuleImpl());
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+#if PLATFORM_COMPACTFRAMEWORK
+ ///
+ /// Creates and returns a memory block obtained from the SQLite core
+ /// library used to store the native sqlite3_module structure for this
+ /// object instance when running on the .NET Compact Framework.
+ ///
+ ///
+ /// The native pointer to the native sqlite3_module structure.
+ ///
+ internal IntPtr CreateNativeModuleInterop()
+ {
+ if (pNativeModule == IntPtr.Zero)
+ {
+ //
+ // HACK: No easy way to determine the size of the native
+ // sqlite_module structure when running on the .NET
+ // Compact Framework; therefore, just base the size
+ // on what we know:
+ //
+ // There is one integer member.
+ // There are 22 function pointers.
+ //
+ pNativeModule = SQLiteMemory.Allocate(
+ sizeof(int) + (22 * IntPtr.Size));
+
+ if (pNativeModule == IntPtr.Zero)
+ throw new OutOfMemoryException("sqlite3_module");
+ }
+
+ return pNativeModule;
+ }
+#endif
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Private Methods
+ ///
+ /// Creates and returns the native sqlite_module structure using the
+ /// specified interface
+ /// implementation.
+ ///
+ ///
+ /// The interface implementation to
+ /// use.
+ ///
+ ///
+ /// The native sqlite_module structure using the specified
+ /// interface implementation.
+ ///
+ private UnsafeNativeMethods.sqlite3_module CreateNativeModule(
+ ISQLiteNativeModule module
+ )
+ {
+ nativeModule = new UnsafeNativeMethods.sqlite3_module();
+ nativeModule.iVersion = DefaultModuleVersion;
+
+ if (module != null)
+ {
+ nativeModule.xCreate = new UnsafeNativeMethods.xCreate(
+ module.xCreate);
+
+ nativeModule.xConnect = new UnsafeNativeMethods.xConnect(
+ module.xConnect);
+
+ nativeModule.xBestIndex = new UnsafeNativeMethods.xBestIndex(
+ module.xBestIndex);
+
+ nativeModule.xDisconnect = new UnsafeNativeMethods.xDisconnect(
+ module.xDisconnect);
+
+ nativeModule.xDestroy = new UnsafeNativeMethods.xDestroy(
+ module.xDestroy);
+
+ nativeModule.xOpen = new UnsafeNativeMethods.xOpen(
+ module.xOpen);
+
+ nativeModule.xClose = new UnsafeNativeMethods.xClose(
+ module.xClose);
+
+ nativeModule.xFilter = new UnsafeNativeMethods.xFilter(
+ module.xFilter);
+
+ nativeModule.xNext = new UnsafeNativeMethods.xNext(
+ module.xNext);
+
+ nativeModule.xEof = new UnsafeNativeMethods.xEof(module.xEof);
+
+ nativeModule.xColumn = new UnsafeNativeMethods.xColumn(
+ module.xColumn);
+
+ nativeModule.xRowId = new UnsafeNativeMethods.xRowId(
+ module.xRowId);
+
+ nativeModule.xUpdate = new UnsafeNativeMethods.xUpdate(
+ module.xUpdate);
+
+ nativeModule.xBegin = new UnsafeNativeMethods.xBegin(
+ module.xBegin);
+
+ nativeModule.xSync = new UnsafeNativeMethods.xSync(
+ module.xSync);
+
+ nativeModule.xCommit = new UnsafeNativeMethods.xCommit(
+ module.xCommit);
+
+ nativeModule.xRollback = new UnsafeNativeMethods.xRollback(
+ module.xRollback);
+
+ nativeModule.xFindFunction = new UnsafeNativeMethods.xFindFunction(
+ module.xFindFunction);
+
+ nativeModule.xRename = new UnsafeNativeMethods.xRename(
+ module.xRename);
+
+ nativeModule.xSavepoint = new UnsafeNativeMethods.xSavepoint(
+ module.xSavepoint);
+
+ nativeModule.xRelease = new UnsafeNativeMethods.xRelease(
+ module.xRelease);
+
+ nativeModule.xRollbackTo = new UnsafeNativeMethods.xRollbackTo(
+ module.xRollbackTo);
+ }
+ else
+ {
+ nativeModule.xCreate = new UnsafeNativeMethods.xCreate(
+ xCreate);
+
+ nativeModule.xConnect = new UnsafeNativeMethods.xConnect(
+ xConnect);
+
+ nativeModule.xBestIndex = new UnsafeNativeMethods.xBestIndex(
+ xBestIndex);
+
+ nativeModule.xDisconnect = new UnsafeNativeMethods.xDisconnect(
+ xDisconnect);
+
+ nativeModule.xDestroy = new UnsafeNativeMethods.xDestroy(
+ xDestroy);
+
+ nativeModule.xOpen = new UnsafeNativeMethods.xOpen(xOpen);
+ nativeModule.xClose = new UnsafeNativeMethods.xClose(xClose);
+
+ nativeModule.xFilter = new UnsafeNativeMethods.xFilter(
+ xFilter);
+
+ nativeModule.xNext = new UnsafeNativeMethods.xNext(xNext);
+ nativeModule.xEof = new UnsafeNativeMethods.xEof(xEof);
+
+ nativeModule.xColumn = new UnsafeNativeMethods.xColumn(
+ xColumn);
+
+ nativeModule.xRowId = new UnsafeNativeMethods.xRowId(xRowId);
+
+ nativeModule.xUpdate = new UnsafeNativeMethods.xUpdate(
+ xUpdate);
+
+ nativeModule.xBegin = new UnsafeNativeMethods.xBegin(xBegin);
+ nativeModule.xSync = new UnsafeNativeMethods.xSync(xSync);
+
+ nativeModule.xCommit = new UnsafeNativeMethods.xCommit(
+ xCommit);
+
+ nativeModule.xRollback = new UnsafeNativeMethods.xRollback(
+ xRollback);
+
+ nativeModule.xFindFunction = new UnsafeNativeMethods.xFindFunction(
+ xFindFunction);
+
+ nativeModule.xRename = new UnsafeNativeMethods.xRename(
+ xRename);
+
+ nativeModule.xSavepoint = new UnsafeNativeMethods.xSavepoint(
+ xSavepoint);
+
+ nativeModule.xRelease = new UnsafeNativeMethods.xRelease(
+ xRelease);
+
+ nativeModule.xRollbackTo = new UnsafeNativeMethods.xRollbackTo(
+ xRollbackTo);
+ }
+
+ return nativeModule;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Protected Members
+ #region Module Helper Methods
+ ///
+ /// Gets and returns the interface
+ /// implementation to be used when creating the native sqlite3_module
+ /// structure. Derived classes may override this method to supply an
+ /// alternate implementation for the
+ /// interface.
+ ///
+ ///
+ /// The interface implementation to
+ /// be used when populating the native sqlite3_module structure. If
+ /// the returned value is null, the private methods provided by the
+ /// class and relating to the
+ /// interface will be used to
+ /// create the necessary delegates.
+ ///
+ protected virtual ISQLiteNativeModule GetNativeModuleImpl()
+ {
+ return null; /* NOTE: Use the built-in default delegates. */
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Creates and returns the
+ /// interface implementation corresponding to the current
+ /// object instance.
+ ///
+ ///
+ /// The interface implementation
+ /// corresponding to the current object
+ /// instance.
+ ///
+ protected virtual ISQLiteNativeModule CreateNativeModuleImpl()
+ {
+ return new SQLiteNativeModule(this);
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Native Table Helper Methods
+ ///
+ /// Allocates a native sqlite3_vtab derived structure and returns a
+ /// native pointer to it.
+ ///
+ ///
+ /// A native pointer to a native sqlite3_vtab derived structure.
+ ///
+ protected virtual IntPtr AllocateTable()
+ {
+ int size = Marshal.SizeOf(typeof(
+ UnsafeNativeMethods.sqlite3_vtab));
+
+ return SQLiteMemory.Allocate(size);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Zeros out the fields of a native sqlite3_vtab derived structure.
+ ///
+ ///
+ /// The native pointer to the native sqlite3_vtab derived structure to
+ /// zero.
+ ///
+ protected virtual void ZeroTable(
+ IntPtr pVtab
+ )
+ {
+ if (pVtab == IntPtr.Zero)
+ return;
+
+ int offset = 0;
+
+ SQLiteMarshal.WriteIntPtr(pVtab, offset, IntPtr.Zero);
+
+ offset += IntPtr.Size;
+
+ SQLiteMarshal.WriteInt32(pVtab, offset, 0);
+
+ offset += sizeof(int);
+
+ SQLiteMarshal.WriteIntPtr(pVtab, offset, IntPtr.Zero);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Frees a native sqlite3_vtab structure using the provided native
+ /// pointer to it.
+ ///
+ ///
+ /// A native pointer to a native sqlite3_vtab derived structure.
+ ///
+ protected virtual void FreeTable(
+ IntPtr pVtab
+ )
+ {
+ SetTableError(pVtab, null);
+ SQLiteMemory.Free(pVtab);
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Native Cursor Helper Methods
+ ///
+ /// Allocates a native sqlite3_vtab_cursor derived structure and
+ /// returns a native pointer to it.
+ ///
+ ///
+ /// A native pointer to a native sqlite3_vtab_cursor derived structure.
+ ///
+ protected virtual IntPtr AllocateCursor()
+ {
+ int size = Marshal.SizeOf(typeof(
+ UnsafeNativeMethods.sqlite3_vtab_cursor));
+
+ return SQLiteMemory.Allocate(size);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Frees a native sqlite3_vtab_cursor structure using the provided
+ /// native pointer to it.
+ ///
+ ///
+ /// A native pointer to a native sqlite3_vtab_cursor derived structure.
+ ///
+ protected virtual void FreeCursor(
+ IntPtr pCursor
+ )
+ {
+ SQLiteMemory.Free(pCursor);
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Static Table Lookup Methods
+ ///
+ /// Reads and returns the native pointer to the sqlite3_vtab derived
+ /// structure based on the native pointer to the sqlite3_vtab_cursor
+ /// derived structure.
+ ///
+ ///
+ /// The object instance to be used.
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab_cursor derived structure
+ /// from which to read the native pointer to the sqlite3_vtab derived
+ /// structure.
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure -OR-
+ /// if it cannot be determined.
+ ///
+ private static IntPtr TableFromCursor(
+ SQLiteModule module,
+ IntPtr pCursor
+ )
+ {
+ if (pCursor == IntPtr.Zero)
+ return IntPtr.Zero;
+
+ return Marshal.ReadIntPtr(pCursor);
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Table Lookup Methods
+ ///
+ /// Reads and returns the native pointer to the sqlite3_vtab derived
+ /// structure based on the native pointer to the sqlite3_vtab_cursor
+ /// derived structure.
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab_cursor derived structure
+ /// from which to read the native pointer to the sqlite3_vtab derived
+ /// structure.
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure -OR-
+ /// if it cannot be determined.
+ ///
+ protected virtual IntPtr TableFromCursor(
+ IntPtr pCursor
+ )
+ {
+ return TableFromCursor(this, pCursor);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Looks up and returns the object
+ /// instance based on the native pointer to the sqlite3_vtab derived
+ /// structure.
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// The object instance or null if
+ /// the corresponding one cannot be found.
+ ///
+ protected virtual SQLiteVirtualTable TableFromIntPtr(
+ IntPtr pVtab
+ )
+ {
+ if (pVtab == IntPtr.Zero)
+ {
+ SetTableError(pVtab, "invalid native table");
+ return null;
+ }
+
+ SQLiteVirtualTable table;
+
+ if ((tables != null) &&
+ tables.TryGetValue(pVtab, out table))
+ {
+ return table;
+ }
+
+ SetTableError(pVtab, String.Format(
+ CultureInfo.CurrentCulture,
+ "managed table for {0} not found", pVtab));
+
+ return null;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Allocates and returns a native pointer to a sqlite3_vtab derived
+ /// structure and creates an association between it and the specified
+ /// object instance.
+ ///
+ ///
+ /// The object instance to be used
+ /// when creating the association.
+ ///
+ ///
+ /// The native pointer to a sqlite3_vtab derived structure or
+ /// if the method fails for any reason.
+ ///
+ protected virtual IntPtr TableToIntPtr(
+ SQLiteVirtualTable table
+ )
+ {
+ if ((table == null) || (tables == null))
+ return IntPtr.Zero;
+
+ IntPtr pVtab = IntPtr.Zero;
+ bool success = false;
+
+ try
+ {
+ pVtab = AllocateTable();
+
+ if (pVtab != IntPtr.Zero)
+ {
+ ZeroTable(pVtab);
+ table.NativeHandle = pVtab;
+ tables.Add(pVtab, table);
+ success = true;
+ }
+ }
+ finally
+ {
+ if (!success && (pVtab != IntPtr.Zero))
+ {
+ FreeTable(pVtab);
+ pVtab = IntPtr.Zero;
+ }
+ }
+
+ return pVtab;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Cursor Lookup Methods
+ ///
+ /// Looks up and returns the
+ /// object instance based on the native pointer to the
+ /// sqlite3_vtab_cursor derived structure.
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab_cursor derived structure.
+ ///
+ ///
+ /// The object instance or null
+ /// if the corresponding one cannot be found.
+ ///
+ protected virtual SQLiteVirtualTableCursor CursorFromIntPtr(
+ IntPtr pVtab,
+ IntPtr pCursor
+ )
+ {
+ if (pCursor == IntPtr.Zero)
+ {
+ SetTableError(pVtab, "invalid native cursor");
+ return null;
+ }
+
+ SQLiteVirtualTableCursor cursor;
+
+ if ((cursors != null) &&
+ cursors.TryGetValue(pCursor, out cursor))
+ {
+ return cursor;
+ }
+
+ SetTableError(pVtab, String.Format(
+ CultureInfo.CurrentCulture,
+ "managed cursor for {0} not found", pCursor));
+
+ return null;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Allocates and returns a native pointer to a sqlite3_vtab_cursor
+ /// derived structure and creates an association between it and the
+ /// specified object instance.
+ ///
+ ///
+ /// The object instance to be
+ /// used when creating the association.
+ ///
+ ///
+ /// The native pointer to a sqlite3_vtab_cursor derived structure or
+ /// if the method fails for any reason.
+ ///
+ protected virtual IntPtr CursorToIntPtr(
+ SQLiteVirtualTableCursor cursor
+ )
+ {
+ if ((cursor == null) || (cursors == null))
+ return IntPtr.Zero;
+
+ IntPtr pCursor = IntPtr.Zero;
+ bool success = false;
+
+ try
+ {
+ pCursor = AllocateCursor();
+
+ if (pCursor != IntPtr.Zero)
+ {
+ cursor.NativeHandle = pCursor;
+ cursors.Add(pCursor, cursor);
+ success = true;
+ }
+ }
+ finally
+ {
+ if (!success && (pCursor != IntPtr.Zero))
+ {
+ FreeCursor(pCursor);
+ pCursor = IntPtr.Zero;
+ }
+ }
+
+ return pCursor;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Table Declaration Helper Methods
+ ///
+ /// Attempts to declare the schema for the virtual table using the
+ /// specified database connection.
+ ///
+ ///
+ /// The object instance to use when
+ /// declaring the schema of the virtual table.
+ ///
+ ///
+ /// The string containing the CREATE TABLE statement that completely
+ /// describes the schema for the virtual table.
+ ///
+ ///
+ /// Upon failure, this parameter must be modified to contain an error
+ /// message.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ protected virtual SQLiteErrorCode DeclareTable(
+ SQLiteConnection connection,
+ string sql,
+ ref string error
+ )
+ {
+ if (connection == null)
+ {
+ error = "invalid connection";
+ return SQLiteErrorCode.Error;
+ }
+
+ SQLiteBase sqliteBase = connection._sql;
+
+ if (sqliteBase == null)
+ {
+ error = "connection has invalid handle";
+ return SQLiteErrorCode.Error;
+ }
+
+ return sqliteBase.DeclareVirtualTable(this, sql, ref error);
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Error Handling Helper Methods
+ ///
+ /// Arranges for the specified error message to be placed into the
+ /// zErrMsg field of a sqlite3_vtab derived structure, freeing the
+ /// existing error message, if any.
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// The error message.
+ ///
+ ///
+ /// Non-zero upon success.
+ ///
+ protected virtual bool SetTableError(
+ IntPtr pVtab,
+ string error
+ )
+ {
+ return SetTableError(this, pVtab, LogErrors, error);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Arranges for the specified error message to be placed into the
+ /// zErrMsg field of a sqlite3_vtab derived structure, freeing the
+ /// existing error message, if any.
+ ///
+ ///
+ /// The object instance used to
+ /// lookup the native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// The error message.
+ ///
+ ///
+ /// Non-zero upon success.
+ ///
+ protected virtual bool SetTableError(
+ SQLiteVirtualTable table,
+ string error
+ )
+ {
+ return SetTableError(this, table, LogErrors, error);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Arranges for the specified error message to be placed into the
+ /// zErrMsg field of a sqlite3_vtab derived structure, freeing the
+ /// existing error message, if any.
+ ///
+ ///
+ /// The object instance used to
+ /// lookup the native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// The error message.
+ ///
+ ///
+ /// Non-zero upon success.
+ ///
+ protected virtual bool SetCursorError(
+ SQLiteVirtualTableCursor cursor,
+ string error
+ )
+ {
+ return SetCursorError(this, cursor, LogErrors, error);
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Static Error Handling Helper Methods
+ ///
+ /// Arranges for the specified error message to be placed into the
+ /// zErrMsg field of a sqlite3_vtab derived structure, freeing the
+ /// existing error message, if any.
+ ///
+ ///
+ /// The object instance to be used.
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// Non-zero if this error message should also be logged using the
+ /// class.
+ ///
+ ///
+ /// The error message.
+ ///
+ ///
+ /// Non-zero upon success.
+ ///
+ private static bool SetTableError(
+ SQLiteModule module,
+ IntPtr pVtab,
+ bool logErrors,
+ string error
+ )
+ {
+ try
+ {
+ if (logErrors)
+ {
+ SQLiteLog.LogMessage(SQLiteErrorCode.Error,
+ String.Format(CultureInfo.CurrentCulture,
+ "Virtual table error: {0}", error)); /* throw */
+ }
+ }
+ catch
+ {
+ // do nothing.
+ }
+
+ if (pVtab == IntPtr.Zero)
+ return false;
+
+ int offset = IntPtr.Size + sizeof(int);
+ IntPtr pError = SQLiteMarshal.ReadIntPtr(pVtab, offset);
+
+ if (pError != IntPtr.Zero)
+ {
+ SQLiteMemory.Free(pError); pError = IntPtr.Zero;
+ SQLiteMarshal.WriteIntPtr(pVtab, offset, pError);
+ }
+
+ if (error == null)
+ return true;
+
+ bool success = false;
+
+ try
+ {
+ pError = SQLiteString.Utf8IntPtrFromString(error);
+ SQLiteMarshal.WriteIntPtr(pVtab, offset, pError);
+ success = true;
+ }
+ finally
+ {
+ if (!success && (pError != IntPtr.Zero))
+ {
+ SQLiteMemory.Free(pError);
+ pError = IntPtr.Zero;
+ }
+ }
+
+ return success;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Arranges for the specified error message to be placed into the
+ /// zErrMsg field of a sqlite3_vtab derived structure, freeing the
+ /// existing error message, if any.
+ ///
+ ///
+ /// The object instance to be used.
+ ///
+ ///
+ /// The object instance used to
+ /// lookup the native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// Non-zero if this error message should also be logged using the
+ /// class.
+ ///
+ ///
+ /// The error message.
+ ///
+ ///
+ /// Non-zero upon success.
+ ///
+ private static bool SetTableError(
+ SQLiteModule module,
+ SQLiteVirtualTable table,
+ bool logErrors,
+ string error
+ )
+ {
+ if (table == null)
+ return false;
+
+ IntPtr pVtab = table.NativeHandle;
+
+ if (pVtab == IntPtr.Zero)
+ return false;
+
+ return SetTableError(module, pVtab, logErrors, error);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Arranges for the specified error message to be placed into the
+ /// zErrMsg field of a sqlite3_vtab derived structure, freeing the
+ /// existing error message, if any.
+ ///
+ ///
+ /// The object instance to be used.
+ ///
+ ///
+ /// The native pointer to the sqlite3_vtab_cursor derived structure
+ /// used to get the native pointer to the sqlite3_vtab derived
+ /// structure.
+ ///
+ ///
+ /// Non-zero if this error message should also be logged using the
+ /// class.
+ ///
+ ///
+ /// The error message.
+ ///
+ ///
+ /// Non-zero upon success.
+ ///
+ private static bool SetCursorError(
+ SQLiteModule module,
+ IntPtr pCursor,
+ bool logErrors,
+ string error
+ )
+ {
+ if (pCursor == IntPtr.Zero)
+ return false;
+
+ IntPtr pVtab = TableFromCursor(module, pCursor);
+
+ if (pVtab == IntPtr.Zero)
+ return false;
+
+ return SetTableError(module, pVtab, logErrors, error);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Arranges for the specified error message to be placed into the
+ /// zErrMsg field of a sqlite3_vtab derived structure, freeing the
+ /// existing error message, if any.
+ ///
+ ///
+ /// The object instance to be used.
+ ///
+ ///
+ /// The object instance used to
+ /// lookup the native pointer to the sqlite3_vtab derived structure.
+ ///
+ ///
+ /// Non-zero if this error message should also be logged using the
+ /// class.
+ ///
+ ///
+ /// The error message.
+ ///
+ ///
+ /// Non-zero upon success.
+ ///
+ private static bool SetCursorError(
+ SQLiteModule module,
+ SQLiteVirtualTableCursor cursor,
+ bool logErrors,
+ string error
+ )
+ {
+ if (cursor == null)
+ return false;
+
+ IntPtr pCursor = cursor.NativeHandle;
+
+ if (pCursor == IntPtr.Zero)
+ return false;
+
+ return SetCursorError(module, pCursor, logErrors, error);
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Index Handling Helper Methods
+ ///
+ /// Modifies the specified object instance
+ /// to contain the specified estimated cost.
+ ///
+ ///
+ /// The object instance to modify.
+ ///
+ ///
+ /// The estimated cost value to use.
+ ///
+ ///
+ /// Non-zero upon success.
+ ///
+ protected virtual bool SetEstimatedCost(
+ SQLiteIndex index,
+ double estimatedCost
+ )
+ {
+ if ((index == null) || (index.Outputs == null))
+ return false;
+
+ index.Outputs.EstimatedCost = estimatedCost;
+ return true;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Modifies the specified object instance
+ /// to contain the default estimated cost.
+ ///
+ ///
+ /// The object instance to modify.
+ ///
+ ///
+ /// Non-zero upon success.
+ ///
+ protected virtual bool SetEstimatedCost(
+ SQLiteIndex index
+ )
+ {
+ return SetEstimatedCost(index, DefaultEstimatedCost);
+ }
+ #endregion
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Public Properties
+ private bool logErrors;
+ ///
+ /// Returns or sets a boolean value indicating whether virtual table
+ /// errors should be logged using the class.
+ ///
+ public virtual bool LogErrors
+ {
+ get { CheckDisposed(); return logErrors; }
+ set { CheckDisposed(); logErrors = value; }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ private bool logExceptions;
+ ///
+ /// Returns or sets a boolean value indicating whether exceptions
+ /// caught in the
+ /// method,
+ /// method, and the
+ /// method should be logged using the
+ /// class.
+ ///
+ public virtual bool LogExceptions
+ {
+ get { CheckDisposed(); return logExceptions; }
+ set { CheckDisposed(); logExceptions = value; }
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region ISQLiteNativeModule Members
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xCreate(
+ IntPtr pDb,
+ IntPtr pAux,
+ int argc,
+ IntPtr argv,
+ ref IntPtr pVtab,
+ ref IntPtr pError
+ )
+ {
+ try
+ {
+ string fileName = SQLiteString.StringFromUtf8IntPtr(
+ UnsafeNativeMethods.sqlite3_db_filename(pDb, IntPtr.Zero));
+
+ using (SQLiteConnection connection = new SQLiteConnection(
+ pDb, fileName, false))
+ {
+ SQLiteVirtualTable table = null;
+ string error = null;
+
+ if (Create(connection, pAux,
+ SQLiteString.StringArrayFromUtf8SizeAndIntPtr(argc,
+ argv), ref table, ref error) == SQLiteErrorCode.Ok)
+ {
+ if (table != null)
+ {
+ pVtab = TableToIntPtr(table);
+ return SQLiteErrorCode.Ok;
+ }
+ else
+ {
+ pError = SQLiteString.Utf8IntPtrFromString(
+ "no table was created");
+ }
+ }
+ else
+ {
+ pError = SQLiteString.Utf8IntPtrFromString(error);
+ }
+ }
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ pError = SQLiteString.Utf8IntPtrFromString(e.ToString());
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xConnect(
+ IntPtr pDb,
+ IntPtr pAux,
+ int argc,
+ IntPtr argv,
+ ref IntPtr pVtab,
+ ref IntPtr pError
+ )
+ {
+ try
+ {
+ string fileName = SQLiteString.StringFromUtf8IntPtr(
+ UnsafeNativeMethods.sqlite3_db_filename(pDb, IntPtr.Zero));
+
+ using (SQLiteConnection connection = new SQLiteConnection(
+ pDb, fileName, false))
+ {
+ SQLiteVirtualTable table = null;
+ string error = null;
+
+ if (Connect(connection, pAux,
+ SQLiteString.StringArrayFromUtf8SizeAndIntPtr(argc,
+ argv), ref table, ref error) == SQLiteErrorCode.Ok)
+ {
+ if (table != null)
+ {
+ pVtab = TableToIntPtr(table);
+ return SQLiteErrorCode.Ok;
+ }
+ else
+ {
+ pError = SQLiteString.Utf8IntPtrFromString(
+ "no table was created");
+ }
+ }
+ else
+ {
+ pError = SQLiteString.Utf8IntPtrFromString(error);
+ }
+ }
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ pError = SQLiteString.Utf8IntPtrFromString(e.ToString());
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xBestIndex(
+ IntPtr pVtab,
+ IntPtr pIndex
+ )
+ {
+ try
+ {
+ SQLiteVirtualTable table = TableFromIntPtr(pVtab);
+
+ if (table != null)
+ {
+ SQLiteIndex index = null;
+
+ SQLiteMarshal.IndexFromIntPtr(pIndex, ref index);
+
+ if (BestIndex(table, index) == SQLiteErrorCode.Ok)
+ {
+ SQLiteMarshal.IndexToIntPtr(index, pIndex);
+ return SQLiteErrorCode.Ok;
+ }
+ }
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ SetTableError(pVtab, e.ToString());
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xDisconnect(
+ IntPtr pVtab
+ )
+ {
+ try
+ {
+ SQLiteVirtualTable table = TableFromIntPtr(pVtab);
+
+ if (table != null)
+ {
+ if (Disconnect(table) == SQLiteErrorCode.Ok)
+ {
+ if (tables != null)
+ tables.Remove(pVtab);
+
+ return SQLiteErrorCode.Ok;
+ }
+ }
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ //
+ // NOTE: At this point, there is no way to report the error
+ // condition back to the caller; therefore, use the
+ // logging facility instead.
+ //
+ try
+ {
+ if (LogExceptions)
+ {
+ SQLiteLog.LogMessage(SQLiteBase.COR_E_EXCEPTION,
+ String.Format(CultureInfo.CurrentCulture,
+ "Caught exception in \"xDisconnect\" method: {0}",
+ e)); /* throw */
+ }
+ }
+ catch
+ {
+ // do nothing.
+ }
+ }
+ finally
+ {
+ FreeTable(pVtab);
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xDestroy(
+ IntPtr pVtab
+ )
+ {
+ try
+ {
+ SQLiteVirtualTable table = TableFromIntPtr(pVtab);
+
+ if (table != null)
+ {
+ if (Destroy(table) == SQLiteErrorCode.Ok)
+ {
+ if (tables != null)
+ tables.Remove(pVtab);
+
+ return SQLiteErrorCode.Ok;
+ }
+ }
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ //
+ // NOTE: At this point, there is no way to report the error
+ // condition back to the caller; therefore, use the
+ // logging facility instead.
+ //
+ try
+ {
+ if (LogExceptions)
+ {
+ SQLiteLog.LogMessage(SQLiteBase.COR_E_EXCEPTION,
+ String.Format(CultureInfo.CurrentCulture,
+ "Caught exception in \"xDestroy\" method: {0}",
+ e)); /* throw */
+ }
+ }
+ catch
+ {
+ // do nothing.
+ }
+ }
+ finally
+ {
+ FreeTable(pVtab);
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xOpen(
+ IntPtr pVtab,
+ ref IntPtr pCursor
+ )
+ {
+ try
+ {
+ SQLiteVirtualTable table = TableFromIntPtr(pVtab);
+
+ if (table != null)
+ {
+ SQLiteVirtualTableCursor cursor = null;
+
+ if (Open(table, ref cursor) == SQLiteErrorCode.Ok)
+ {
+ if (cursor != null)
+ {
+ pCursor = CursorToIntPtr(cursor);
+
+ if (pCursor != IntPtr.Zero)
+ {
+ return SQLiteErrorCode.Ok;
+ }
+ else
+ {
+ SetTableError(pVtab,
+ "no native cursor was created");
+ }
+ }
+ else
+ {
+ SetTableError(pVtab,
+ "no managed cursor was created");
+ }
+ }
+ }
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ SetTableError(pVtab, e.ToString());
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xClose(
+ IntPtr pCursor
+ )
+ {
+ IntPtr pVtab = IntPtr.Zero;
+
+ try
+ {
+ pVtab = TableFromCursor(pCursor);
+
+ SQLiteVirtualTableCursor cursor = CursorFromIntPtr(
+ pVtab, pCursor);
+
+ if (cursor != null)
+ {
+ if (Close(cursor) == SQLiteErrorCode.Ok)
+ {
+ if (cursors != null)
+ cursors.Remove(pCursor);
+
+ return SQLiteErrorCode.Ok;
+ }
+ }
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ SetTableError(pVtab, e.ToString());
+ }
+ finally
+ {
+ FreeCursor(pCursor);
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xFilter(
+ IntPtr pCursor,
+ int idxNum,
+ IntPtr idxStr,
+ int argc,
+ IntPtr argv
+ )
+ {
+ IntPtr pVtab = IntPtr.Zero;
+
+ try
+ {
+ pVtab = TableFromCursor(pCursor);
+
+ SQLiteVirtualTableCursor cursor = CursorFromIntPtr(
+ pVtab, pCursor);
+
+ if (cursor != null)
+ {
+ if (Filter(cursor, idxNum,
+ SQLiteString.StringFromUtf8IntPtr(idxStr),
+ SQLiteMarshal.ValueArrayFromSizeAndIntPtr(argc,
+ argv)) == SQLiteErrorCode.Ok)
+ {
+ return SQLiteErrorCode.Ok;
+ }
+ }
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ SetTableError(pVtab, e.ToString());
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xNext(
+ IntPtr pCursor
+ )
+ {
+ IntPtr pVtab = IntPtr.Zero;
+
+ try
+ {
+ pVtab = TableFromCursor(pCursor);
+
+ SQLiteVirtualTableCursor cursor = CursorFromIntPtr(
+ pVtab, pCursor);
+
+ if (cursor != null)
+ {
+ if (Next(cursor) == SQLiteErrorCode.Ok)
+ return SQLiteErrorCode.Ok;
+ }
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ SetTableError(pVtab, e.ToString());
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private int xEof(
+ IntPtr pCursor
+ )
+ {
+ IntPtr pVtab = IntPtr.Zero;
+
+ try
+ {
+ pVtab = TableFromCursor(pCursor);
+
+ SQLiteVirtualTableCursor cursor = CursorFromIntPtr(
+ pVtab, pCursor);
+
+ if (cursor != null)
+ return Eof(cursor) ? 1 : 0;
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ SetTableError(pVtab, e.ToString());
+ }
+
+ return 1;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xColumn(
+ IntPtr pCursor,
+ IntPtr pContext,
+ int index
+ )
+ {
+ IntPtr pVtab = IntPtr.Zero;
+
+ try
+ {
+ pVtab = TableFromCursor(pCursor);
+
+ SQLiteVirtualTableCursor cursor = CursorFromIntPtr(
+ pVtab, pCursor);
+
+ if (cursor != null)
+ {
+ SQLiteContext context = new SQLiteContext(pContext);
+
+ return Column(cursor, context, index);
+ }
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ SetTableError(pVtab, e.ToString());
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xRowId(
+ IntPtr pCursor,
+ ref long rowId
+ )
+ {
+ IntPtr pVtab = IntPtr.Zero;
+
+ try
+ {
+ pVtab = TableFromCursor(pCursor);
+
+ SQLiteVirtualTableCursor cursor = CursorFromIntPtr(
+ pVtab, pCursor);
+
+ if (cursor != null)
+ return RowId(cursor, ref rowId);
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ SetTableError(pVtab, e.ToString());
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xUpdate(
+ IntPtr pVtab,
+ int argc,
+ IntPtr argv,
+ ref long rowId
+ )
+ {
+ try
+ {
+ SQLiteVirtualTable table = TableFromIntPtr(pVtab);
+
+ if (table != null)
+ {
+ return Update(
+ table, SQLiteMarshal.ValueArrayFromSizeAndIntPtr(
+ argc, argv), ref rowId);
+ }
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ SetTableError(pVtab, e.ToString());
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xBegin(
+ IntPtr pVtab
+ )
+ {
+ try
+ {
+ SQLiteVirtualTable table = TableFromIntPtr(pVtab);
+
+ if (table != null)
+ return Begin(table);
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ SetTableError(pVtab, e.ToString());
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xSync(
+ IntPtr pVtab
+ )
+ {
+ try
+ {
+ SQLiteVirtualTable table = TableFromIntPtr(pVtab);
+
+ if (table != null)
+ return Sync(table);
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ SetTableError(pVtab, e.ToString());
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xCommit(
+ IntPtr pVtab
+ )
+ {
+ try
+ {
+ SQLiteVirtualTable table = TableFromIntPtr(pVtab);
+
+ if (table != null)
+ return Commit(table);
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ SetTableError(pVtab, e.ToString());
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xRollback(
+ IntPtr pVtab
+ )
+ {
+ try
+ {
+ SQLiteVirtualTable table = TableFromIntPtr(pVtab);
+
+ if (table != null)
+ return Rollback(table);
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ SetTableError(pVtab, e.ToString());
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private int xFindFunction(
+ IntPtr pVtab,
+ int nArg,
+ IntPtr zName,
+ ref SQLiteCallback callback,
+ ref IntPtr pClientData
+ )
+ {
+ try
+ {
+ SQLiteVirtualTable table = TableFromIntPtr(pVtab);
+
+ if (table != null)
+ {
+ SQLiteFunction function = null;
+
+ if (FindFunction(
+ table, nArg,
+ SQLiteString.StringFromUtf8IntPtr(zName),
+ ref function, ref pClientData))
+ {
+ if (function != null)
+ {
+ callback = function.ScalarCallback;
+ return 1;
+ }
+ else
+ {
+ SetTableError(pVtab, "no function was created");
+ }
+ }
+ }
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ SetTableError(pVtab, e.ToString());
+ }
+
+ return 0;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xRename(
+ IntPtr pVtab,
+ IntPtr zNew
+ )
+ {
+ try
+ {
+ SQLiteVirtualTable table = TableFromIntPtr(pVtab);
+
+ if (table != null)
+ {
+ return Rename(table,
+ SQLiteString.StringFromUtf8IntPtr(zNew));
+ }
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ SetTableError(pVtab, e.ToString());
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xSavepoint(
+ IntPtr pVtab,
+ int iSavepoint
+ )
+ {
+ try
+ {
+ SQLiteVirtualTable table = TableFromIntPtr(pVtab);
+
+ if (table != null)
+ return Savepoint(table, iSavepoint);
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ SetTableError(pVtab, e.ToString());
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xRelease(
+ IntPtr pVtab,
+ int iSavepoint
+ )
+ {
+ try
+ {
+ SQLiteVirtualTable table = TableFromIntPtr(pVtab);
+
+ if (table != null)
+ return Release(table, iSavepoint);
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ SetTableError(pVtab, e.ToString());
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ private SQLiteErrorCode xRollbackTo(
+ IntPtr pVtab,
+ int iSavepoint
+ )
+ {
+ try
+ {
+ SQLiteVirtualTable table = TableFromIntPtr(pVtab);
+
+ if (table != null)
+ return RollbackTo(table, iSavepoint);
+ }
+ catch (Exception e) /* NOTE: Must catch ALL. */
+ {
+ SetTableError(pVtab, e.ToString());
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region ISQLiteManagedModule Members
+ private bool declared;
+ ///
+ /// Returns non-zero if the schema for the virtual table has been
+ /// declared.
+ ///
+ public virtual bool Declared
+ {
+ get { CheckDisposed(); return declared; }
+ internal set { declared = value; }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ private string name;
+ ///
+ /// Returns the name of the module as it was registered with the SQLite
+ /// core library.
+ ///
+ public virtual string Name
+ {
+ get { CheckDisposed(); return name; }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated with
+ /// the virtual table.
+ ///
+ ///
+ /// The native user-data pointer associated with this module, as it was
+ /// provided to the SQLite core library when the native module instance
+ /// was created.
+ ///
+ ///
+ /// The module name, database name, virtual table name, and all other
+ /// arguments passed to the CREATE VIRTUAL TABLE statement.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to contain the
+ /// object instance associated with
+ /// the virtual table.
+ ///
+ ///
+ /// Upon failure, this parameter must be modified to contain an error
+ /// message.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode Create(
+ SQLiteConnection connection,
+ IntPtr pClientData,
+ string[] arguments,
+ ref SQLiteVirtualTable table,
+ ref string error
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated with
+ /// the virtual table.
+ ///
+ ///
+ /// The native user-data pointer associated with this module, as it was
+ /// provided to the SQLite core library when the native module instance
+ /// was created.
+ ///
+ ///
+ /// The module name, database name, virtual table name, and all other
+ /// arguments passed to the CREATE VIRTUAL TABLE statement.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to contain the
+ /// object instance associated with
+ /// the virtual table.
+ ///
+ ///
+ /// Upon failure, this parameter must be modified to contain an error
+ /// message.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode Connect(
+ SQLiteConnection connection,
+ IntPtr pClientData,
+ string[] arguments,
+ ref SQLiteVirtualTable table,
+ ref string error
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// The object instance containing all the
+ /// data for the inputs and outputs relating to index selection.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode BestIndex(
+ SQLiteVirtualTable table,
+ SQLiteIndex index
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode Disconnect(
+ SQLiteVirtualTable table
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode Destroy(
+ SQLiteVirtualTable table
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to contain the
+ /// object instance associated
+ /// with the newly opened virtual table cursor.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode Open(
+ SQLiteVirtualTable table,
+ ref SQLiteVirtualTableCursor cursor
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance
+ /// associated with the previously opened virtual table cursor to be
+ /// used.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode Close(
+ SQLiteVirtualTableCursor cursor
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance
+ /// associated with the previously opened virtual table cursor to be
+ /// used.
+ ///
+ ///
+ /// Number used to help identify the selected index.
+ ///
+ ///
+ /// String used to help identify the selected index.
+ ///
+ ///
+ /// The values corresponding to each column in the selected index.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode Filter(
+ SQLiteVirtualTableCursor cursor,
+ int indexNumber,
+ string indexString,
+ SQLiteValue[] values
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance
+ /// associated with the previously opened virtual table cursor to be
+ /// used.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode Next(
+ SQLiteVirtualTableCursor cursor
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance
+ /// associated with the previously opened virtual table cursor to be
+ /// used.
+ ///
+ ///
+ /// Non-zero if no more rows are available; zero otherwise.
+ ///
+ public abstract bool Eof(
+ SQLiteVirtualTableCursor cursor
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance
+ /// associated with the previously opened virtual table cursor to be
+ /// used.
+ ///
+ ///
+ /// The object instance to be used for
+ /// returning the specified column value to the SQLite core library.
+ ///
+ ///
+ /// The zero-based index corresponding to the column containing the
+ /// value to be returned.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode Column(
+ SQLiteVirtualTableCursor cursor,
+ SQLiteContext context,
+ int index
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance
+ /// associated with the previously opened virtual table cursor to be
+ /// used.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to contain the unique
+ /// integer row identifier for the current row for the specified cursor.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode RowId(
+ SQLiteVirtualTableCursor cursor,
+ ref long rowId
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// The array of object instances containing
+ /// the new or modified column values, if any.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to contain the unique
+ /// integer row identifier for the row that was inserted, if any.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode Update(
+ SQLiteVirtualTable table,
+ SQLiteValue[] values,
+ ref long rowId
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode Begin(
+ SQLiteVirtualTable table
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode Sync(
+ SQLiteVirtualTable table
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode Commit(
+ SQLiteVirtualTable table
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode Rollback(
+ SQLiteVirtualTable table
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// The number of arguments to the function being sought.
+ ///
+ ///
+ /// The name of the function being sought.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to contain the
+ /// object instance responsible for
+ /// implementing the specified function.
+ ///
+ ///
+ /// Upon success, this parameter must be modified to contain the
+ /// native user-data pointer associated with
+ /// .
+ ///
+ ///
+ /// Non-zero if the specified function was found; zero otherwise.
+ ///
+ public abstract bool FindFunction(
+ SQLiteVirtualTable table,
+ int argumentCount,
+ string name,
+ ref SQLiteFunction function,
+ ref IntPtr pClientData
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// The new name for the virtual table.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode Rename(
+ SQLiteVirtualTable table,
+ string newName
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// This is an integer identifier under which the the current state of
+ /// the virtual table should be saved.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode Savepoint(
+ SQLiteVirtualTable table,
+ int savepoint
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// This is an integer used to indicate that any saved states with an
+ /// identifier greater than or equal to this should be deleted by the
+ /// virtual table.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode Release(
+ SQLiteVirtualTable table,
+ int savepoint
+ );
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method is called in response to the
+ /// method.
+ ///
+ ///
+ /// The object instance associated
+ /// with this virtual table.
+ ///
+ ///
+ /// This is an integer identifier used to specify a specific saved
+ /// state for the virtual table for it to restore itself back to, which
+ /// should also have the effect of deleting all saved states with an
+ /// integer identifier greater than this one.
+ ///
+ ///
+ /// A standard SQLite return code.
+ ///
+ public abstract SQLiteErrorCode RollbackTo(
+ SQLiteVirtualTable table,
+ int savepoint
+ );
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region IDisposable Members
+ ///
+ /// Disposes of this object instance.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region IDisposable "Pattern" Members
+ private bool disposed;
+ ///
+ /// Throws an if this object
+ /// instance has been disposed.
+ ///
+ private void CheckDisposed() /* throw */
+ {
+#if THROW_ON_DISPOSED
+ if (disposed)
+ {
+ throw new ObjectDisposedException(
+ typeof(SQLiteModule).Name);
+ }
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Disposes of this object instance.
+ ///
+ ///
+ /// Non-zero if this method is being called from the
+ /// method. Zero if this method is being
+ /// called from the finalizer.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposed)
+ {
+ //if (disposing)
+ //{
+ // ////////////////////////////////////
+ // // dispose managed resources here...
+ // ////////////////////////////////////
+ //}
+
+ //////////////////////////////////////
+ // release unmanaged resources here...
+ //////////////////////////////////////
+
+ try
+ {
+#if !PLATFORM_COMPACTFRAMEWORK
+ UnsafeNativeMethods.sqlite3_dispose_module(
+ ref nativeModule);
+#elif !SQLITE_STANDARD
+ if (pNativeModule != IntPtr.Zero)
+ {
+ try
+ {
+ UnsafeNativeMethods.sqlite3_dispose_module_interop(
+ pNativeModule);
+ }
+ finally
+ {
+ SQLiteMemory.Free(pNativeModule);
+ }
+ }
+#else
+ throw new NotImplementedException();
+#endif
+ }
+ catch (Exception e)
+ {
+ try
+ {
+ if (LogExceptions)
+ {
+ SQLiteLog.LogMessage(SQLiteBase.COR_E_EXCEPTION,
+ String.Format(CultureInfo.CurrentCulture,
+ "Caught exception in \"Dispose\" method: {0}",
+ e)); /* throw */
+ }
+ }
+ catch
+ {
+ // do nothing.
+ }
+ }
+
+ disposed = true;
+ }
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Destructor
+ ///
+ /// Finalizes this object instance.
+ ///
+ ~SQLiteModule()
+ {
+ Dispose(false);
+ }
+ #endregion
+ }
+ #endregion
+}
ADDED System.Data.SQLite/SQLiteModuleEnumerable.cs
Index: System.Data.SQLite/SQLiteModuleEnumerable.cs
==================================================================
--- /dev/null
+++ System.Data.SQLite/SQLiteModuleEnumerable.cs
@@ -0,0 +1,887 @@
+/********************************************************
+ * ADO.NET 2.0 Data Provider for SQLite Version 3.X
+ * Written by Joe Mistachkin (joe@mistachkin.com)
+ *
+ * Released to the public domain, use at your own risk!
+ ********************************************************/
+
+using System.Collections;
+using System.Globalization;
+
+namespace System.Data.SQLite
+{
+ #region SQLiteVirtualTableCursorEnumerable Class
+ ///
+ /// This class represents a virtual table cursor to be used with the
+ /// class. It is not sealed and may
+ /// be used as the base class for any user-defined virtual table cursor
+ /// class that wraps an object instance.
+ ///
+ public class SQLiteVirtualTableCursorEnumerable :
+ SQLiteVirtualTableCursor /* NOT SEALED */
+ {
+ #region Private Data
+ ///
+ /// The instance provided when this cursor
+ /// was created.
+ ///
+ private IEnumerator enumerator;
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This value will be non-zero if false has been returned from the
+ /// method.
+ ///
+ private bool endOfEnumerator;
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Public Constructors
+ ///
+ /// Constructs an instance of this class.
+ ///
+ ///
+ /// The object instance associated
+ /// with this object instance.
+ ///
+ ///
+ /// The instance to expose as a virtual
+ /// table cursor.
+ ///
+ public SQLiteVirtualTableCursorEnumerable(
+ SQLiteVirtualTable table,
+ IEnumerator enumerator
+ )
+ : base(table)
+ {
+ this.enumerator = enumerator;
+ this.endOfEnumerator = true;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Public Members
+ ///
+ /// Advances to the next row of the virtual table cursor using the
+ /// method of the
+ /// object instance.
+ ///
+ ///
+ /// Non-zero if the current row is valid; zero otherwise. If zero is
+ /// returned, no further rows are available.
+ ///
+ public virtual bool MoveNext()
+ {
+ CheckDisposed();
+
+ if (enumerator == null)
+ return false;
+
+ endOfEnumerator = !enumerator.MoveNext();
+ return !endOfEnumerator;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Returns the value for the current row of the virtual table cursor
+ /// using the property of the
+ /// object instance.
+ ///
+ public virtual object Current
+ {
+ get
+ {
+ CheckDisposed();
+
+ if (enumerator == null)
+ return null;
+
+ return enumerator.Current;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Resets the virtual table cursor position, also invalidating the
+ /// current row, using the method of
+ /// the object instance.
+ ///
+ public virtual void Reset()
+ {
+ CheckDisposed();
+
+ if (enumerator == null)
+ return;
+
+ enumerator.Reset();
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Returns non-zero if the end of the virtual table cursor has been
+ /// seen (i.e. no more rows are available, including the current one).
+ ///
+ public virtual bool EndOfEnumerator
+ {
+ get { CheckDisposed(); return endOfEnumerator; }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Closes the virtual table cursor.
+ ///
+ public virtual void Close()
+ {
+ // CheckDisposed();
+
+ if (enumerator != null)
+ enumerator = null;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region IDisposable "Pattern" Members
+ private bool disposed;
+ ///
+ /// Throws an if this object
+ /// instance has been disposed.
+ ///
+ private void CheckDisposed() /* throw */
+ {
+#if THROW_ON_DISPOSED
+ if (disposed)
+ {
+ throw new ObjectDisposedException(
+ typeof(SQLiteVirtualTableCursorEnumerable).Name);
+ }
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Disposes of this object instance.
+ ///
+ ///
+ /// Non-zero if this method is being called from the
+ /// method. Zero if this method is
+ /// being called from the finalizer.
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ try
+ {
+ if (!disposed)
+ {
+ //if (disposing)
+ //{
+ // ////////////////////////////////////
+ // // dispose managed resources here...
+ // ////////////////////////////////////
+ //}
+
+ //////////////////////////////////////
+ // release unmanaged resources here...
+ //////////////////////////////////////
+
+ Close();
+
+ disposed = true;
+ }
+ }
+ finally
+ {
+ base.Dispose(disposing);
+ }
+ }
+ #endregion
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region SQLiteModuleEnumerable Class
+ ///
+ /// This class implements a virtual table module that exposes an
+ /// IEnumerable instance as a read-only virtual table. It is not sealed
+ /// and may be used as the base class for any user-defined virtual table
+ /// class that wraps an object instance.
+ ///
+ public class SQLiteModuleEnumerable : SQLiteModuleNoop /* NOT SEALED */
+ {
+ #region Private Constants
+ ///
+ /// The CREATE TABLE statement used to declare the schema for the
+ /// virtual table.
+ ///
+ private static readonly string declareSql = String.Format(
+ CultureInfo.CurrentCulture, "CREATE TABLE {0}(x);",
+ typeof(SQLiteModuleEnumerable).Name);
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Private Data
+ ///
+ /// The instance containing the backing data
+ /// for the virtual table.
+ ///
+ private IEnumerable enumerable;
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Public Constructors
+ ///
+ /// Constructs an instance of this class.
+ ///
+ ///
+ /// The name of the module. This parameter cannot be null.
+ ///
+ ///
+ /// The instance to expose as a virtual
+ /// table. This parameter cannot be null.
+ ///
+ public SQLiteModuleEnumerable(
+ string name,
+ IEnumerable enumerable
+ )
+ : base(name)
+ {
+ if (enumerable == null)
+ throw new ArgumentNullException("enumerable");
+
+ this.enumerable = enumerable;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Protected Methods
+ ///
+ /// Sets the table error message to one that indicates the virtual
+ /// table cursor is of the wrong type.
+ ///
+ ///
+ /// The object instance.
+ ///
+ ///
+ /// The value of .
+ ///
+ protected virtual SQLiteErrorCode CursorTypeMismatchError(
+ SQLiteVirtualTableCursor cursor
+ )
+ {
+ SetCursorError(cursor, "not an \"enumerable\" cursor");
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Sets the table error message to one that indicates the virtual
+ /// table cursor has no current row.
+ ///
+ ///
+ /// The object instance.
+ ///
+ ///
+ /// The value of .
+ ///
+ protected virtual SQLiteErrorCode CursorEndOfEnumeratorError(
+ SQLiteVirtualTableCursor cursor
+ )
+ {
+ SetCursorError(cursor, "already hit end of enumerator");
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Determines the string to return as the column value for the object
+ /// instance value.
+ ///
+ ///
+ /// The object instance to return a string representation for.
+ ///
+ ///
+ /// The string representation of the specified object instance or null
+ /// upon failure.
+ ///
+ protected virtual string GetStringFromObject(
+ object value
+ )
+ {
+ if (value == null)
+ return null;
+
+ return value.ToString();
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Determines the unique row identifier for the object instance value.
+ ///
+ ///
+ /// The object instance to return a unique row identifier for.
+ ///
+ ///
+ /// The unique row identifier or zero upon failure.
+ ///
+ protected virtual long GetRowIdFromObject(
+ object value
+ )
+ {
+ if (value == null)
+ return 0;
+
+ return value.GetHashCode();
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Converts a into a boolean return
+ /// value for use with the
+ /// method.
+ ///
+ ///
+ /// The value to convert.
+ ///
+ ///
+ /// The value.
+ ///
+ protected virtual bool CodeToEofResult(
+ SQLiteErrorCode returnCode
+ )
+ {
+ return (returnCode == SQLiteErrorCode.Ok) ? false : true;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region ISQLiteManagedModule Members
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Create(
+ SQLiteConnection connection,
+ IntPtr pClientData,
+ string[] arguments,
+ ref SQLiteVirtualTable table,
+ ref string error
+ )
+ {
+ CheckDisposed();
+
+ if (DeclareTable(
+ connection, declareSql,
+ ref error) == SQLiteErrorCode.Ok)
+ {
+ table = new SQLiteVirtualTable(arguments);
+ return SQLiteErrorCode.Ok;
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Connect(
+ SQLiteConnection connection,
+ IntPtr pClientData,
+ string[] arguments,
+ ref SQLiteVirtualTable table,
+ ref string error
+ )
+ {
+ CheckDisposed();
+
+ if (DeclareTable(
+ connection, declareSql,
+ ref error) == SQLiteErrorCode.Ok)
+ {
+ table = new SQLiteVirtualTable(arguments);
+ return SQLiteErrorCode.Ok;
+ }
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode BestIndex(
+ SQLiteVirtualTable table,
+ SQLiteIndex index
+ )
+ {
+ CheckDisposed();
+
+ if (!SetEstimatedCost(index))
+ {
+ SetTableError(table, "failed to set estimated cost");
+ return SQLiteErrorCode.Error;
+ }
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Disconnect(
+ SQLiteVirtualTable table
+ )
+ {
+ CheckDisposed();
+
+ table.Dispose();
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Destroy(
+ SQLiteVirtualTable table
+ )
+ {
+ CheckDisposed();
+
+ table.Dispose();
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Open(
+ SQLiteVirtualTable table,
+ ref SQLiteVirtualTableCursor cursor
+ )
+ {
+ CheckDisposed();
+
+ cursor = new SQLiteVirtualTableCursorEnumerable(
+ table, enumerable.GetEnumerator());
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Close(
+ SQLiteVirtualTableCursor cursor
+ )
+ {
+ CheckDisposed();
+
+ SQLiteVirtualTableCursorEnumerable enumerableCursor =
+ cursor as SQLiteVirtualTableCursorEnumerable;
+
+ if (enumerableCursor == null)
+ return CursorTypeMismatchError(cursor);
+
+ enumerableCursor.Close();
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Filter(
+ SQLiteVirtualTableCursor cursor,
+ int indexNumber,
+ string indexString,
+ SQLiteValue[] values
+ )
+ {
+ CheckDisposed();
+
+ SQLiteVirtualTableCursorEnumerable enumerableCursor =
+ cursor as SQLiteVirtualTableCursorEnumerable;
+
+ if (enumerableCursor == null)
+ return CursorTypeMismatchError(cursor);
+
+ enumerableCursor.Filter(indexNumber, indexString, values);
+ enumerableCursor.Reset(); /* NO RESULT */
+ enumerableCursor.MoveNext(); /* IGNORED */
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Next(
+ SQLiteVirtualTableCursor cursor
+ )
+ {
+ CheckDisposed();
+
+ SQLiteVirtualTableCursorEnumerable enumerableCursor =
+ cursor as SQLiteVirtualTableCursorEnumerable;
+
+ if (enumerableCursor == null)
+ return CursorTypeMismatchError(cursor);
+
+ if (enumerableCursor.EndOfEnumerator)
+ return CursorEndOfEnumeratorError(cursor);
+
+ enumerableCursor.MoveNext(); /* IGNORED */
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override bool Eof(
+ SQLiteVirtualTableCursor cursor
+ )
+ {
+ CheckDisposed();
+
+ SQLiteVirtualTableCursorEnumerable enumerableCursor =
+ cursor as SQLiteVirtualTableCursorEnumerable;
+
+ if (enumerableCursor == null)
+ return CodeToEofResult(CursorTypeMismatchError(cursor));
+
+ return enumerableCursor.EndOfEnumerator;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Column(
+ SQLiteVirtualTableCursor cursor,
+ SQLiteContext context,
+ int index
+ )
+ {
+ CheckDisposed();
+
+ SQLiteVirtualTableCursorEnumerable enumerableCursor =
+ cursor as SQLiteVirtualTableCursorEnumerable;
+
+ if (enumerableCursor == null)
+ return CursorTypeMismatchError(cursor);
+
+ if (enumerableCursor.EndOfEnumerator)
+ return CursorEndOfEnumeratorError(cursor);
+
+ object current = enumerableCursor.Current;
+
+ if (current != null)
+ context.SetString(GetStringFromObject(current));
+ else
+ context.SetNull();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode RowId(
+ SQLiteVirtualTableCursor cursor,
+ ref long rowId
+ )
+ {
+ CheckDisposed();
+
+ SQLiteVirtualTableCursorEnumerable enumerableCursor =
+ cursor as SQLiteVirtualTableCursorEnumerable;
+
+ if (enumerableCursor == null)
+ return CursorTypeMismatchError(cursor);
+
+ if (enumerableCursor.EndOfEnumerator)
+ return CursorEndOfEnumeratorError(cursor);
+
+ object current = enumerableCursor.Current;
+
+ rowId = GetRowIdFromObject(current);
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Update(
+ SQLiteVirtualTable table,
+ SQLiteValue[] values,
+ ref long rowId
+ )
+ {
+ CheckDisposed();
+
+ SetTableError(table, String.Format(CultureInfo.CurrentCulture,
+ "virtual table \"{0}\" is read-only", table.TableName));
+
+ return SQLiteErrorCode.Error;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Rename(
+ SQLiteVirtualTable table,
+ string newName
+ )
+ {
+ CheckDisposed();
+
+ if (!table.Rename(newName))
+ {
+ SetTableError(table, String.Format(CultureInfo.CurrentCulture,
+ "failed to rename virtual table from \"{0}\" to \"{1}\"",
+ table.TableName, newName));
+
+ return SQLiteErrorCode.Error;
+ }
+
+ return SQLiteErrorCode.Ok;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region IDisposable "Pattern" Members
+ private bool disposed;
+ ///
+ /// Throws an if this object
+ /// instance has been disposed.
+ ///
+ private void CheckDisposed() /* throw */
+ {
+#if THROW_ON_DISPOSED
+ if (disposed)
+ {
+ throw new ObjectDisposedException(
+ typeof(SQLiteModuleNoop).Name);
+ }
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Disposes of this object instance.
+ ///
+ ///
+ /// Non-zero if this method is being called from the
+ /// method. Zero if this method is
+ /// being called from the finalizer.
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ try
+ {
+ if (!disposed)
+ {
+ //if (disposing)
+ //{
+ // ////////////////////////////////////
+ // // dispose managed resources here...
+ // ////////////////////////////////////
+ //}
+
+ //////////////////////////////////////
+ // release unmanaged resources here...
+ //////////////////////////////////////
+
+ disposed = true;
+ }
+ }
+ finally
+ {
+ base.Dispose(disposing);
+ }
+ }
+ #endregion
+ }
+ #endregion
+}
ADDED System.Data.SQLite/SQLiteModuleNoop.cs
Index: System.Data.SQLite/SQLiteModuleNoop.cs
==================================================================
--- /dev/null
+++ System.Data.SQLite/SQLiteModuleNoop.cs
@@ -0,0 +1,633 @@
+/********************************************************
+ * ADO.NET 2.0 Data Provider for SQLite Version 3.X
+ * Written by Joe Mistachkin (joe@mistachkin.com)
+ *
+ * Released to the public domain, use at your own risk!
+ ********************************************************/
+
+namespace System.Data.SQLite
+{
+ ///
+ /// This class implements a virtual table module that does nothing.
+ ///
+ public class SQLiteModuleNoop : SQLiteModule /* NOT SEALED */
+ {
+ #region Public Constructors
+ ///
+ /// Constructs an instance of this class.
+ ///
+ ///
+ /// The name of the module. This parameter cannot be null.
+ ///
+ public SQLiteModuleNoop(
+ string name
+ )
+ : base(name)
+ {
+ // do nothing.
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region ISQLiteManagedModule Members
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Create(
+ SQLiteConnection connection,
+ IntPtr pClientData,
+ string[] arguments,
+ ref SQLiteVirtualTable table,
+ ref string error
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Connect(
+ SQLiteConnection connection,
+ IntPtr pClientData,
+ string[] arguments,
+ ref SQLiteVirtualTable table,
+ ref string error
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode BestIndex(
+ SQLiteVirtualTable table,
+ SQLiteIndex index
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Disconnect(
+ SQLiteVirtualTable table
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Destroy(
+ SQLiteVirtualTable table
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Open(
+ SQLiteVirtualTable table,
+ ref SQLiteVirtualTableCursor cursor
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Close(
+ SQLiteVirtualTableCursor cursor
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Filter(
+ SQLiteVirtualTableCursor cursor,
+ int indexNumber,
+ string indexString,
+ SQLiteValue[] values
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Next(
+ SQLiteVirtualTableCursor cursor
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override bool Eof(
+ SQLiteVirtualTableCursor cursor
+ )
+ {
+ CheckDisposed();
+
+ return true;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Column(
+ SQLiteVirtualTableCursor cursor,
+ SQLiteContext context,
+ int index
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode RowId(
+ SQLiteVirtualTableCursor cursor,
+ ref long rowId
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Update(
+ SQLiteVirtualTable table,
+ SQLiteValue[] values,
+ ref long rowId
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Begin(
+ SQLiteVirtualTable table
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Sync(
+ SQLiteVirtualTable table
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Commit(
+ SQLiteVirtualTable table
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Rollback(
+ SQLiteVirtualTable table
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override bool FindFunction(
+ SQLiteVirtualTable table,
+ int argumentCount,
+ string name,
+ ref SQLiteFunction function,
+ ref IntPtr pClientData
+ )
+ {
+ CheckDisposed();
+
+ return false;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Rename(
+ SQLiteVirtualTable table,
+ string newName
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Savepoint(
+ SQLiteVirtualTable table,
+ int savepoint
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode Release(
+ SQLiteVirtualTable table,
+ int savepoint
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ ///
+ /// See the method.
+ ///
+ public override SQLiteErrorCode RollbackTo(
+ SQLiteVirtualTable table,
+ int savepoint
+ )
+ {
+ CheckDisposed();
+
+ return SQLiteErrorCode.Ok;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region IDisposable "Pattern" Members
+ private bool disposed;
+ ///
+ /// Throws an if this object
+ /// instance has been disposed.
+ ///
+ private void CheckDisposed() /* throw */
+ {
+#if THROW_ON_DISPOSED
+ if (disposed)
+ {
+ throw new ObjectDisposedException(
+ typeof(SQLiteModuleNoop).Name);
+ }
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Disposes of this object instance.
+ ///
+ ///
+ /// Non-zero if this method is being called from the
+ /// method. Zero if this method is
+ /// being called from the finalizer.
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ try
+ {
+ if (!disposed)
+ {
+ //if (disposing)
+ //{
+ // ////////////////////////////////////
+ // // dispose managed resources here...
+ // ////////////////////////////////////
+ //}
+
+ //////////////////////////////////////
+ // release unmanaged resources here...
+ //////////////////////////////////////
+
+ disposed = true;
+ }
+ }
+ finally
+ {
+ base.Dispose(disposing);
+ }
+ }
+ #endregion
+ }
+}
Index: System.Data.SQLite/SQLiteStatement.cs
==================================================================
--- System.Data.SQLite/SQLiteStatement.cs
+++ System.Data.SQLite/SQLiteStatement.cs
@@ -276,13 +276,14 @@
case TypeCode.Decimal:
return ((decimal)obj) != Decimal.Zero ? true : false;
case TypeCode.String:
return Convert.ToBoolean(obj, provider);
default:
- throw new SQLiteException(SQLiteErrorCode.Error,
- String.Format(CultureInfo.CurrentCulture,
- "Cannot convert type {0} to boolean", typeCode));
+ throw new SQLiteException(String.Format(
+ CultureInfo.CurrentCulture,
+ "Cannot convert type {0} to boolean",
+ typeCode));
}
}
///
/// Perform the bind operation for an individual parameter
@@ -290,11 +291,11 @@
/// The index of the parameter to bind
/// The parameter we're binding
private void BindParameter(int index, SQLiteParameter param)
{
if (param == null)
- throw new SQLiteException(SQLiteErrorCode.Error, "Insufficient parameters supplied to the command");
+ throw new SQLiteException("Insufficient parameters supplied to the command");
object obj = param.Value;
DbType objType = param.DbType;
if ((obj != null) && (objType == DbType.Object))
Index: System.Data.SQLite/SQLiteTransaction.cs
==================================================================
--- System.Data.SQLite/SQLiteTransaction.cs
+++ System.Data.SQLite/SQLiteTransaction.cs
@@ -197,23 +197,23 @@
else return false;
}
if (_cnn._version != _version)
{
- if (throwError == true) throw new SQLiteException(SQLiteErrorCode.Misuse, "The connection was closed and re-opened, changes were already rolled back");
+ if (throwError == true) throw new SQLiteException("The connection was closed and re-opened, changes were already rolled back");
else return false;
}
if (_cnn.State != ConnectionState.Open)
{
- if (throwError == true) throw new SQLiteException(SQLiteErrorCode.Misuse, "Connection was closed");
+ if (throwError == true) throw new SQLiteException("Connection was closed");
else return false;
}
if (_cnn._transactionLevel == 0 || _cnn._sql.AutoCommit == true)
{
_cnn._transactionLevel = 0; // Make sure the transaction level is reset before returning
- if (throwError == true) throw new SQLiteException(SQLiteErrorCode.Misuse, "No transaction is active on this connection");
+ if (throwError == true) throw new SQLiteException("No transaction is active on this connection");
else return false;
}
return true;
}
Index: System.Data.SQLite/System.Data.SQLite.Files.targets
==================================================================
--- System.Data.SQLite/System.Data.SQLite.Files.targets
+++ System.Data.SQLite/System.Data.SQLite.Files.targets
@@ -82,6 +82,18 @@
+
+
+
+
+
+
+
+
Index: System.Data.SQLite/System.Data.SQLite.Properties.targets
==================================================================
--- System.Data.SQLite/System.Data.SQLite.Properties.targets
+++ System.Data.SQLite/System.Data.SQLite.Properties.targets
@@ -75,10 +75,17 @@
-->
$(DefineConstants);COUNT_HANDLE
+
+
+ $(DefineConstants);TRACK_MEMORY_BYTES
+
+
@@ -128,25 +135,10 @@
-->
$(DefineConstants);PRELOAD_NATIVE_LIBRARY
-
-
- $(DefineConstants);INTEROP_EXTENSION_FUNCTIONS
-
-
-
-
- $(DefineConstants);INTEROP_TEST_EXTENSION
-
-
@@ -159,10 +151,18 @@
-->
$(DefineConstants);INTEROP_DEBUG
+
+
+ $(DefineConstants);INTEROP_EXTENSION_FUNCTIONS
+
+
@@ -175,10 +175,26 @@
-->
$(DefineConstants);INTEROP_LOG
+
+
+ $(DefineConstants);INTEROP_TEST_EXTENSION
+
+
+
+
+ $(DefineConstants);INTEROP_VIRTUAL_TABLE
+
+
Index: System.Data.SQLite/UnsafeNativeMethods.cs
==================================================================
--- System.Data.SQLite/UnsafeNativeMethods.cs
+++ System.Data.SQLite/UnsafeNativeMethods.cs
@@ -630,22 +630,22 @@
internal const string SQLITE_DLL = "SQLite.Interop.087.dll";
#elif SQLITE_STANDARD
//
// NOTE: Otherwise, if the standard SQLite library is enabled, use it.
//
- private const string SQLITE_DLL = "sqlite3";
+ internal const string SQLITE_DLL = "sqlite3";
#elif USE_INTEROP_DLL
- //
+ //
// NOTE: Otherwise, if the native SQLite interop assembly is enabled,
// use it.
//
- private const string SQLITE_DLL = "SQLite.Interop.dll";
+ internal const string SQLITE_DLL = "SQLite.Interop.dll";
#else
//
// NOTE: Finally, assume that the mixed-mode assembly is being used.
//
- private const string SQLITE_DLL = "System.Data.SQLite.dll";
+ internal const string SQLITE_DLL = "System.Data.SQLite.dll";
#endif
// This section uses interop calls that also fetch text length to optimize conversion.
// When using the standard dll, we can replace these calls with normal sqlite calls and
// do unoptimized conversions instead afterwards
@@ -705,10 +705,13 @@
internal static extern IntPtr sqlite3_value_text_interop(IntPtr p, out int len);
[DllImport(SQLITE_DLL)]
internal static extern IntPtr sqlite3_value_text16_interop(IntPtr p, out int len);
+ [DllImport(SQLITE_DLL)]
+ internal static extern int sqlite3_malloc_size_interop(IntPtr p);
+
#if INTEROP_LOG
[DllImport(SQLITE_DLL)]
internal static extern SQLiteErrorCode sqlite3_config_log_interop();
#endif
#endif
@@ -1058,13 +1061,10 @@
internal static extern void sqlite3_interrupt(IntPtr db);
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
internal static extern long sqlite3_last_insert_rowid(IntPtr db);
-#else
- [DllImport(SQLITE_DLL)]
- internal static extern void sqlite3_last_insert_rowid_interop(IntPtr db, ref long rowId);
#endif
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
@@ -1073,21 +1073,15 @@
internal static extern int sqlite3_changes(IntPtr db);
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
internal static extern long sqlite3_memory_used();
-#else
- [DllImport(SQLITE_DLL)]
- internal static extern void sqlite3_memory_used_interop(ref long bytes);
#endif
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
internal static extern long sqlite3_memory_highwater(int resetFlag);
-#else
- [DllImport(SQLITE_DLL)]
- internal static extern void sqlite3_memory_highwater_interop(int resetFlag, ref long bytes);
#endif
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
@@ -1110,13 +1104,10 @@
internal static extern SQLiteErrorCode sqlite3_bind_blob(IntPtr stmt, int index, Byte[] value, int nSize, IntPtr nTransient);
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
internal static extern SQLiteErrorCode sqlite3_bind_double(IntPtr stmt, int index, double value);
-#else
- [DllImport(SQLITE_DLL)]
- internal static extern SQLiteErrorCode sqlite3_bind_double_interop(IntPtr stmt, int index, ref double value);
#endif
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
@@ -1136,25 +1127,19 @@
internal static extern SQLiteErrorCode sqlite3_bind_uint(IntPtr stmt, int index, uint value);
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
internal static extern SQLiteErrorCode sqlite3_bind_int64(IntPtr stmt, int index, long value);
-#else
- [DllImport(SQLITE_DLL)]
- internal static extern SQLiteErrorCode sqlite3_bind_int64_interop(IntPtr stmt, int index, ref long value);
#endif
//
// NOTE: This really just calls "sqlite3_bind_int64"; however, it has the
// correct type signature for an unsigned long (64-bit) integer.
//
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, EntryPoint = "sqlite3_bind_int64", CallingConvention = CallingConvention.Cdecl)]
internal static extern SQLiteErrorCode sqlite3_bind_uint64(IntPtr stmt, int index, ulong value);
-#else
- [DllImport(SQLITE_DLL, EntryPoint = "sqlite3_bind_int64_interop")]
- internal static extern SQLiteErrorCode sqlite3_bind_uint64_interop(IntPtr stmt, int index, ref ulong value);
#endif
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
@@ -1198,13 +1183,10 @@
internal static extern SQLiteErrorCode sqlite3_step(IntPtr stmt);
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
internal static extern double sqlite3_column_double(IntPtr stmt, int index);
-#else
- [DllImport(SQLITE_DLL)]
- internal static extern void sqlite3_column_double_interop(IntPtr stmt, int index, out double value);
#endif
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
@@ -1213,13 +1195,10 @@
internal static extern int sqlite3_column_int(IntPtr stmt, int index);
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
internal static extern long sqlite3_column_int64(IntPtr stmt, int index);
-#else
- [DllImport(SQLITE_DLL)]
- internal static extern void sqlite3_column_int64_interop(IntPtr stmt, int index, out long value);
#endif
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
@@ -1284,13 +1263,10 @@
internal static extern int sqlite3_value_bytes16(IntPtr p);
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
internal static extern double sqlite3_value_double(IntPtr p);
-#else
- [DllImport(SQLITE_DLL)]
- internal static extern void sqlite3_value_double_interop(IntPtr p, out double value);
#endif
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
@@ -1299,13 +1275,10 @@
internal static extern int sqlite3_value_int(IntPtr p);
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
internal static extern long sqlite3_value_int64(IntPtr p);
-#else
- [DllImport(SQLITE_DLL)]
- internal static extern void sqlite3_value_int64_interop(IntPtr p, out Int64 value);
#endif
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
@@ -1321,13 +1294,10 @@
internal static extern void sqlite3_result_blob(IntPtr context, byte[] value, int nSize, IntPtr pvReserved);
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
internal static extern void sqlite3_result_double(IntPtr context, double value);
-#else
- [DllImport(SQLITE_DLL)]
- internal static extern void sqlite3_result_double_interop(IntPtr context, ref double value);
#endif
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
@@ -1336,20 +1306,52 @@
internal static extern void sqlite3_result_error(IntPtr context, byte[] strErr, int nLen);
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
+ [DllImport(SQLITE_DLL)]
+#endif
+ internal static extern void sqlite3_result_error_code(IntPtr context, SQLiteErrorCode value);
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
+#else
+ [DllImport(SQLITE_DLL)]
+#endif
+ internal static extern void sqlite3_result_error_toobig(IntPtr context);
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
+#else
+ [DllImport(SQLITE_DLL)]
+#endif
+ internal static extern void sqlite3_result_error_nomem(IntPtr context);
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
+#else
+ [DllImport(SQLITE_DLL)]
+#endif
+ internal static extern void sqlite3_result_value(IntPtr context, IntPtr value);
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
+#else
+ [DllImport(SQLITE_DLL)]
+#endif
+ internal static extern void sqlite3_result_zeroblob(IntPtr context, int nLen);
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
+#else
[DllImport(SQLITE_DLL)]
#endif
internal static extern void sqlite3_result_int(IntPtr context, int value);
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
internal static extern void sqlite3_result_int64(IntPtr context, long value);
-#else
- [DllImport(SQLITE_DLL)]
- internal static extern void sqlite3_result_int64_interop(IntPtr context, ref Int64 value);
#endif
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
@@ -1467,10 +1469,17 @@
internal static extern IntPtr sqlite3_db_handle(IntPtr stmt);
#if !PLATFORM_COMPACTFRAMEWORK
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
+ [DllImport(SQLITE_DLL)]
+#endif
+ internal static extern IntPtr sqlite3_db_filename(IntPtr db, IntPtr dbName);
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
+#else
[DllImport(SQLITE_DLL)]
#endif
internal static extern IntPtr sqlite3_next_stmt(IntPtr db, IntPtr stmt);
#if !PLATFORM_COMPACTFRAMEWORK
@@ -1557,10 +1566,486 @@
[DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
[DllImport(SQLITE_DLL)]
#endif
internal static extern int sqlite3_backup_pagecount(IntPtr backup);
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
+#else
+ [DllImport(SQLITE_DLL)]
+#endif
+ internal static extern SQLiteErrorCode sqlite3_declare_vtab(IntPtr db, IntPtr zSQL);
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
+#else
+ [DllImport(SQLITE_DLL)]
+#endif
+ internal static extern IntPtr sqlite3_mprintf(IntPtr format, __arglist);
+ #endregion
+
+ // SQLite API calls that are provided by "well-known" extensions that may be statically
+ // linked with the SQLite core native library currently in use.
+ #region extension sqlite api calls
+#if INTEROP_VIRTUAL_TABLE
+#if !PLATFORM_COMPACTFRAMEWORK
+ [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
+#else
+ [DllImport(SQLITE_DLL)]
+#endif
+ internal static extern IntPtr sqlite3_create_disposable_module(IntPtr db, IntPtr name, ref sqlite3_module module, IntPtr pClientData, xDestroyModule xDestroy);
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
+#else
+ [DllImport(SQLITE_DLL)]
+#endif
+ internal static extern void sqlite3_dispose_module(ref sqlite3_module pModule);
+#endif
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region sqlite interop api calls (.NET Compact Framework only)
+#if PLATFORM_COMPACTFRAMEWORK && !SQLITE_STANDARD
+ [DllImport(SQLITE_DLL)]
+ internal static extern void sqlite3_last_insert_rowid_interop(IntPtr db, ref long rowId);
+
+ [DllImport(SQLITE_DLL)]
+ internal static extern void sqlite3_memory_used_interop(ref long bytes);
+
+ [DllImport(SQLITE_DLL)]
+ internal static extern void sqlite3_memory_highwater_interop(int resetFlag, ref long bytes);
+
+ [DllImport(SQLITE_DLL)]
+ internal static extern SQLiteErrorCode sqlite3_bind_double_interop(IntPtr stmt, int index, ref double value);
+
+ [DllImport(SQLITE_DLL)]
+ internal static extern SQLiteErrorCode sqlite3_bind_int64_interop(IntPtr stmt, int index, ref long value);
+
+ [DllImport(SQLITE_DLL, EntryPoint = "sqlite3_bind_int64_interop")]
+ internal static extern SQLiteErrorCode sqlite3_bind_uint64_interop(IntPtr stmt, int index, ref ulong value);
+
+ [DllImport(SQLITE_DLL)]
+ internal static extern void sqlite3_column_double_interop(IntPtr stmt, int index, out double value);
+
+ [DllImport(SQLITE_DLL)]
+ internal static extern void sqlite3_column_int64_interop(IntPtr stmt, int index, out long value);
+
+ [DllImport(SQLITE_DLL)]
+ internal static extern void sqlite3_value_double_interop(IntPtr p, out double value);
+
+ [DllImport(SQLITE_DLL)]
+ internal static extern void sqlite3_value_int64_interop(IntPtr p, out Int64 value);
+
+ [DllImport(SQLITE_DLL)]
+ internal static extern void sqlite3_result_double_interop(IntPtr context, ref double value);
+
+ [DllImport(SQLITE_DLL)]
+ internal static extern void sqlite3_result_int64_interop(IntPtr context, ref Int64 value);
+
+ [DllImport(SQLITE_DLL)]
+ internal static extern IntPtr sqlite3_create_disposable_module_interop(
+ IntPtr db, IntPtr name, IntPtr pModule, int iVersion, xCreate xCreate,
+ xConnect xConnect, xBestIndex xBestIndex, xDisconnect xDisconnect,
+ xDestroy xDestroy, xOpen xOpen, xClose xClose, xFilter xFilter,
+ xNext xNext, xEof xEof, xColumn xColumn, xRowId xRowId, xUpdate xUpdate,
+ xBegin xBegin, xSync xSync, xCommit xCommit, xRollback xRollback,
+ xFindFunction xFindFunction, xRename xRename, xSavepoint xSavepoint,
+ xRelease xRelease, xRollbackTo xRollbackTo, IntPtr pClientData,
+ xDestroyModule xDestroyModule);
+
+ [DllImport(SQLITE_DLL)]
+ internal static extern void sqlite3_dispose_module_interop(IntPtr pModule);
+#endif
+ // PLATFORM_COMPACTFRAMEWORK && !SQLITE_STANDARD
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region Native Delegates
+#if INTEROP_VIRTUAL_TABLE
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xCreate(
+ IntPtr pDb,
+ IntPtr pAux,
+ int argc,
+ IntPtr argv,
+ ref IntPtr pVtab,
+ ref IntPtr pError
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xConnect(
+ IntPtr pDb,
+ IntPtr pAux,
+ int argc,
+ IntPtr argv,
+ ref IntPtr pVtab,
+ ref IntPtr pError
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xBestIndex(
+ IntPtr pVtab,
+ IntPtr pIndex
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xDisconnect(
+ IntPtr pVtab
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xDestroy(
+ IntPtr pVtab
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xOpen(
+ IntPtr pVtab,
+ ref IntPtr pCursor
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xClose(
+ IntPtr pCursor
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xFilter(
+ IntPtr pCursor,
+ int idxNum,
+ IntPtr idxStr,
+ int argc,
+ IntPtr argv
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xNext(
+ IntPtr pCursor
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate int xEof(
+ IntPtr pCursor
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xColumn(
+ IntPtr pCursor,
+ IntPtr pContext,
+ int index
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xRowId(
+ IntPtr pCursor,
+ ref long rowId
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xUpdate(
+ IntPtr pVtab,
+ int argc,
+ IntPtr argv,
+ ref long rowId
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xBegin(
+ IntPtr pVtab
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xSync(
+ IntPtr pVtab
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xCommit(
+ IntPtr pVtab
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xRollback(
+ IntPtr pVtab
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate int xFindFunction(
+ IntPtr pVtab,
+ int nArg,
+ IntPtr zName,
+ ref SQLiteCallback callback,
+ ref IntPtr pUserData
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xRename(
+ IntPtr pVtab,
+ IntPtr zNew
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xSavepoint(
+ IntPtr pVtab,
+ int iSavepoint
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xRelease(
+ IntPtr pVtab,
+ int iSavepoint
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate SQLiteErrorCode xRollbackTo(
+ IntPtr pVtab,
+ int iSavepoint
+ );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+#endif
+ public delegate void xDestroyModule(IntPtr pClientData);
+#endif
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ #region Native Structures
+#if INTEROP_VIRTUAL_TABLE
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct sqlite3_module
+ {
+ public int iVersion;
+ public xCreate xCreate;
+ public xConnect xConnect;
+ public xBestIndex xBestIndex;
+ public xDisconnect xDisconnect;
+ public xDestroy xDestroy;
+ public xOpen xOpen;
+ public xClose xClose;
+ public xFilter xFilter;
+ public xNext xNext;
+ public xEof xEof;
+ public xColumn xColumn;
+ public xRowId xRowId;
+ public xUpdate xUpdate;
+ public xBegin xBegin;
+ public xSync xSync;
+ public xCommit xCommit;
+ public xRollback xRollback;
+ public xFindFunction xFindFunction;
+ public xRename xRename;
+ /* The methods above are in version 1 of the sqlite3_module
+ * object. Those below are for version 2 and greater. */
+ public xSavepoint xSavepoint;
+ public xRelease xRelease;
+ public xRollbackTo xRollbackTo;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct sqlite3_vtab
+ {
+ public IntPtr pModule;
+ public int nRef; /* NO LONGER USED */
+ public IntPtr zErrMsg;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct sqlite3_vtab_cursor
+ {
+ public IntPtr pVTab;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct sqlite3_index_constraint
+ {
+ public sqlite3_index_constraint(
+ SQLiteIndexConstraint constraint
+ )
+ : this()
+ {
+ if (constraint != null)
+ {
+ iColumn = constraint.iColumn;
+ op = constraint.op;
+ usable = constraint.usable;
+ iTermOffset = constraint.iTermOffset;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ public int iColumn;
+ public SQLiteIndexConstraintOp op;
+ public byte usable;
+ public int iTermOffset;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct sqlite3_index_orderby
+ {
+ public sqlite3_index_orderby(
+ SQLiteIndexOrderBy orderBy
+ )
+ : this()
+ {
+ if (orderBy != null)
+ {
+ iColumn = orderBy.iColumn;
+ desc = orderBy.desc;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ public int iColumn; /* Column number */
+ public byte desc; /* True for DESC. False for ASC. */
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct sqlite3_index_constraint_usage
+ {
+ public sqlite3_index_constraint_usage(
+ SQLiteIndexConstraintUsage constraintUsage
+ )
+ : this()
+ {
+ if (constraintUsage != null)
+ {
+ argvIndex = constraintUsage.argvIndex;
+ omit = constraintUsage.omit;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ public int argvIndex; /* if >0, constraint is part of argv to xFilter */
+ public byte omit; /* Do not code a test for this constraint */
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct sqlite3_index_info
+ {
+ /* Inputs */
+ public int nConstraint; /* Number of entries in aConstraint */
+ public IntPtr aConstraint;
+ public int nOrderBy;
+ public IntPtr aOrderBy;
+ /* Outputs */
+ public IntPtr aConstraintUsage;
+ public int idxNum; /* Number used to identify the index */
+ public string idxStr; /* String, possibly obtained from sqlite3_malloc */
+ public int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */
+ public int orderByConsumed; /* True if output is already ordered */
+ public double estimatedCost; /* Estimated cost of using this index */
+ }
+#endif
#endregion
}
#if PLATFORM_COMPACTFRAMEWORK
internal abstract class CriticalHandle : IDisposable
@@ -1655,10 +2140,14 @@
internal readonly object syncRoot = new object();
#endif
///////////////////////////////////////////////////////////////////////
+ private bool ownHandle;
+
+ ///////////////////////////////////////////////////////////////////////
+
public static implicit operator IntPtr(SQLiteConnectionHandle db)
{
if (db != null)
{
#if PLATFORM_COMPACTFRAMEWORK
@@ -1671,36 +2160,44 @@
return IntPtr.Zero;
}
///////////////////////////////////////////////////////////////////////
- internal SQLiteConnectionHandle(IntPtr db)
- : this()
+ internal SQLiteConnectionHandle(IntPtr db, bool ownHandle)
+ : this(ownHandle)
{
#if PLATFORM_COMPACTFRAMEWORK
lock (syncRoot)
#endif
{
+ this.ownHandle = ownHandle;
SetHandle(db);
}
}
///////////////////////////////////////////////////////////////////////
- private SQLiteConnectionHandle()
+ private SQLiteConnectionHandle(bool ownHandle)
: base(IntPtr.Zero)
{
#if COUNT_HANDLE
- Interlocked.Increment(
- ref UnsafeNativeMethods.connectionCount);
+ if (ownHandle)
+ Interlocked.Increment(ref UnsafeNativeMethods.connectionCount);
#endif
}
///////////////////////////////////////////////////////////////////////
protected override bool ReleaseHandle()
{
+#if PLATFORM_COMPACTFRAMEWORK
+ lock (syncRoot)
+#endif
+ {
+ if (!ownHandle) return true;
+ }
+
try
{
#if !PLATFORM_COMPACTFRAMEWORK
IntPtr localHandle = Interlocked.Exchange(
ref handle, IntPtr.Zero);
@@ -1782,10 +2279,25 @@
{
return Interlocked.Decrement(
ref UnsafeNativeMethods.connectionCount);
}
#endif
+
+ ///////////////////////////////////////////////////////////////////////
+
+ public bool OwnHandle
+ {
+ get
+ {
+#if PLATFORM_COMPACTFRAMEWORK
+ lock (syncRoot)
+#endif
+ {
+ return ownHandle;
+ }
+ }
+ }
///////////////////////////////////////////////////////////////////////
public override bool IsInvalid
{
Index: Tests/basic.eagle
==================================================================
--- Tests/basic.eagle
+++ Tests/basic.eagle
@@ -76,20 +76,30 @@
#
testClrExec $testExeFile [list -eventflags Wait -directory \
[file dirname $testExeFile] -stdout output -success 0] -autoRun \
-fileName [appendArgs \" [file nativename $fileName] \"]
} error]
+
+ set successCount [regexp -all -- {\tSucceeded\t} $output]
+ set failureCount [regexp -all -- {\tFailed\t} $output]
+ set totalCount [expr {$successCount + $failureCount}]
+
+ tputs $test_channel [appendArgs \
+ "---- found and executed " $totalCount " unit tests from \"" \
+ $testExeFile "\", " $successCount " passed, " $failureCount \
+ " failed\n"]
tlog "---- BEGIN STDOUT OUTPUT\n"
tlog $output
tlog "\n---- END STDOUT OUTPUT\n"
list $code [expr {$code == 0 ? "" : $error}]
} -cleanup {
cleanupFile $fileName
- unset -nocomplain code output error fileName
+ unset -nocomplain totalCount failureCount successCount code output \
+ error fileName
} -constraints {eagle SQLite file_System.Data.SQLite.dll file_test.exe} \
-result {0 {}}}
###############################################################################
@@ -1472,15 +1482,20 @@
# NOTE: Make sure that SQLite core library is completely shutdown prior to
# starting this test.
#
shutdownSQLite $test_channel
+ #
+ # NOTE: Create an IntPtr instance with a value of zero.
+ #
+ set zero [object invoke -create IntPtr Zero]
+
#
# NOTE: Create an instance of the core SQLite library interop wrapper class.
#
set sqlite3 [object create -flags +NonPublic System.Data.SQLite.SQLite3 \
- Default Unspecified null]
+ Default Unspecified null $zero null true]
} -body {
set result(rc1) [object invoke -flags +NonPublic $sqlite3 SetMemoryStatus \
false]
set result(before) [object invoke -flags +NonPublic $sqlite3 MemoryUsed]
@@ -1540,11 +1555,11 @@
#
object invoke -flags +NonPublic System.Data.SQLite.UnsafeNativeMethods \
sqlite3_config_int SQLITE_CONFIG_MEMSTATUS 1
}
- unset -nocomplain result sqlite3
+ unset -nocomplain result sqlite3 zero
} -constraints \
{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -match \
regexp -result {^Ok Misuse Ok Ok System#IntPtr#\d+ System#IntPtr#\d+ \d+ \d+\
\d+ \d+ \d+ True True True True True True$}}
Index: Tests/common.eagle
==================================================================
--- Tests/common.eagle
+++ Tests/common.eagle
@@ -1475,10 +1475,51 @@
proc reportSQLiteResources { channel {quiet false} {collect true} } {
#
# NOTE: Skip all output if we are running in "quiet" mode.
#
+ if {[haveConstraint \
+ defineConstant.System.Data.SQLite.INTEROP_VIRTUAL_TABLE] && \
+ [haveConstraint \
+ defineConstant.System.Data.SQLite.TRACK_MEMORY_BYTES]} then {
+ if {!$quiet} then {
+ tputs $channel "---- current memory in use by SQLiteMemory... "
+ }
+
+ if {[catch {object invoke -flags +NonPublic \
+ System.Data.SQLite.SQLiteMemory \
+ bytesAllocated} memory] == 0} then {
+ if {!$quiet} then {
+ tputs $channel [appendArgs $memory " bytes\n"]
+ }
+ } else {
+ set memory unknown
+
+ if {!$quiet} then {
+ tputs $channel [appendArgs $memory \n]
+ }
+ }
+
+ if {!$quiet} then {
+ tputs $channel "---- maximum memory in use by SQLiteMemory... "
+ }
+
+ if {[catch {object invoke -flags +NonPublic \
+ System.Data.SQLite.SQLiteMemory \
+ maximumBytesAllocated} memory] == 0} then {
+ if {!$quiet} then {
+ tputs $channel [appendArgs $memory " bytes\n"]
+ }
+ } else {
+ set memory unknown
+
+ if {!$quiet} then {
+ tputs $channel [appendArgs $memory \n]
+ }
+ }
+ }
+
if {!$quiet} then {
tputs $channel "---- current memory in use by SQLite... "
}
if {[catch {object invoke -flags +NonPublic \
@@ -1910,14 +1951,15 @@
# assembly if it was enabled for the managed assembly.
#
foreach defineConstant [list \
CHECK_STATE COUNT_HANDLE DEBUG INTEROP_CODEC INTEROP_DEBUG \
INTEROP_EXTENSION_FUNCTIONS INTEROP_LEGACY_CLOSE INTEROP_LOG \
- INTEROP_TEST_EXTENSION NET_20 NET_35 NET_40 NET_45 NET_COMPACT_20 \
- PLATFORM_COMPACTFRAMEWORK PRELOAD_NATIVE_LIBRARY RETARGETABLE \
- SQLITE_STANDARD THROW_ON_DISPOSED TRACE TRACE_CONNECTION \
- TRACE_HANDLE TRACE_PRELOAD TRACE_STATEMENT TRACE_WARNING \
+ INTEROP_TEST_EXTENSION INTEROP_VIRTUAL_TABLE NET_20 NET_35 \
+ NET_40 NET_45 NET_COMPACT_20 PLATFORM_COMPACTFRAMEWORK \
+ PRELOAD_NATIVE_LIBRARY RETARGETABLE SQLITE_STANDARD \
+ THROW_ON_DISPOSED TRACE TRACE_CONNECTION TRACE_HANDLE \
+ TRACE_PRELOAD TRACE_STATEMENT TRACE_WARNING TRACK_MEMORY_BYTES \
USE_INTEROP_DLL USE_PREPARE_V2 WINDOWS] {
#
# NOTE: Check if the compile-time option is listed in the list of
# "define constants" kept track of by the managed assembly.
#
ADDED Tests/vtab.eagle
Index: Tests/vtab.eagle
==================================================================
--- /dev/null
+++ Tests/vtab.eagle
@@ -0,0 +1,219 @@
+###############################################################################
+#
+# vtab.eagle --
+#
+# Written by Joe Mistachkin.
+# Released to the public domain, use at your own risk!
+#
+###############################################################################
+
+package require Eagle
+package require Eagle.Library
+package require Eagle.Test
+
+runTestPrologue
+
+###############################################################################
+
+package require System.Data.SQLite.Test
+runSQLiteTestPrologue
+
+###############################################################################
+
+runTest {test vtab-1.1 {virtual table support} -setup {
+ setupDb [set fileName vtab-1.1.db]
+} -body {
+ set id [object invoke Interpreter.GetActive NextId]
+ set dataSource [file join [getDatabaseDirectory] $fileName]
+
+ set sql { \
+ CREATE VIRTUAL TABLE t${id} USING mod${id}; \
+ }
+
+ unset -nocomplain results errors
+
+ set code [compileCSharpWith [subst {
+ using System;
+ using System.Data.SQLite;
+
+ namespace _Dynamic${id}
+ {
+ public sealed class SQLiteModuleTest${id} : SQLiteModuleNoop
+ {
+ public SQLiteModuleTest${id}(string name)
+ : base(name)
+ {
+ // do nothing.
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ public override SQLiteErrorCode Create(
+ SQLiteConnection connection,
+ IntPtr pClientData,
+ string\[\] arguments,
+ ref SQLiteVirtualTable table,
+ ref string error
+ )
+ {
+ SQLiteErrorCode rc = DeclareTable(
+ connection, "CREATE TABLE ignored(x);", ref error);
+
+ if (rc != SQLiteErrorCode.Ok)
+ return rc;
+
+ table = new SQLiteVirtualTable(arguments);
+ return SQLiteErrorCode.Ok;
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+
+ public static class Test${id}
+ {
+ public static void Main()
+ {
+ using (SQLiteConnection connection = new SQLiteConnection(
+ "Data Source=${dataSource};"))
+ {
+ connection.Open();
+ connection.CreateModule(new SQLiteModuleTest${id}("mod${id}"));
+
+ using (SQLiteCommand command = connection.CreateCommand())
+ {
+ command.CommandText = "[subst ${sql}]";
+ command.ExecuteNonQuery();
+ }
+
+ connection.Close();
+ }
+ }
+ }
+ }
+ }] true true true results errors System.Data.SQLite.dll]
+
+ list $code $results \
+ [expr {[info exists errors] ? $errors : ""}] \
+ [expr {$code eq "Ok" ? [catch {
+ object invoke _Dynamic${id}.Test${id} Main
+ } result] : [set result ""]}] $result
+} -cleanup {
+ cleanupDb $fileName
+
+ unset -nocomplain result code results errors sql dataSource id db fileName
+} -constraints \
+{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\
+defineConstant.System.Data.SQLite.INTEROP_VIRTUAL_TABLE} -match regexp -result \
+{^Ok System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 \{\}$}}
+
+###############################################################################
+
+runTest {test vtab-1.2 {IEnumerable virtual table} -setup {
+ setupDb [set fileName vtab-1.2.db]
+} -body {
+ set id [object invoke Interpreter.GetActive NextId]
+ set dataSource [file join [getDatabaseDirectory] $fileName]
+
+ set sql(1) { \
+ CREATE VIRTUAL TABLE t${id} USING mod${id}; \
+ }
+
+ set sql(2) { \
+ SELECT * FROM t${id}; \
+ }
+
+ set sql(3) { \
+ UPDATE t${id} SET x = 1; \
+ }
+
+ unset -nocomplain results errors
+
+ set code [compileCSharpWith [subst {
+ using System;
+ using System.Data.SQLite;
+ using Eagle._Containers.Public;
+
+ namespace _Dynamic${id}
+ {
+ public static class Test${id}
+ {
+ public static StringList GetList(params string\[\] strings)
+ {
+ StringList result = new StringList();
+
+ using (SQLiteConnection connection = new SQLiteConnection(
+ "Data Source=${dataSource};"))
+ {
+ connection.Open();
+
+ connection.CreateModule(new SQLiteModuleEnumerable(
+ "mod${id}", strings));
+
+ using (SQLiteCommand command = connection.CreateCommand())
+ {
+ command.CommandText = "[subst ${sql(1)}]";
+ command.ExecuteNonQuery();
+ }
+
+ using (SQLiteCommand command = connection.CreateCommand())
+ {
+ command.CommandText = "[subst ${sql(2)}]";
+
+ using (SQLiteDataReader dataReader = command.ExecuteReader())
+ {
+ while (dataReader.Read())
+ result.Add(dataReader\[0\].ToString());
+ }
+ }
+
+ using (SQLiteCommand command = connection.CreateCommand())
+ {
+ command.CommandText = "[subst ${sql(3)}]";
+
+ try
+ {
+ command.ExecuteNonQuery();
+ }
+ catch (SQLiteException e)
+ {
+ result.Add(e.ReturnCode.ToString());
+ result.Add(e.Message);
+ }
+ }
+
+ connection.Close();
+ }
+
+ return result;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ public static void Main()
+ {
+ // do nothing.
+ }
+ }
+ }
+ }] true true true results errors [list System.Data.SQLite.dll Eagle.dll]]
+
+ list $code $results \
+ [expr {[info exists errors] ? $errors : ""}] \
+ [expr {$code eq "Ok" ? [catch {
+ object invoke _Dynamic${id}.Test${id} GetList one two three 4 5.0
+ } result] : [set result ""]}] $result
+} -cleanup {
+ cleanupDb $fileName
+
+ unset -nocomplain result code results errors sql dataSource id db fileName
+} -constraints \
+{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\
+defineConstant.System.Data.SQLite.INTEROP_VIRTUAL_TABLE} -match regexp -result \
+[string map [list \n \r\n] {^Ok System#CodeDom#Compiler#CompilerResults#\d+\
+\{\} 0 \{one two three 4 5.0 Error \{SQL logic error or missing database
+virtual table "t\d+" is read-only\}\}$}]}
+
+###############################################################################
+
+runSQLiteTestEpilogue
+runTestEpilogue
Index: readme.htm
==================================================================
--- readme.htm
+++ readme.htm
@@ -188,10 +188,11 @@
1.0.87.0 - June XX, 2013 (release scheduled)
+ - Add all the necessary infrastructure to allow virtual tables to be implemented in managed code. Fix for [9a544991be].
- The DbType to type name translation needs to prioritize the Entity Framework type names. Fix for [47f4bac575].
- Add DateTimeFormatString connection string property to allow the DateTime format string used for all parsing and formatting to be overridden.
- Disable use of the new connection string parsing algorithm when the No_SQLiteConnectionNewParser environment variable is set. Pursuant to [bbdda6eae2].
Index: test/TestCases.cs
==================================================================
--- test/TestCases.cs
+++ test/TestCases.cs
@@ -1224,14 +1224,17 @@
}
[Test]
internal void ConnectionStringBuilder()
{
- DbConnectionStringBuilder builder = _fact.CreateConnectionStringBuilder();
- if (builder is SQLiteConnectionStringBuilder)
+ if (_fact.GetType().Name.IndexOf("SQLite", StringComparison.OrdinalIgnoreCase) > -1)
{
- bool pool = ((SQLiteConnectionStringBuilder)builder).Pooling;
+ DbConnectionStringBuilder builder = _fact.CreateConnectionStringBuilder();
+ if (builder is SQLiteConnectionStringBuilder)
+ {
+ bool pool = ((SQLiteConnectionStringBuilder)builder).Pooling;
+ }
}
}
[Test]
internal void LeakyCommands()
Index: testce/TestCases.cs
==================================================================
--- testce/TestCases.cs
+++ testce/TestCases.cs
@@ -217,10 +217,14 @@
total++;
try { Int64Properties(cnn); frm.WriteLine("SUCCESS - Int64Properties"); passed++; }
catch (Exception) { frm.WriteLine("FAIL - Int64Properties"); failed++; }
+ total++;
+ try { ManagedVirtualTable(cnn); frm.WriteLine("SUCCESS - ManagedVirtualTable"); passed++; }
+ catch (Exception) { frm.WriteLine("FAIL - ManagedVirtualTable"); failed++; }
+
total++;
try { MultipleThreadStress(cnn); frm.WriteLine("SUCCESS - MultipleThreadStress"); passed++; }
catch (Exception) { frm.WriteLine("FAIL - MultipleThreadStress"); failed++; }
total++;
@@ -943,10 +947,71 @@
cnn2.MemoryHighwater
})
{
// do nothing.
}
+
+ return;
+ }
+
+ throw new NotSupportedException("not a SQLite connection");
+ }
+
+ // Make sure that managed virtual table support works on the .NET Compact Framework.
+ internal void ManagedVirtualTable(DbConnection cnn)
+ {
+ SQLiteConnection cnn2 = cnn as SQLiteConnection;
+
+ if (cnn2 != null)
+ {
+ string[] result = new string[5];
+
+ cnn2.CreateModule(new SQLiteModuleEnumerable("enumMod", new string[] {
+ "one", "two", "three", "4", "5.0"
+ }));
+
+ using (SQLiteCommand command = cnn2.CreateCommand())
+ {
+ command.CommandText = "CREATE VIRTUAL TABLE enumTab USING enumMod;";
+ command.ExecuteNonQuery();
+ }
+
+ using (SQLiteCommand command = cnn2.CreateCommand())
+ {
+ command.CommandText = "SELECT * FROM enumTab;";
+
+ using (SQLiteDataReader dataReader = command.ExecuteReader())
+ {
+ int index = 0;
+
+ while (dataReader.Read())
+ result[index++] = dataReader[0].ToString();
+
+ if (result[0] != "one") throw new ArgumentException("one");
+ if (result[1] != "two") throw new ArgumentException("two");
+ if (result[2] != "three") throw new ArgumentException("three");
+ if (result[3] != "4") throw new ArgumentException("4");
+ if (result[4] != "5.0") throw new ArgumentException("5.0");
+ }
+ }
+
+ using (SQLiteCommand command = cnn2.CreateCommand())
+ {
+ command.CommandText = "UPDATE enumTab SET x = 1;";
+
+ try
+ {
+ command.ExecuteNonQuery();
+
+ throw new InvalidOperationException(
+ "UPDATE should throw exception");
+ }
+ catch (SQLiteException)
+ {
+ // do nothing.
+ }
+ }
return;
}
throw new NotSupportedException("not a SQLite connection");
Index: www/news.wiki
==================================================================
--- www/news.wiki
+++ www/news.wiki
@@ -4,10 +4,11 @@
1.0.87.0 - June XX, 2013 (release scheduled)
+ - Add all the necessary infrastructure to allow virtual tables to be implemented in managed code. Fix for [9a544991be].
- The DbType to type name translation needs to prioritize the Entity Framework type names. Fix for [47f4bac575].
- Add DateTimeFormatString connection string property to allow the DateTime format string used for all parsing and formatting to be overridden.
- Disable use of the new connection string parsing algorithm when the No_SQLiteConnectionNewParser environment variable is set. Pursuant to [bbdda6eae2].