Version History
-
1.0.94.0 - August XX, 2014 (release scheduled)
+
1.0.94.0 - September XX, 2014 (release scheduled)
+ - Updated to SQLite 3.8.6.
- Updated to Entity Framework 6.1.1.
- Add RefreshFlags method to the SQLiteDataReader class to forcibly refresh its connection flags.
- Improve automatic detection and handling of the Entity Framework 6 assembly by the design-time components installer. Pursuant to [e634e330a6]. ** Potentially Incompatible Change **
- Improve SQLiteDataReader performance slightly by caching the connection flags. ** Potentially Incompatible Change **
+ - Add ClearCachedSettings method to the SQLiteConnection class.
+ - Add NoConvertSettings connection flag to disable querying of runtime configuration settings from within the SQLiteConvert class. Pursuant to [58ed318f2f].
- Minimize usage of the "Use_SQLiteConvert_DefaultDbType" and "Use_SQLiteConvert_DefaultTypeName" settings. Fix for [58ed318f2f]. ** Potentially Incompatible Change **
1.0.93.0 - June 23, 2014
- Updated to SQLite 3.8.5.
@@ -1077,11 +1080,11 @@
- Added SQLiteMetaDataCollectionNames class.
1.0.24.6 beta - January 23, 2006
- This beta is built from sqlite.org's 3.3.2 beta.
- Eliminated the static linking of mscoree from all binaries. Native projects
- can now use the library without any dependencies on the .NET framework, while managed
+ can now use the library without any dependencies on the .NET Framework, while managed
projects continue to be able to use the library normally.
1.0.24.5 beta - January 20, 2006
- This beta is built from sqlite.org's 3.3.1 alpha and contains development-in-progress code. Therefore no guarantees
can be made regarding its suitability for production use.
Index: Externals/Eagle/bin/Eagle.dll
==================================================================
--- Externals/Eagle/bin/Eagle.dll
+++ Externals/Eagle/bin/Eagle.dll
cannot compute difference between binary files
Index: Externals/Eagle/bin/EagleShell.exe
==================================================================
--- Externals/Eagle/bin/EagleShell.exe
+++ Externals/Eagle/bin/EagleShell.exe
cannot compute difference between binary files
Index: Externals/Eagle/bin/EagleShell32.exe
==================================================================
--- Externals/Eagle/bin/EagleShell32.exe
+++ Externals/Eagle/bin/EagleShell32.exe
cannot compute difference between binary files
Index: Externals/Eagle/bin/x64/Spilornis.dll
==================================================================
--- Externals/Eagle/bin/x64/Spilornis.dll
+++ Externals/Eagle/bin/x64/Spilornis.dll
cannot compute difference between binary files
Index: Externals/Eagle/bin/x86/Spilornis.dll
==================================================================
--- Externals/Eagle/bin/x86/Spilornis.dll
+++ Externals/Eagle/bin/x86/Spilornis.dll
cannot compute difference between binary files
Index: Externals/Eagle/lib/Eagle1.0/init.eagle
==================================================================
--- Externals/Eagle/lib/Eagle1.0/init.eagle
+++ Externals/Eagle/lib/Eagle1.0/init.eagle
@@ -101,10 +101,27 @@
#
proc isMono {} {
return [expr {[info exists ::eagle_platform(runtime)] && \
[string compare -nocase mono $::eagle_platform(runtime)] == 0}]
}
+
+ #
+ # NOTE: This procedure returns non-zero if the specified file names refer
+ # to the same file, using the most robust method available for the
+ # script engine and platform.
+ #
+ proc isSameFileName { fileName1 fileName2 } {
+ if {[isEagle]} then {
+ return [file same $fileName1 $fileName2]
+ } else {
+ if {[isWindows]} then {
+ return [string equal -nocase $fileName1 $fileName2]
+ } else {
+ return [string equal $fileName1 $fileName2]
+ }
+ }
+ }
proc getEnvironmentVariable { name } {
#
# NOTE: This should work properly in both Tcl and Eagle.
#
@@ -916,22 +933,51 @@
#
set platformOptions [expr { \
[info exists ::eagle_platform(compileOptions)] ? \
$::eagle_platform(compileOptions) : [list]}]
- if {[llength $platformOptions] > 0} then {
+ #
+ # NOTE: Permit extra C# compiler options to be passed via the global
+ # array element "csharpOptions", if it exists.
+ #
+ set csharpOptions [expr { \
+ [info exists ::eagle_platform(csharpOptions)] ? \
+ $::eagle_platform(csharpOptions) : [list]}]
+
+ if {[llength $platformOptions] > 0 || \
+ [llength $csharpOptions] > 0} then {
#
# NOTE: Grab the existing compiler options, if any.
#
set compilerOptions [$parameters CompilerOptions]
if {"DEBUG" in $platformOptions} then {
- append compilerOptions " /define:DEBUG"
+ if {[string length $compilerOptions] > 0} then {
+ append compilerOptions " "
+ }
+
+ append compilerOptions /define:DEBUG
}
if {"TRACE" in $platformOptions} then {
- append compilerOptions " /define:TRACE"
+ if {[string length $compilerOptions] > 0} then {
+ append compilerOptions " "
+ }
+
+ append compilerOptions /define:TRACE
+ }
+
+ #
+ # NOTE: Append the configured extra C# compiler options configured
+ # via the global array element "csharpOptions", if any.
+ #
+ foreach csharpOption $csharpOptions {
+ if {[string length $compilerOptions] > 0} then {
+ append compilerOptions " "
+ }
+
+ append compilerOptions $csharpOption
}
#
# NOTE: Reset the compiler options to the pre-existing ones plus the
# extra defines we may have added (above).
@@ -1812,25 +1858,26 @@
if {$length > $maxLength} {
set maxLength $length
}
}
+ set stringMap [list \b " " \t " " \r \xB6 \n \xB6]
set maxLength [expr {$maxLength + [string length $a] + 2}]
set hostLength [lindex [getHostSize] 0]
set valueLength [expr {$hostLength - $maxLength - 5}]; # " ... "
foreach name $names {
#
# NOTE: Format the array element name for display.
#
- set nameString [appendArgs $a ( $name )]
+ set nameString [string map $stringMap [appendArgs $a ( $name )]]
#
# NOTE: If the value by itself is too long to fit on one host line,
# just truncate and ellipsis it.
#
- set valueString $array($name)
+ set valueString [string map $stringMap $array($name)]
if {[string length $valueString] > $valueLength} then {
set valueString [appendArgs [string range $valueString 0 \
[expr {$valueLength - 4}]] " ..."]
}
@@ -1966,11 +2013,11 @@
proc findDirectories { pattern } {
#
# NOTE: Block non-Windows platforms since this is Windows specific.
#
- if {$::tcl_platform(platform) ne "windows"} then {
+ if {![isWindows]} then {
error "not supported on this operating system"
}
#
# NOTE: This should work properly in Eagle only.
@@ -2014,11 +2061,11 @@
proc findFiles { pattern } {
#
# NOTE: Block non-Windows platforms since this is Windows specific.
#
- if {$::tcl_platform(platform) ne "windows"} then {
+ if {![isWindows]} then {
error "not supported on this operating system"
}
#
# NOTE: This should work properly in Eagle only.
@@ -2062,11 +2109,11 @@
proc findFilesRecursive { pattern } {
#
# NOTE: Block non-Windows platforms since this is Windows specific.
#
- if {$::tcl_platform(platform) ne "windows"} then {
+ if {![isWindows]} then {
error "not supported on this operating system"
}
#
# NOTE: This should work properly in Eagle only.
@@ -2169,11 +2216,11 @@
proc findFilesRecursive { pattern } {
#
# NOTE: Block non-Windows platforms since this is Windows specific.
#
- if {$::tcl_platform(platform) ne "windows"} then {
+ if {![isWindows]} then {
error "not supported on this operating system"
}
#
# NOTE: This should work properly in Tcl only.
@@ -2260,11 +2307,11 @@
#
# NOTE: Exports the necessary commands from this package and import them
# into the global namespace.
#
exportAndImportPackageCommands [namespace current] [list \
- isEagle isWindows haveGaruda isTclThread isMono \
+ isEagle isWindows haveGaruda isTclThread isMono isSameFileName \
getEnvironmentVariable combineFlags getCompileInfo getPlatformInfo \
getPluginPath appendArgs lappendArgs getDictionaryValue \
getColumnValue getRowColumnValue tqputs tqlog readFile \
readSharedFile writeFile appendFile appendLogFile appendSharedFile \
appendSharedLogFile readAsciiFile writeAsciiFile readUnicodeFile \
Index: Externals/Eagle/lib/Eagle1.0/test.eagle
==================================================================
--- Externals/Eagle/lib/Eagle1.0/test.eagle
+++ Externals/Eagle/lib/Eagle1.0/test.eagle
@@ -485,31 +485,70 @@
# TODO: Add more support for standard tcltest options here.
#
set options [list \
-breakOnLeak -configuration -constraints -exitOnComplete -file \
-logFile -machine -match -no -notFile -platform -postTest -preTest \
- -randomOrder -skip -startFile -stopFile -stopOnFailure -suffix \
- -suite -tclsh -threshold]
+ -randomOrder -skip -startFile -stopFile -stopOnFailure -stopOnLeak \
+ -suffix -suite -tclsh -threshold]
- foreach {name value} $args {
+ set length [llength $args]
+
+ for {set index 0} {$index < $length} {incr index} {
+ #
+ # NOTE: Grab the current list element, which should be the name of
+ # the test option.
+ #
+ set name [lindex $args $index]
+
#
# NOTE: Use the [tqputs] command here just in case the test log file
# has not been setup yet (i.e. by default, this procedure is
# almost always called by the test prologue file prior to the
# test log file having been setup and we do not want to just
# lose this output).
#
if {[lsearch -exact $options $name] != -1} then {
- set array($name) $value
-
- tqputs $::test_channel [appendArgs \
- "---- overrode test option \"" $name "\" with value \"" \
- $value \"\n]
- } else {
- tqputs $::test_channel [appendArgs \
- "---- unknown test option \"" $name "\" with value \"" \
- $value "\" ignored\n"]
+ #
+ # NOTE: Is there another list element available for the value? If
+ # not, this is not a valid test option.
+ #
+ if {$index + 1 < $length} then {
+ incr index; set value [lindex $args $index]
+
+ set array($name) $value
+
+ tqputs $::test_channel [appendArgs \
+ "---- overrode test option \"" $name "\" with value \"" \
+ $value \"\n]
+ } else {
+ tqputs $::test_channel [appendArgs \
+ "---- no value for test option \"" $name "\", ignored\n"]
+ }
+ } elseif {[string index $name 0] eq "-"} then {
+ #
+ # NOTE: Is there another list element available for the value? If
+ # not, it does not conform to the standard command line name
+ # and value pattern.
+ #
+ if {$index + 1 < $length} then {
+ incr index; set value [lindex $args $index]
+
+ tqputs $::test_channel [appendArgs \
+ "---- unknown test option \"" $name "\" with value \"" \
+ $value "\" ignored\n"]
+ } else {
+ tqputs $::test_channel [appendArgs \
+ "---- no value for unknown test option \"" $name \
+ "\" ignored\n"]
+ }
+ } else {
+ #
+ # NOTE: This is not an option of *any* kind that we know about.
+ # Ignore it and issue a warning.
+ #
+ tqputs $::test_channel [appendArgs \
+ "---- unknown argument \"" $name "\" ignored\n"]
}
}
#
# NOTE: Now, attempt to flush the test log queue, if available.
@@ -801,14 +840,82 @@
proc getTestLogId {} {
return [expr {[info exists ::test_log_id] ? \
[append result . $::test_log_id] : ""}]
}
+
+ proc getDefaultTestLog {} {
+ return [file join [getTemporaryPath] [appendArgs \
+ [file tail [info nameofexecutable]] [getTestLogId] \
+ .test. [pid] .log]]
+ }
proc getTestLog {} {
return [expr {[info exists ::test_log] ? $::test_log : ""}]
}
+
+ proc getLastTestLog {} {
+ #
+ # NOTE: Use the configured log file name -OR- what the configured
+ # log file name would be, by default, if it actually existed.
+ #
+ if {[info exists ::test_log]} then {
+ set logFileName $::test_log
+ } else {
+ set logFileName [getDefaultTestLog]
+ }
+
+ set logFileName [file normalize $logFileName]
+ set logTime [expr {[file exists $logFileName] ? \
+ [file mtime $logFileName] : 0}]
+
+ #
+ # NOTE: Make the log file name into a pattern we can use to find
+ # the related log files.
+ #
+ if {[regsub -- {\.\d+\.} $logFileName {.*.} pattern]} then {
+ set lastLogFile [list]
+
+ foreach fileName [findFiles $pattern] {
+ #
+ # NOTE: Skip the current test log file, if found.
+ #
+ if {[isSameFileName $fileName $logFileName]} then {
+ continue
+ }
+
+ #
+ # NOTE: When was this log file last modified?
+ #
+ set time [file mtime $fileName]
+
+ #
+ # NOTE: Check if there has been no log file seen -OR- this
+ # log file has the latest modified time seen.
+ #
+ if {[llength $lastLogFile] == 0 || \
+ $time > [lindex $lastLogFile 0]} then {
+ #
+ # NOTE: This is now the latest log file seen.
+ #
+ set lastLogFile [list $time $fileName]
+ }
+ }
+
+ #
+ # NOTE: Either return the last log file seen, if any -OR- the
+ # configured log file, if it actually exists.
+ #
+ if {[llength $lastLogFile] > 0} then {
+ return [lindex $lastLogFile 1]
+ } elseif {$logTime != 0} then {
+ return $logFileName
+ }
+ }
+
+ return ""
+ }
proc getTestSuite {} {
#
# NOTE: Determine the effective test suite name and return it. If the
# test suite name cannot be determined, return the default based
@@ -1080,10 +1187,16 @@
proc isStopOnFailure {} {
return [expr {[info exists ::test_stop_on_failure] && \
[string is boolean -strict $::test_stop_on_failure] && \
$::test_stop_on_failure}]
}
+
+ proc isStopOnLeak {} {
+ return [expr {[info exists ::test_stop_on_leak] && \
+ [string is boolean -strict $::test_stop_on_leak] && \
+ $::test_stop_on_leak}]
+ }
proc isExitOnComplete {} {
return [expr {[info exists ::test_exit_on_complete] && \
[string is boolean -strict $::test_exit_on_complete] && \
$::test_exit_on_complete}]
@@ -1302,10 +1415,11 @@
#
# NOTE: Record counts of all object types that we track.
#
upvar 1 $varName array
+ set array(uncounted,$index) [list]
set array(time,$index) [clock seconds]
set array(afters,$index) [llength [after info]]
set array(variables,$index) [llength [info globals]]
set array(commands,$index) [llength [info commands]]
set array(procedures,$index) [llength [info procs]]
@@ -1315,10 +1429,17 @@
set array(channels,$index) [llength [file channels]]
set array(aliases,$index) [llength [interp aliases]]
set array(interpreters,$index) [llength [interp slaves]]
set array(environment,$index) [llength [array names env]]
+ #
+ # NOTE: These native resource types cannot be positively checked
+ # for leaks (i.e. because the "leak" may be from an external
+ # process).
+ #
+ lappend array(uncounted,$index) temporaryFiles
+
if {[isEagle]} then {
set array(scopes,$index) [llength [scope list]]
set array(assemblies,$index) [llength [object assemblies]]
set array(processes,$index) [llength [getProcesses ""]]
set array(objects,$index) [llength [info objects]]
@@ -1325,10 +1446,17 @@
set array(objectCallbacks,$index) [llength [info callbacks]]
set array(objectTypes,$index) [llength [object types]]
set array(objectInterfaces,$index) [llength [object interfaces]]
set array(objectNamespaces,$index) [llength [object namespaces]]
+ #
+ # NOTE: These managed resource types cannot be positively checked
+ # for leaks (i.e. because the "leak" may be from an external
+ # process).
+ #
+ lappend array(uncounted,$index) assemblies processes
+
#
# NOTE: Support for some of all of these entity types may not be
# present in the interpreter, initialize all these counts
# to zero and then try to query each one individually below
# wrapped in a catch.
@@ -1378,11 +1506,11 @@
#
set count 0; upvar 1 $statsVarName array
foreach statistic $statistics {
if {$array($statistic,after) > $array($statistic,before)} then {
- incr count; lappend array(statistics,leaked) $statistic
+ lappend array(statistics,leaked) $statistic
tputs $channel [appendArgs "==== \"" $fileName "\" LEAKED " \
$statistic \n]
if {[info exists array($statistic,before,list)]} then {
@@ -1392,10 +1520,22 @@
if {[info exists array($statistic,after,list)]} then {
tputs $channel [appendArgs "---- " $statistic " AFTER: " \
[formatList $array($statistic,after,list)] \n]
}
+
+ if {[info exists array(uncounted,before)] && \
+ [lsearch -exact $array(uncounted,before) $statistic] != -1} then {
+ continue
+ }
+
+ if {[info exists array(uncounted,after)] && \
+ [lsearch -exact $array(uncounted,after) $statistic] != -1} then {
+ continue
+ }
+
+ incr count
}
}
#
# NOTE: Make sure this file name is recorded in the list of file names with
@@ -1407,15 +1547,22 @@
[lsearch -exact $fileNames [file tail $fileName]] == -1} then {
lappend fileNames [file tail $fileName]
}
#
- # NOTE: If we are supposed to break into the debugger whenever a leak is
- # detected, do it now.
+ # NOTE: If we are supposed to stop or break into the debugger whenever
+ # a leak is detected, do it now.
#
- if {$count > 0 && [isBreakOnLeak]} then {
- testDebugBreak
+ if {$count > 0} then {
+ if {[isStopOnLeak]} then {
+ tresult Error "OVERALL RESULT: STOP-ON-LEAK\n"
+
+ unset -nocomplain ::test_suite_running
+ error ""; # no message
+ } elseif {[isBreakOnLeak]} then {
+ testDebugBreak
+ }
}
}
proc formatList { list {default ""} {columns 1} } {
if {[catch {
@@ -1496,13 +1643,18 @@
# to match an element against a list of patterns.
#
set command [list string match]
if {$noCase} then {lappend command -nocase}
- for {set index 0} {$index < [llength $patterns]} {incr index} {
+ set length [llength $patterns]
+
+ for {set index 0} {$index < $length} {incr index} {
set pattern [lindex $patterns $index]
- if {[eval $command [list $pattern] [list $element]]} then {return $index}
+
+ if {[eval $command [list $pattern] [list $element]]} then {
+ return $index
+ }
}
return -1
}
@@ -2479,11 +2631,11 @@
} finally {
interp bgerror {} $bgerror
}
}
- proc testExecTclScript { script {shell ""} } {
+ proc testExecTclScript { script {shell ""} {verbose false} } {
try {
#
# NOTE: Get a temporary file name for the script we are going to
# use to query the machine type for the native Tcl shell.
#
@@ -2511,11 +2663,11 @@
} else {
#
# NOTE: We cannot execute the native Tcl shell because one
# has not been specified, nor configured.
#
- return error
+ return [expr {$verbose ? "::test_tclsh missing" : "error"}]
}
}
#
# NOTE: Evaluate the script using the native Tcl shell, trim the
@@ -2532,11 +2684,11 @@
} else {
#
# NOTE: We could not execute the native Tcl shell (perhaps one
# is not available?).
#
- return error
+ return [expr {$verbose ? [appendArgs "error: " $result] : "error"}]
}
} finally {
#
# NOTE: Did we create a temporary file?
#
@@ -2579,10 +2731,22 @@
proc getTkVersionForTclShell { {shell ""} } {
return [testExecTclScript {
puts -nonewline stdout [package require Tk]; exit
} $shell]
}
+
+ proc evalWithTclShell { script {raw false} {shell ""} {verbose false} } {
+ return [testExecTclScript [string map \
+ [list %script% $script %raw% $raw] {
+ if {%raw%} then {
+ set code [catch {%script%} result]
+ puts -nonewline stdout [list $code $result]
+ } else {
+ puts -nonewline stdout [eval {%script%}]
+ }
+ }] $shell $verbose]
+ }
proc getGarudaDll { {machine ""} } {
#
# NOTE: Get the Garuda DLL of the same platform (i.e. machine type)
# as the native Tcl shell.
@@ -2865,20 +3029,21 @@
tputs tlog getSoftwareRegistryKey haveConstraint addConstraint \
haveOrAddConstraint getConstraints removeConstraint fixConstraints \
calculateBogoCops calculateRelativePerformance formatTimeStamp \
formatElapsedTime sourceIfValid processTestArguments \
getTclShellFileName getTemporaryPath getFiles getTestFiles \
- getTestRunId getTestLogId getTestLog getTestSuite getTestMachine \
- getTestPlatform getTestConfiguration getTestSuffix testExec \
- testClrExec execTestShell isRandomOrder isBreakOnLeak isStopOnFailure \
- isExitOnComplete returnInfoScript runTestPrologue runTestEpilogue \
- hookPuts unhookPuts runTest testDebugBreak testArrayGet testShim \
- tsource recordTestStatistics reportTestStatistics formatList \
- formatListAsDict pathToRegexp inverseLsearchGlob \
- removePathFromFileNames formatDecimal clearTestPercent \
- reportTestPercent runAllTests isTestSuiteRunning configureTcltest \
- machineToPlatform getPassPercentage getSkipPercentage] false false
+ getTestRunId getTestLogId getDefaultTestLog getTestLog getLastTestLog \
+ getTestSuite getTestMachine getTestPlatform getTestConfiguration \
+ getTestSuffix testExec testClrExec execTestShell isRandomOrder \
+ isBreakOnLeak isStopOnFailure isStopOnLeak isExitOnComplete \
+ returnInfoScript runTestPrologue runTestEpilogue hookPuts unhookPuts \
+ runTest testDebugBreak testArrayGet testShim tsource \
+ recordTestStatistics reportTestStatistics formatList formatListAsDict \
+ pathToRegexp inverseLsearchGlob removePathFromFileNames formatDecimal \
+ clearTestPercent reportTestPercent runAllTests isTestSuiteRunning \
+ configureTcltest machineToPlatform getPassPercentage \
+ getSkipPercentage] false false
###########################################################################
############################## END Tcl ONLY ###############################
###########################################################################
}
Index: Externals/Eagle/lib/Test1.0/constraints.eagle
==================================================================
--- Externals/Eagle/lib/Test1.0/constraints.eagle
+++ Externals/Eagle/lib/Test1.0/constraints.eagle
@@ -246,28 +246,31 @@
if {![isEagle]} then {
#
# BUGFIX: We do not normally want to skip any Mono bugs in native Tcl.
#
if {![info exists ::no(runtimeVersion)]} then {
- set constraints [list monoToDo monoBug monoCrash]
-
#
# NOTE: Add the necessary constraints for each version of Mono that
# we know about.
#
foreach monoVersion [getKnownMonoVersions] {
set constraintVersion [join $monoVersion ""]
addConstraint [appendArgs monoToDo $constraintVersion]
+ addConstraint [appendArgs monoToDo $constraintVersion Only]
addConstraint [appendArgs monoBug $constraintVersion]
+ addConstraint [appendArgs monoBug $constraintVersion Only]
addConstraint [appendArgs monoCrash $constraintVersion]
+ addConstraint [appendArgs monoCrash $constraintVersion Only]
}
#
# NOTE: Also add just the generic Mono constraints that do not have
# a trailing version.
#
+ set constraints [list monoToDo monoBug monoCrash]
+
foreach constraint $constraints {
addConstraint $constraint
}
}
}
@@ -769,12 +772,14 @@
#
# NOTE: Baseline reported language and feature
# version.
#
addConstraint tcl84
- addConstraint tcl84OrHigher
addConstraint tcl84Feature
+ addConstraint tcl84OrLower
+ addConstraint tcl84OrHigher
+ addConstraint tcl85OrLower
if {[isEagle]} then {
#
# NOTE: *EAGLE* We do want to include any
# tests that target "Tcl 8.5 or higher"
@@ -791,15 +796,16 @@
#
# NOTE: Baseline reported language and feature
# version. Tcl 8.5 includes all the
# features from itself and Tcl 8.4.
#
- addConstraint tcl85
+ addConstraint tcl84Feature
addConstraint tcl84OrHigher
- addConstraint tcl85OrHigher
- addConstraint tcl84Feature
+ addConstraint tcl85
addConstraint tcl85Feature
+ addConstraint tcl85OrLower
+ addConstraint tcl85OrHigher
if {[isEagle]} then {
#
# NOTE: *EAGLE* We do want to include any
# tests that target "Tcl 8.5 or higher"
@@ -816,17 +822,18 @@
# NOTE: Baseline reported language and feature
# version. Tcl 8.6 includes all the
# features from itself Tcl 8.4, and Tcl
# 8.5.
#
- addConstraint tcl86
+ addConstraint tcl84Feature
addConstraint tcl84OrHigher
+ addConstraint tcl85Feature
addConstraint tcl85OrHigher
- addConstraint tcl86OrHigher
- addConstraint tcl84Feature
- addConstraint tcl85Feature
+ addConstraint tcl86
addConstraint tcl86Feature
+ addConstraint tcl86OrLower
+ addConstraint tcl86OrHigher
}
tputs $channel [appendArgs $::tcl_version \n]
} else {
tputs $channel no\n
@@ -850,11 +857,11 @@
} else {
tputs $channel no\n
}
}
- proc checkForNamespaces { channel } {
+ proc checkForNamespaces { channel quiet } {
tputs $channel "---- checking for namespace support... "
if {[isEagle]} then {
#
# NOTE: Check if namespace support was compiled into the core library
@@ -889,11 +896,11 @@
#
# NOTE: Check if namespace support was compiled into the core
# library (i.e. is this beta 30 or later).
#
- if {$available} then {
+ if {!$quiet && $available} then {
#
# NOTE: The tests seem to be running with namespace support
# available, but disabled. Emit a warning into the
# test log file.
#
@@ -914,21 +921,21 @@
tputs $channel enabled\n
}
}
- proc checkForTestExec { channel } {
+ proc checkForTestExec { channel quiet } {
tputs $channel "---- checking for test use of \"exec\" command... "
set procName [lindex [info level [info level]] 0]
if {![info exists ::no(testExec)] && [canTestExec $procName]} then {
addConstraint testExec
tputs $channel yes\n
- if {[info exists ::no(exec)]} then {
+ if {!$quiet && [info exists ::no(exec)]} then {
tputs $channel \
"==== WARNING: running with the \"testExec\" procedure disabled\n"
}
} else {
tputs $channel no\n
@@ -1252,10 +1259,25 @@
tputs $channel yes\n
} else {
tputs $channel no\n
}
}
+
+ proc checkForTip429 { channel } {
+ tputs $channel "---- checking for TIP #429... "
+
+ #
+ # NOTE: Is the interpreter TIP #429 ready?
+ #
+ if {[catch {string cat}] == 0} then {
+ addConstraint tip429
+
+ tputs $channel yes\n
+ } else {
+ tputs $channel no\n
+ }
+ }
proc checkForTiming {
channel threshold {constraint ""} {tries 1} {delay 1000}
{average false} {asynchronous false} } {
tputs $channel [appendArgs \
@@ -1395,10 +1417,25 @@
}
} else {
tputs $channel no\n
}
}
+
+ proc checkForMemoryIntensive { channel } {
+ tputs $channel "---- checking for memory intensive testing... "
+
+ #
+ # NOTE: Are we allowed to do memory intensive testing?
+ #
+ if {![info exists ::no(memoryIntensive)]} then {
+ addConstraint memoryIntensive
+
+ tputs $channel yes\n
+ } else {
+ tputs $channel no\n
+ }
+ }
proc checkForStackIntensive { channel } {
tputs $channel "---- checking for stack intensive testing... "
#
@@ -2037,10 +2074,39 @@
addConstraint [appendArgs mono $constraintVersion OrHigher]
addConstraint [appendArgs monoToDo $constraintVersion]
addConstraint [appendArgs monoBug $constraintVersion]
addConstraint [appendArgs monoCrash $constraintVersion]
}
+
+ #
+ # NOTE: Check all known versions of Mono for an exact match with
+ # the currently running one.
+ #
+ foreach monoVersion [getKnownMonoVersions] {
+ #
+ # NOTE: Check if Mono major/minor version is exactly the one
+ # we are currently processing.
+ #
+ set constraintVersion [join $monoVersion ""]
+
+ if {[lindex $monoVersion 0] == $majorVersion && \
+ [lindex $monoVersion 1] == $minorVersion} then {
+ #
+ # NOTE: Add test constraints that only apply to this exact
+ # version of Mono.
+ #
+ addConstraint [appendArgs mono $constraintVersion Only]
+ } else {
+ #
+ # NOTE: Add test constraints that apply to all versions of
+ # Mono except this exact version.
+ #
+ addConstraint [appendArgs monoToDo $constraintVersion Only]
+ addConstraint [appendArgs monoBug $constraintVersion Only]
+ addConstraint [appendArgs monoCrash $constraintVersion Only]
+ }
+ }
}
} else {
#
# NOTE: If the runtime version was found, add a test constraint
# for it now.
@@ -2061,12 +2127,15 @@
#
foreach monoVersion [getKnownMonoVersions] {
set constraintVersion [join $monoVersion ""]
addConstraint [appendArgs monoToDo $constraintVersion]
+ addConstraint [appendArgs monoToDo $constraintVersion Only]
addConstraint [appendArgs monoBug $constraintVersion]
+ addConstraint [appendArgs monoBug $constraintVersion Only]
addConstraint [appendArgs monoCrash $constraintVersion]
+ addConstraint [appendArgs monoCrash $constraintVersion Only]
}
}
tputs $channel [appendArgs $::eagle_platform(runtimeVersion) \
" " ( $dotVersion ) \n]
@@ -2183,23 +2252,30 @@
} else {
tputs $channel unknown\n
}
}
- proc checkForQuiet { channel } {
- tputs $channel "---- checking for quiet... "
+ proc checkForQuiet { channel quiet } {
+ if {!$quiet} then {
+ tputs $channel "---- checking for quiet... "
+ }
- if {[catch {object invoke Interpreter.GetActive Quiet} quiet] == 0 && \
- $quiet} then {
+ if {[catch {
+ object invoke Interpreter.GetActive Quiet
+ } isQuiet] == 0 && $isQuiet} then {
#
# NOTE: Yes, quiet mode is enabled.
#
addConstraint quiet
- tputs $channel yes\n
+ if {!$quiet} then {
+ tputs $channel yes\n
+ }
} else {
- tputs $channel no\n
+ if {!$quiet} then {
+ tputs $channel no\n
+ }
}
}
proc checkForReferenceCountTracking { channel } {
tputs $channel "---- checking for object reference count tracking... "
@@ -3118,15 +3194,15 @@
checkForShell checkForDebug checkForTk checkForVersion \
checkForCommand checkForNamespaces checkForTestExec \
checkForTestMachine checkForTestPlatform checkForTestConfiguration \
checkForTestSuffix checkForFile checkForPathFile checkForNativeCode \
checkForTip127 checkForTip194 checkForTip207 checkForTip241 \
- checkForTip285 checkForTip405 checkForTip426 checkForTiming \
- checkForPerformance checkForBigLists checkForStackIntensive \
- checkForInteractive checkForInteractiveCommand \
- checkForUserInteraction checkForNetwork checkForCompileOption \
- checkForKnownCompileOptions] false false
+ checkForTip285 checkForTip405 checkForTip426 checkForTip429 \
+ checkForTiming checkForPerformance checkForBigLists \
+ checkForMemoryIntensive checkForStackIntensive checkForInteractive \
+ checkForInteractiveCommand checkForUserInteraction checkForNetwork \
+ checkForCompileOption checkForKnownCompileOptions] false false
###########################################################################
############################## END Tcl ONLY ###############################
###########################################################################
}
Index: Externals/Eagle/lib/Test1.0/prologue.eagle
==================================================================
--- Externals/Eagle/lib/Test1.0/prologue.eagle
+++ Externals/Eagle/lib/Test1.0/prologue.eagle
@@ -91,10 +91,24 @@
unset pkg_dir
}
#############################################################################
+ #
+ # NOTE: Set the location of the Eagle main strong name keys directory,
+ # if necessary.
+ #
+ if {![info exists key_path]} then {
+ #
+ # NOTE: Normally, there should be a "Keys" sub-directory just within
+ # the base directory.
+ #
+ set key_path [file join $base_path Keys]
+ }
+
+ #############################################################################
+
#
# NOTE: Set the executable file name for the process, if
# necessary.
#
if {![info exists bin_file]} then {
@@ -284,10 +298,11 @@
set test_flags(-logFile) ""; # default to using standard log file naming.
set test_flags(-threshold) ""; # default to requiring all tests to pass.
set test_flags(-randomOrder) ""; # default to deterministic order.
set test_flags(-breakOnLeak) ""; # default to continue on leak.
set test_flags(-stopOnFailure) ""; # default to continue on failure.
+ set test_flags(-stopOnLeak) ""; # default to continue on leak.
set test_flags(-exitOnComplete) ""; # default to not exit after complete.
set test_flags(-preTest) ""; # default to not evaluating anything.
set test_flags(-postTest) ""; # default to not evaluating anything.
set test_flags(-tclsh) ""; # Tcl shell, default to empty.
@@ -352,10 +367,19 @@
# NOTE: Set the test stop-on-failure flag to the one provided by the
# command line.
#
set test_stop_on_failure $test_flags(-stopOnFailure)
}
+
+ if {[info exists test_flags(-stopOnLeak)] && \
+ [string is boolean -strict $test_flags(-stopOnLeak)]} then {
+ #
+ # NOTE: Set the test stop-on-leak flag to the one provided by the
+ # command line.
+ #
+ set test_stop_on_leak $test_flags(-stopOnLeak)
+ }
if {[info exists test_flags(-exitOnComplete)] && \
[string is boolean -strict $test_flags(-exitOnComplete)]} then {
#
# NOTE: Set the test exit-on-complete flag to the one provided by the
@@ -416,14 +440,37 @@
if {![info exists no(logFileName)]} then {
#
# NOTE: Set the log to use for test output, if necessary.
#
if {![info exists test_log]} then {
- set test_log [file join [getTemporaryPath] [appendArgs [file tail [info \
- nameofexecutable]] [getTestLogId] .test. [pid] .log]]
+ set test_log [getDefaultTestLog]
+ }
+ }
+
+ #############################################################################
+
+ #
+ # NOTE: *SPECIAL* This test constraint must be checked first as it can
+ # determine if subsequent ones will emit warnings. This is only
+ # applicable to Eagle.
+ #
+ if {[isEagle]} then {
+ #
+ # NOTE: Has quiet testing support been disabled?
+ #
+ if {![info exists no(preQuiet)]} then {
+ #
+ # NOTE: There are checks for the "quiet" test constraint prior to
+ # the real test constraints being initialized. Prepare for
+ # those checks now. This will have to be repeated later,
+ # after the real test constraints are initialized.
+ #
+ checkForQuiet $test_channel true
}
}
+
+ #############################################################################
#
# NOTE: Has native Tcl shell detection and use been disabled?
#
if {![info exists no(tclsh)]} then {
@@ -451,11 +498,12 @@
![info exists no(getTclShellFileName)]} then {
#
# NOTE: Attempt to automatically select the native Tcl shell
# to use.
#
- if {![info exists no(warningForTclShell)]} then {
+ if {![info exists no(warningForTclShell)] && \
+ ![haveConstraint quiet]} then {
tputs $test_channel \
"==== WARNING: attempting automatic Tcl shell selection...\n"
}
set test_tclsh [getTclShellFileName true]
@@ -477,11 +525,12 @@
# the interpreter and issue warnings if any are found. The warning
# may be used to explain subsequent test failures due to the extra
# plugins being loaded (i.e. there are some tests are sensitive to
# having "unexpected" plugins loaded).
#
- if {[isEagle] && ![info exists no(warningForPlugin)]} then {
+ if {[isEagle] && ![info exists no(warningForPlugin)] && \
+ ![haveConstraint quiet]} then {
foreach loaded [info loaded] {
#
# HACK: This code assumes that all plugins in the "Eagle._Plugins"
# namespace belong to the Eagle core library itself.
#
@@ -581,48 +630,11 @@
tputs $test_channel [appendArgs "---- test suffix: " \
[expr {[info exists test_suffix] ? \
$test_suffix : ""}] \n]
- if {[isEagle] && ![info exists no(warningForStrongName)]} then {
- catch {info engine PublicKeyToken} publicKeyToken
-
- if {[string length $publicKeyToken] == 0} then {
- #
- # NOTE: The Eagle core library is not strong name signed. This is not an
- # error, per se; however, it may cause some tests to fail and it
- # should be reported to the user and noted in the test suite log
- # file.
- #
- tputs $test_channel \
- "==== WARNING: running without any strong name signature...\n"
- } else {
- #
- # BUGBUG: Tcl 8.4 does not like this expression because it contains the
- # "ni" operator (and Tcl tries to compile it even though it will
- # only actually ever be evaluated in Eagle).
- #
- set expr {$publicKeyToken ni \
- "29c6297630be05eb 1e22ec67879739a2 358030063a832bc3"}
-
- if {[expr $expr]} then {
- #
- # NOTE: The Eagle core library is strong name signed with a key that is
- # not official. This is also not an error, per se; however, it
- # may cause some tests to fail and it should be reported to the
- # user and noted in the test suite log file.
- #
- tputs $test_channel [appendArgs \
- "==== WARNING: running without official strong name signature: " \
- $publicKeyToken \n]
- }
-
- unset expr
- }
-
- unset publicKeyToken
-
+ if {[isEagle]} then {
tputs $test_channel [appendArgs "---- original command line: " \
[info cmdline] \n]
tputs $test_channel [appendArgs "---- threadId: " \
[info tid] \n]
@@ -695,10 +707,15 @@
tputs $test_channel [appendArgs "---- stop on failure: " \
[expr {[info exists test_stop_on_failure] && \
[string is boolean -strict $test_stop_on_failure] ? \
$test_stop_on_failure : ""}] \n]
+
+ tputs $test_channel [appendArgs "---- stop on leak: " \
+ [expr {[info exists test_stop_on_leak] && \
+ [string is boolean -strict $test_stop_on_leak] ? \
+ $test_stop_on_leak : ""}] \n]
tputs $test_channel [appendArgs "---- exit on complete: " \
[expr {[info exists test_exit_on_complete] && \
[string is boolean -strict $test_exit_on_complete] ? \
$test_exit_on_complete : ""}] \n]
@@ -743,10 +760,13 @@
[expr {[info exists path] && [string length $path] > 0 ? \
[appendArgs \" $path \"] : ""}] \n]
tputs $test_channel [appendArgs "---- base path: \"" \
$base_path \"\n]
+
+ tputs $test_channel [appendArgs "---- key path: \"" \
+ $key_path \"\n]
tputs $test_channel [appendArgs "---- root path: \"" \
$root_path \"\n]
tputs $test_channel [appendArgs "---- binary path: \"" \
@@ -776,10 +796,14 @@
#
# NOTE: Initialize the Eagle test constraints.
#
if {[isEagle]} then {
+ #
+ # NOTE: *WARNING* This has the effect of removing test constraints
+ # added prior to this point.
+ #
initializeTests; configureTcltest [list] [list] [list] [list] false
#
# NOTE: If the "no(mono)" variable is set (to anything) then any
# special test suite hacks for Mono will be disabled. This
@@ -794,10 +818,94 @@
######################### BEGIN Eagle Constraints #########################
###########################################################################
tputs $test_channel \
"---- start of Eagle specific test constraints...\n"
+
+ #
+ # NOTE: *WARNING* Has quiet testing support been disabled?
+ # Please do not move this "quietness" test constraint
+ # check as subsequent test constraints may rely on it
+ # when determining if a warning should be emitted.
+ #
+ if {![info exists no(quiet)]} then {
+ #
+ # NOTE: For tests "basic-1.36", "benchmark-1.*", "debug-1.3",
+ # "debug-1.4", "glob-99.*", "object-10.*", "perf-2.2",
+ # and various other places within the test suite code
+ # itself.
+ #
+ checkForQuiet $test_channel false
+ }
+
+ #
+ # NOTE: Has strong name key detection been disabled?
+ #
+ if {![info exists no(strongNameKey)]} then {
+ catch {info engine PublicKeyToken} publicKeyToken
+
+ if {[string length $publicKeyToken] == 0} then {
+ #
+ # NOTE: The Eagle core library is not signed with a strong name key.
+ # This is not an error, per se; however, it may cause selected
+ # tests to fail and it should be reported to the user and noted
+ # in the test suite log file.
+ #
+ addConstraint strongName.none
+
+ if {![info exists no(warningForStrongNameKey)] && \
+ ![haveConstraint quiet]} then {
+ tputs $test_channel \
+ "==== WARNING: no Eagle strong name signature detected...\n"
+ }
+ } else {
+ #
+ # NOTE: Add a test constraint for this specific strong name key.
+ #
+ addConstraint [appendArgs strongName. $publicKeyToken]
+
+ #
+ # BUGBUG: Tcl 8.4 does not seem to like this expression because it
+ # contains the "ni" operator added in Tcl 8.5 (and Tcl 8.4
+ # tries to compile it even though it will only be evaluated
+ # in Eagle).
+ #
+ set expr {$publicKeyToken ni \
+ "29c6297630be05eb 1e22ec67879739a2 358030063a832bc3"}
+
+ if {[expr $expr]} then {
+ #
+ # NOTE: The Eagle core library is strong name signed with a key that
+ # is not official. This is also not an error, per se; however,
+ # it may cause some tests to fail and it should be reported to
+ # the user and noted in the test suite log file.
+ #
+ addConstraint strongName.unofficial
+
+ if {![info exists no(warningForStrongNameKey)] && \
+ ![haveConstraint quiet]} then {
+ tputs $test_channel [appendArgs \
+ "==== WARNING: unofficial Eagle strong name signature " \
+ "detected: " $publicKeyToken \n]
+ }
+ } else {
+ #
+ # NOTE: Several tests require one of the official strong name keys to
+ # be used in order for them to pass.
+ #
+ addConstraint strongName.official
+
+ tputs $test_channel [appendArgs \
+ "---- official Eagle strong name signature detected: " \
+ $publicKeyToken \n]
+ }
+
+ unset expr
+ }
+
+ unset publicKeyToken
+ }
#
# NOTE: Has administrator detection support been disabled? We do
# this check [nearly] first as it may [eventually] be used
# to help determine if other constraints should be skipped.
@@ -1013,21 +1121,10 @@
#
if {![info exists no(assemblySymbols)]} then {
checkForSymbols $test_channel [lindex [info assembly] end]
}
- #
- # NOTE: Has quiet testing support been disabled?
- #
- if {![info exists no(quiet)]} then {
- #
- # NOTE: For tests "basic-1.36", "debug-1.3", "debug-1.4", "object-10.*",
- # and "perf-2.2".
- #
- checkForQuiet $test_channel
- }
-
#
# NOTE: Has object handle reference count tracking support been disabled
# (at compile-time)?
#
if {![info exists no(refCount)]} then {
@@ -1516,10 +1613,28 @@
checkForObjectMember $test_channel Eagle._Tests.Default \
*TestUnsetVariableLinks*
}
+ #
+ # NOTE: Has system array variable testing support been disabled?
+ #
+ if {![info exists no(testSystemArrayVariables)]} then {
+ #
+ # NOTE: For tests "basic-1.62", "basic-1.63", "basic-1.64",
+ # and "basic-1.65".
+ #
+ checkForObjectMember $test_channel Eagle._Tests.Default \
+ *TestIntPtrChangeTypeCallback*
+
+ checkForObjectMember $test_channel Eagle._Tests.Default \
+ *TestSetVariableSystemArray*
+
+ checkForObjectMember $test_channel Eagle._Tests.Default \
+ *TestUnsetVariableSystemArray*
+ }
+
#
# NOTE: Has field testing support been disabled?
#
if {![info exists no(testFields)]} then {
#
@@ -1586,10 +1701,16 @@
# NOTE: For test "object-2.1".
#
checkForObjectMember $test_channel Eagle._Tests.Default \
*TestComplexMethod*
+ #
+ # NOTE: For test "object-2.12".
+ #
+ checkForObjectMember $test_channel Eagle._Tests.Default \
+ *TestMoreComplexMethod*
+
#
# NOTE: For test "object-2.3".
#
checkForObjectMember $test_channel Eagle._Tests.Default \
*TestToHexadecimalString*
@@ -2024,11 +2145,11 @@
#
# NOTE: Has all use of [exec] for tests been disabled?
#
if {![info exists no(checkForTestExec)]} then {
- checkForTestExec $test_channel
+ checkForTestExec $test_channel [haveConstraint quiet]
}
#
# NOTE: Has checking for the test machine been disabled?
#
@@ -2331,10 +2452,14 @@
}
if {![info exists no(checkForBigLists)]} then {
checkForBigLists $test_channel
}
+
+ if {![info exists no(checkForMemoryIntensive)]} then {
+ checkForMemoryIntensive $test_channel
+ }
if {![info exists no(checkForStackIntensive)]} then {
checkForStackIntensive $test_channel
}
@@ -2421,11 +2546,11 @@
#
# NOTE: Has namespace detection support been disabled?
#
if {![info exists no(namespaces)]} then {
- checkForNamespaces $test_channel
+ checkForNamespaces $test_channel [haveConstraint quiet]
}
#
# NOTE: Check for various features that were added through
# the TIP process.
@@ -2456,10 +2581,14 @@
if {![info exists no(tip426)]} then {
checkForTip426 $test_channel
}
+ if {![info exists no(tip429)]} then {
+ checkForTip429 $test_channel
+ }
+
#
# NOTE: Has performance testing been disabled?
#
if {![info exists no(core)] && \
![info exists no(checkForPerformance)]} then {
@@ -2480,11 +2609,19 @@
checkForTiming $test_channel 50; # 1/20th second.
}
if {![info exists no(core)] && \
![info exists no(preciseTiming)]} then {
- checkForTiming $test_channel 25 preciseTiming; # 1/40th second.
+ #
+ # NOTE: Normally, the "preciseTiming" constraint implicitly requires that
+ # the "timing" constraint be present as well; however, that can be
+ # overridden.
+ #
+ if {[info exists no(requireTiming)] || \
+ [haveConstraint timing]} then {
+ checkForTiming $test_channel 25 preciseTiming; # 1/40th second.
+ }
}
#
# NOTE: Has interactive testing been disabled?
#
Index: NuGet/SQLite.Core.Beta.nuspec
==================================================================
--- NuGet/SQLite.Core.Beta.nuspec
+++ NuGet/SQLite.Core.Beta.nuspec
@@ -28,19 +28,19 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
Index: NuGet/SQLite.Core.Test.nuspec
==================================================================
--- NuGet/SQLite.Core.Test.nuspec
+++ NuGet/SQLite.Core.Test.nuspec
@@ -28,19 +28,19 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
Index: NuGet/SQLite.Core.nuspec
==================================================================
--- NuGet/SQLite.Core.nuspec
+++ NuGet/SQLite.Core.nuspec
@@ -28,19 +28,19 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
Index: NuGet/SQLite.EF6.Beta.nuspec
==================================================================
--- NuGet/SQLite.EF6.Beta.nuspec
+++ NuGet/SQLite.EF6.Beta.nuspec
@@ -43,16 +43,16 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
Index: NuGet/SQLite.EF6.Test.nuspec
==================================================================
--- NuGet/SQLite.EF6.Test.nuspec
+++ NuGet/SQLite.EF6.Test.nuspec
@@ -43,16 +43,16 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
Index: NuGet/SQLite.EF6.nuspec
==================================================================
--- NuGet/SQLite.EF6.nuspec
+++ NuGet/SQLite.EF6.nuspec
@@ -43,16 +43,16 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
Index: NuGet/SQLite.Linq.Beta.nuspec
==================================================================
--- NuGet/SQLite.Linq.Beta.nuspec
+++ NuGet/SQLite.Linq.Beta.nuspec
@@ -38,15 +38,15 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
Index: NuGet/SQLite.Linq.Test.nuspec
==================================================================
--- NuGet/SQLite.Linq.Test.nuspec
+++ NuGet/SQLite.Linq.Test.nuspec
@@ -38,15 +38,15 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
Index: NuGet/SQLite.Linq.nuspec
==================================================================
--- NuGet/SQLite.Linq.nuspec
+++ NuGet/SQLite.Linq.nuspec
@@ -38,15 +38,15 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
Index: NuGet/SQLite.MSIL.Beta.nuspec
==================================================================
--- NuGet/SQLite.MSIL.Beta.nuspec
+++ NuGet/SQLite.MSIL.Beta.nuspec
@@ -46,18 +46,18 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
Index: NuGet/SQLite.MSIL.Test.nuspec
==================================================================
--- NuGet/SQLite.MSIL.Test.nuspec
+++ NuGet/SQLite.MSIL.Test.nuspec
@@ -46,18 +46,18 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
Index: NuGet/SQLite.MSIL.nuspec
==================================================================
--- NuGet/SQLite.MSIL.nuspec
+++ NuGet/SQLite.MSIL.nuspec
@@ -46,18 +46,18 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
Index: NuGet/SQLite.x64.nuspec
==================================================================
--- NuGet/SQLite.x64.nuspec
+++ NuGet/SQLite.x64.nuspec
@@ -45,18 +45,18 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
Index: NuGet/SQLite.x86.nuspec
==================================================================
--- NuGet/SQLite.x86.nuspec
+++ NuGet/SQLite.x86.nuspec
@@ -45,18 +45,18 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
DELETED NuGet/net20/Core/config.transform
Index: NuGet/net20/Core/config.transform
==================================================================
--- NuGet/net20/Core/config.transform
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
DELETED NuGet/net20/Core/install.ps1
Index: NuGet/net20/Core/install.ps1
==================================================================
--- NuGet/net20/Core/install.ps1
+++ /dev/null
@@ -1,36 +0,0 @@
-###############################################################################
-#
-# install.ps1 --
-#
-# Written by Joe Mistachkin.
-# Released to the public domain, use at your own risk!
-#
-###############################################################################
-
-param($installPath, $toolsPath, $package, $project)
-
-$platformNames = "x86", "x64"
-$fileName = "SQLite.Interop.dll"
-$propertyName = "CopyToOutputDirectory"
-
-foreach($platformName in $platformNames) {
- $folder = $project.ProjectItems.Item($platformName)
-
- if ($folder -eq $null) {
- continue
- }
-
- $item = $folder.ProjectItems.Item($fileName)
-
- if ($item -eq $null) {
- continue
- }
-
- $property = $item.Properties.Item($propertyName)
-
- if ($property -eq $null) {
- continue
- }
-
- $property.Value = 1
-}
DELETED NuGet/net40/Core/config.transform
Index: NuGet/net40/Core/config.transform
==================================================================
--- NuGet/net40/Core/config.transform
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
DELETED NuGet/net40/Core/install.ps1
Index: NuGet/net40/Core/install.ps1
==================================================================
--- NuGet/net40/Core/install.ps1
+++ /dev/null
@@ -1,36 +0,0 @@
-###############################################################################
-#
-# install.ps1 --
-#
-# Written by Joe Mistachkin.
-# Released to the public domain, use at your own risk!
-#
-###############################################################################
-
-param($installPath, $toolsPath, $package, $project)
-
-$platformNames = "x86", "x64"
-$fileName = "SQLite.Interop.dll"
-$propertyName = "CopyToOutputDirectory"
-
-foreach($platformName in $platformNames) {
- $folder = $project.ProjectItems.Item($platformName)
-
- if ($folder -eq $null) {
- continue
- }
-
- $item = $folder.ProjectItems.Item($fileName)
-
- if ($item -eq $null) {
- continue
- }
-
- $property = $item.Properties.Item($propertyName)
-
- if ($property -eq $null) {
- continue
- }
-
- $property.Value = 1
-}
DELETED NuGet/net40/EF6/config.transform
Index: NuGet/net40/EF6/config.transform
==================================================================
--- NuGet/net40/EF6/config.transform
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
ADDED NuGet/net40/EF6/content/config.transform
Index: NuGet/net40/EF6/content/config.transform
==================================================================
--- /dev/null
+++ NuGet/net40/EF6/content/config.transform
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
DELETED NuGet/net40/EF6/install.ps1
Index: NuGet/net40/EF6/install.ps1
==================================================================
--- NuGet/net40/EF6/install.ps1
+++ /dev/null
@@ -1,39 +0,0 @@
-###############################################################################
-#
-# install.ps1 --
-#
-# Written by Joe Mistachkin.
-# Released to the public domain, use at your own risk!
-#
-###############################################################################
-
-param($installPath, $toolsPath, $package, $project)
-
-$platformNames = "x86", "x64"
-$fileName = "SQLite.Interop.dll"
-$propertyName = "CopyToOutputDirectory"
-
-foreach($platformName in $platformNames) {
- $folder = $project.ProjectItems.Item($platformName)
-
- if ($folder -eq $null) {
- continue
- }
-
- $item = $folder.ProjectItems.Item($fileName)
-
- if ($item -eq $null) {
- continue
- }
-
- $property = $item.Properties.Item($propertyName)
-
- if ($property -eq $null) {
- continue
- }
-
- $property.Value = 1
-}
-
-Add-EFProvider $project "System.Data.SQLite.EF6" `
- "System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6"
DELETED NuGet/net40/EF6/provider.ps1
Index: NuGet/net40/EF6/provider.ps1
==================================================================
--- NuGet/net40/EF6/provider.ps1
+++ /dev/null
@@ -1,13 +0,0 @@
-###############################################################################
-#
-# provider.ps1 --
-#
-# Written by Joe Mistachkin.
-# Released to the public domain, use at your own risk!
-#
-###############################################################################
-
-param($installPath, $toolsPath, $package, $project)
-
-Add-EFProvider $project "System.Data.SQLite.EF6" `
- "System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6"
ADDED NuGet/net40/EF6/tools/provider.ps1
Index: NuGet/net40/EF6/tools/provider.ps1
==================================================================
--- /dev/null
+++ NuGet/net40/EF6/tools/provider.ps1
@@ -0,0 +1,13 @@
+###############################################################################
+#
+# provider.ps1 --
+#
+# Written by Joe Mistachkin.
+# Released to the public domain, use at your own risk!
+#
+###############################################################################
+
+param($installPath, $toolsPath, $package, $project)
+
+Add-EFProvider $project "System.Data.SQLite.EF6" `
+ "System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6"
ADDED NuGet/shared/Core/build/System.Data.SQLite.Core.targets
Index: NuGet/shared/Core/build/System.Data.SQLite.Core.targets
==================================================================
--- /dev/null
+++ NuGet/shared/Core/build/System.Data.SQLite.Core.targets
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(BuildDependsOn);
+ CopySQLiteInteropFiles;
+
+
+ $(CleanDependsOn);
+ CleanSQLiteInteropFiles;
+
+
+
ADDED NuGet/shared/Core/content/config.transform
Index: NuGet/shared/Core/content/config.transform
==================================================================
--- /dev/null
+++ NuGet/shared/Core/content/config.transform
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
Index: SQLite.Designer/Editors/ViewDesignerDoc.cs
==================================================================
--- SQLite.Designer/Editors/ViewDesignerDoc.cs
+++ SQLite.Designer/Editors/ViewDesignerDoc.cs
@@ -75,11 +75,11 @@
_typeQB = SQLiteDataAdapterToolboxItem._vsdesigner.GetType("Microsoft.VSDesigner.Data.Design.QueryBuilderControl");
if (_typeQB != null)
{
_queryDesigner = Activator.CreateInstance(_typeQB) as UserControl;
- _typeQB.InvokeMember("Provider", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.SetProperty | System.Reflection.BindingFlags.NonPublic, null, _queryDesigner, new object[] { "System.Data.SQLite" });
+ _typeQB.InvokeMember("Provider", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.SetProperty | System.Reflection.BindingFlags.NonPublic, null, _queryDesigner, new object[] { SQLiteOptions.GetProviderName() });
_typeQB.InvokeMember("ConnectionString", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.SetProperty | System.Reflection.BindingFlags.NonPublic, null, _queryDesigner, new object[] { _connection.ConnectionSupport.ConnectionString });
_typeQB.InvokeMember("EnableMorphing", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.SetProperty | System.Reflection.BindingFlags.NonPublic, null, _queryDesigner, new object[] { false });
Controls.Add(_queryDesigner);
_queryDesigner.Dock = DockStyle.Fill;
_queryDesigner.Visible = true;
Index: SQLite.Designer/SQLite.Designer.2005.csproj
==================================================================
--- SQLite.Designer/SQLite.Designer.2005.csproj
+++ SQLite.Designer/SQLite.Designer.2005.csproj
@@ -133,10 +133,11 @@
+
Form
Index: SQLite.Designer/SQLite.Designer.2008.csproj
==================================================================
--- SQLite.Designer/SQLite.Designer.2008.csproj
+++ SQLite.Designer/SQLite.Designer.2008.csproj
@@ -138,10 +138,11 @@
+
Form
Index: SQLite.Designer/SQLite.Designer.2010.csproj
==================================================================
--- SQLite.Designer/SQLite.Designer.2010.csproj
+++ SQLite.Designer/SQLite.Designer.2010.csproj
@@ -138,10 +138,11 @@
+
Form
Index: SQLite.Designer/SQLite.Designer.2012.csproj
==================================================================
--- SQLite.Designer/SQLite.Designer.2012.csproj
+++ SQLite.Designer/SQLite.Designer.2012.csproj
@@ -144,10 +144,11 @@
+
Form
Index: SQLite.Designer/SQLite.Designer.2013.csproj
==================================================================
--- SQLite.Designer/SQLite.Designer.2013.csproj
+++ SQLite.Designer/SQLite.Designer.2013.csproj
@@ -144,10 +144,11 @@
+
Form
Index: SQLite.Designer/SQLiteConnectionProperties.cs
==================================================================
--- SQLite.Designer/SQLiteConnectionProperties.cs
+++ SQLite.Designer/SQLiteConnectionProperties.cs
@@ -21,11 +21,11 @@
: this(null)
{
}
public SQLiteConnectionProperties(string connectionString)
- : base("System.Data.SQLite", connectionString)
+ : base(SQLiteOptions.GetProviderName(), connectionString)
{
}
public override string[] GetBasicProperties()
{
@@ -40,11 +40,11 @@
}
public override bool Contains(string propertyName)
{
if (String.Compare(propertyName, "Database", StringComparison.OrdinalIgnoreCase) == 0)
- return (base.Contains("data source") || base.Contains("uri"));
+ return (base.Contains("data source") || base.Contains("uri") || base.Contains("fulluri"));
return base.Contains(propertyName);
}
public override object this[string propertyName]
@@ -66,10 +66,12 @@
{
if (this["data source"] is string && ((string)this["data source"]).Length > 0)
return (string)this["data source"];
else if (this["uri"] is string)
return MapUriPath((string)this["uri"]);
+ else if (this["fulluri"] is string)
+ return (string)this["fulluri"];
return String.Empty;
}
public override bool IsComplete
{
@@ -82,10 +84,15 @@
}
else if (Contains("uri") == true)
{
if (this["uri"] is string && MapUriPath((string)this["uri"]).Length > 0)
return true;
+ }
+ else if (Contains("fulluri") == true)
+ {
+ if (this["fulluri"] is string && ((string)this["fulluri"]).Length > 0)
+ return true;
}
return false;
}
}
Index: SQLite.Designer/SQLiteConnectionStringEditor.cs
==================================================================
--- SQLite.Designer/SQLiteConnectionStringEditor.cs
+++ SQLite.Designer/SQLiteConnectionStringEditor.cs
@@ -58,11 +58,11 @@
if (_managerType != null)
{
object manager = Activator.CreateInstance(_managerType, new object[] { provider });
if (manager != null)
{
- index = (int)_managerType.InvokeMember("AddNewConnection", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public, null, manager, new object[] { "System.Data.SQLite" });
+ index = (int)_managerType.InvokeMember("AddNewConnection", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public, null, manager, new object[] { SQLiteOptions.GetProviderName() });
if (index > -1 && _selector != null)
{
connectionString = (string)_managerType.InvokeMember("GetConnectionString", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public, null, manager, new object[] { index });
_selector.SelectedNode = _selector.AddNode((string)_managerType.InvokeMember("GetConnectionName", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public, null, manager, new object[] { index }), connectionString, null);
}
@@ -102,11 +102,11 @@
for (int n = 0; n < items; n++)
{
connectionString = (string)_managerType.InvokeMember("GetConnectionString", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public, null, manager, new object[] { n });
connectionName = (string)_managerType.InvokeMember("GetConnectionName", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public, null, manager, new object[] { n });
dataProvider = (string)_managerType.InvokeMember("GetProvider", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public, null, manager, new object[] { n });
- if (String.Compare(dataProvider, "System.Data.SQLite", StringComparison.OrdinalIgnoreCase) == 0)
+ if (String.Compare(dataProvider, SQLiteOptions.GetProviderName(), StringComparison.OrdinalIgnoreCase) == 0)
{
node = selector.AddNode(connectionName, connectionString, null);
if (String.Compare(connectionString, connection.ConnectionString, StringComparison.OrdinalIgnoreCase) == 0)
selector.SelectedNode = node;
Index: SQLite.Designer/SQLiteConnectionUIControl.Designer.cs
==================================================================
--- SQLite.Designer/SQLiteConnectionUIControl.Designer.cs
+++ SQLite.Designer/SQLiteConnectionUIControl.Designer.cs
@@ -1,358 +1,383 @@
/********************************************************
* ADO.NET 2.0 Data Provider for SQLite Version 3.X
* Written by Robert Simpson (robert@blackcastlesoft.com)
- *
+ *
* Released to the public domain, use at your own risk!
- ********************************************************/
-
-namespace SQLite.Designer
-{
- partial class SQLiteConnectionUIControl
- {
- ///
- /// Required designer variable.
- ///
- private System.ComponentModel.IContainer components = null;
-
- ///
- /// Clean up any resources being used.
- ///
- /// true if managed resources should be disposed; otherwise, false.
- protected override void Dispose(bool disposing)
- {
- if (disposing && (components != null))
- {
- components.Dispose();
- }
- base.Dispose(disposing);
- }
-
- #region Windows Form Designer generated code
-
- ///
- /// Required method for Designer support - do not modify
- /// the contents of this method with the code editor.
- ///
- private void InitializeComponent()
- {
- System.Windows.Forms.Label labelPassword;
- System.Windows.Forms.GroupBox securityGroup;
- System.Windows.Forms.GroupBox encodingGroup;
- System.Windows.Forms.GroupBox dateTimeGroup;
- System.Windows.Forms.GroupBox databaseGroup;
- System.Windows.Forms.Label cacheSizeLabel;
- System.Windows.Forms.Label pageSizeLabel;
- System.Windows.Forms.GroupBox syncGroup;
- this.passwordTextBox = new System.Windows.Forms.TextBox();
- this.utf16RadioButton = new System.Windows.Forms.RadioButton();
- this.utf8RadioButton = new System.Windows.Forms.RadioButton();
- this.ticksRadioButton = new System.Windows.Forms.RadioButton();
- this.iso8601RadioButton = new System.Windows.Forms.RadioButton();
- this.cacheSizeTextbox = new System.Windows.Forms.TextBox();
- this.pageSizeTextBox = new System.Windows.Forms.TextBox();
- this.fileTextBox = new System.Windows.Forms.TextBox();
- this.browseButton = new System.Windows.Forms.Button();
- this.newDatabase = new System.Windows.Forms.Button();
- this.offRadioButton = new System.Windows.Forms.RadioButton();
- this.normalRadioButton = new System.Windows.Forms.RadioButton();
- this.fullRadioButton = new System.Windows.Forms.RadioButton();
- this.julianRadioButton = new System.Windows.Forms.RadioButton();
- labelPassword = new System.Windows.Forms.Label();
- securityGroup = new System.Windows.Forms.GroupBox();
- encodingGroup = new System.Windows.Forms.GroupBox();
- dateTimeGroup = new System.Windows.Forms.GroupBox();
- databaseGroup = new System.Windows.Forms.GroupBox();
- cacheSizeLabel = new System.Windows.Forms.Label();
- pageSizeLabel = new System.Windows.Forms.Label();
- syncGroup = new System.Windows.Forms.GroupBox();
- securityGroup.SuspendLayout();
- encodingGroup.SuspendLayout();
- dateTimeGroup.SuspendLayout();
- databaseGroup.SuspendLayout();
- syncGroup.SuspendLayout();
- this.SuspendLayout();
- //
- // labelPassword
- //
- labelPassword.AutoSize = true;
- labelPassword.Location = new System.Drawing.Point(6, 23);
- labelPassword.Name = "labelPassword";
- labelPassword.Size = new System.Drawing.Size(53, 13);
- labelPassword.TabIndex = 0;
- labelPassword.Text = "Password";
- //
- // securityGroup
- //
- securityGroup.Controls.Add(this.passwordTextBox);
- securityGroup.Controls.Add(labelPassword);
- securityGroup.Location = new System.Drawing.Point(3, 263);
- securityGroup.Name = "securityGroup";
- securityGroup.Size = new System.Drawing.Size(306, 56);
- securityGroup.TabIndex = 10;
- securityGroup.TabStop = false;
- securityGroup.Text = "Encryption";
- //
- // passwordTextBox
- //
- this.passwordTextBox.Location = new System.Drawing.Point(65, 20);
- this.passwordTextBox.Name = "passwordTextBox";
- this.passwordTextBox.Size = new System.Drawing.Size(235, 21);
- this.passwordTextBox.TabIndex = 1;
- this.passwordTextBox.UseSystemPasswordChar = true;
- this.passwordTextBox.Leave += new System.EventHandler(this.passwordTextBox_Leave);
- //
- // encodingGroup
- //
- encodingGroup.Controls.Add(this.utf16RadioButton);
- encodingGroup.Controls.Add(this.utf8RadioButton);
- encodingGroup.Location = new System.Drawing.Point(3, 159);
- encodingGroup.Name = "encodingGroup";
- encodingGroup.Size = new System.Drawing.Size(75, 98);
- encodingGroup.TabIndex = 7;
- encodingGroup.TabStop = false;
- encodingGroup.Text = "Encoding";
- //
- // utf16RadioButton
- //
- this.utf16RadioButton.AutoSize = true;
- this.utf16RadioButton.Location = new System.Drawing.Point(6, 44);
- this.utf16RadioButton.Name = "utf16RadioButton";
- this.utf16RadioButton.Size = new System.Drawing.Size(60, 17);
- this.utf16RadioButton.TabIndex = 1;
- this.utf16RadioButton.TabStop = true;
- this.utf16RadioButton.Text = "UTF-16";
- this.utf16RadioButton.UseVisualStyleBackColor = true;
- this.utf16RadioButton.CheckedChanged += new System.EventHandler(this.encoding_Changed);
- //
- // utf8RadioButton
- //
- this.utf8RadioButton.AutoSize = true;
- this.utf8RadioButton.Checked = true;
- this.utf8RadioButton.Location = new System.Drawing.Point(7, 21);
- this.utf8RadioButton.Name = "utf8RadioButton";
- this.utf8RadioButton.Size = new System.Drawing.Size(54, 17);
- this.utf8RadioButton.TabIndex = 0;
- this.utf8RadioButton.TabStop = true;
- this.utf8RadioButton.Text = "UTF-8";
- this.utf8RadioButton.UseVisualStyleBackColor = true;
- this.utf8RadioButton.CheckedChanged += new System.EventHandler(this.encoding_Changed);
- //
- // dateTimeGroup
- //
- dateTimeGroup.Controls.Add(this.julianRadioButton);
- dateTimeGroup.Controls.Add(this.ticksRadioButton);
- dateTimeGroup.Controls.Add(this.iso8601RadioButton);
- dateTimeGroup.Location = new System.Drawing.Point(84, 159);
- dateTimeGroup.Name = "dateTimeGroup";
- dateTimeGroup.Size = new System.Drawing.Size(113, 98);
- dateTimeGroup.TabIndex = 8;
- dateTimeGroup.TabStop = false;
- dateTimeGroup.Text = "Date/Time Format";
- //
- // ticksRadioButton
- //
- this.ticksRadioButton.AutoSize = true;
- this.ticksRadioButton.Location = new System.Drawing.Point(7, 66);
- this.ticksRadioButton.Name = "ticksRadioButton";
- this.ticksRadioButton.Size = new System.Drawing.Size(48, 17);
- this.ticksRadioButton.TabIndex = 1;
- this.ticksRadioButton.TabStop = true;
- this.ticksRadioButton.Text = "Ticks";
- this.ticksRadioButton.UseVisualStyleBackColor = true;
- this.ticksRadioButton.CheckedChanged += new System.EventHandler(this.datetime_Changed);
- //
- // iso8601RadioButton
- //
- this.iso8601RadioButton.AutoSize = true;
- this.iso8601RadioButton.Checked = true;
- this.iso8601RadioButton.Location = new System.Drawing.Point(7, 21);
- this.iso8601RadioButton.Name = "iso8601RadioButton";
- this.iso8601RadioButton.Size = new System.Drawing.Size(71, 17);
- this.iso8601RadioButton.TabIndex = 0;
- this.iso8601RadioButton.TabStop = true;
- this.iso8601RadioButton.Text = "ISO-8601";
- this.iso8601RadioButton.UseVisualStyleBackColor = true;
- this.iso8601RadioButton.CheckedChanged += new System.EventHandler(this.datetime_Changed);
- //
- // databaseGroup
- //
- databaseGroup.Controls.Add(cacheSizeLabel);
- databaseGroup.Controls.Add(this.cacheSizeTextbox);
- databaseGroup.Controls.Add(pageSizeLabel);
- databaseGroup.Controls.Add(this.pageSizeTextBox);
- databaseGroup.Controls.Add(this.fileTextBox);
- databaseGroup.Controls.Add(this.browseButton);
- databaseGroup.Controls.Add(this.newDatabase);
- databaseGroup.Location = new System.Drawing.Point(3, 3);
- databaseGroup.Name = "databaseGroup";
- databaseGroup.Size = new System.Drawing.Size(306, 150);
- databaseGroup.TabIndex = 8;
- databaseGroup.TabStop = false;
- databaseGroup.Text = "Database";
- //
- // cacheSizeLabel
- //
- cacheSizeLabel.AutoSize = true;
- cacheSizeLabel.Location = new System.Drawing.Point(7, 116);
- cacheSizeLabel.Name = "cacheSizeLabel";
- cacheSizeLabel.Size = new System.Drawing.Size(59, 13);
- cacheSizeLabel.TabIndex = 5;
- cacheSizeLabel.Text = "Cache Size";
- //
- // cacheSizeTextbox
- //
- this.cacheSizeTextbox.Location = new System.Drawing.Point(72, 113);
- this.cacheSizeTextbox.Name = "cacheSizeTextbox";
- this.cacheSizeTextbox.Size = new System.Drawing.Size(100, 21);
- this.cacheSizeTextbox.TabIndex = 6;
- this.cacheSizeTextbox.Text = "2000";
- this.cacheSizeTextbox.Leave += new System.EventHandler(this.cacheSizeTextbox_Leave);
- //
- // pageSizeLabel
- //
- pageSizeLabel.AutoSize = true;
- pageSizeLabel.Location = new System.Drawing.Point(13, 89);
- pageSizeLabel.Name = "pageSizeLabel";
- pageSizeLabel.Size = new System.Drawing.Size(53, 13);
- pageSizeLabel.TabIndex = 3;
- pageSizeLabel.Text = "Page Size";
- //
- // pageSizeTextBox
- //
- this.pageSizeTextBox.Location = new System.Drawing.Point(72, 86);
- this.pageSizeTextBox.Name = "pageSizeTextBox";
- this.pageSizeTextBox.Size = new System.Drawing.Size(100, 21);
- this.pageSizeTextBox.TabIndex = 4;
- this.pageSizeTextBox.Text = "1024";
- this.pageSizeTextBox.Leave += new System.EventHandler(this.pageSizeTextBox_Leave);
- //
- // fileTextBox
- //
- this.fileTextBox.Location = new System.Drawing.Point(6, 20);
- this.fileTextBox.Name = "fileTextBox";
- this.fileTextBox.Size = new System.Drawing.Size(294, 21);
- this.fileTextBox.TabIndex = 0;
- this.fileTextBox.Leave += new System.EventHandler(this.fileTextBox_Leave);
- //
- // browseButton
- //
- this.browseButton.Location = new System.Drawing.Point(6, 47);
- this.browseButton.Name = "browseButton";
- this.browseButton.Size = new System.Drawing.Size(75, 23);
- this.browseButton.TabIndex = 1;
- this.browseButton.Text = "&Browse ...";
- this.browseButton.UseVisualStyleBackColor = true;
- this.browseButton.Click += new System.EventHandler(this.browseButton_Click);
- //
- // newDatabase
- //
- this.newDatabase.Location = new System.Drawing.Point(87, 47);
- this.newDatabase.Name = "newDatabase";
- this.newDatabase.Size = new System.Drawing.Size(75, 23);
- this.newDatabase.TabIndex = 2;
- this.newDatabase.Text = "&New ...";
- this.newDatabase.UseVisualStyleBackColor = true;
- this.newDatabase.Click += new System.EventHandler(this.newDatabase_Click);
- //
- // syncGroup
- //
- syncGroup.Controls.Add(this.offRadioButton);
- syncGroup.Controls.Add(this.normalRadioButton);
- syncGroup.Controls.Add(this.fullRadioButton);
- syncGroup.Location = new System.Drawing.Point(204, 159);
- syncGroup.Name = "syncGroup";
- syncGroup.Size = new System.Drawing.Size(105, 98);
- syncGroup.TabIndex = 9;
- syncGroup.TabStop = false;
- syncGroup.Text = "Synchronization";
- //
- // offRadioButton
- //
- this.offRadioButton.AutoSize = true;
- this.offRadioButton.Location = new System.Drawing.Point(6, 66);
- this.offRadioButton.Name = "offRadioButton";
- this.offRadioButton.Size = new System.Drawing.Size(41, 17);
- this.offRadioButton.TabIndex = 2;
- this.offRadioButton.Text = "Off";
- this.offRadioButton.UseVisualStyleBackColor = true;
- this.offRadioButton.CheckedChanged += new System.EventHandler(this.sync_Changed);
- //
- // normalRadioButton
- //
- this.normalRadioButton.AutoSize = true;
- this.normalRadioButton.Checked = true;
- this.normalRadioButton.Location = new System.Drawing.Point(6, 43);
- this.normalRadioButton.Name = "normalRadioButton";
- this.normalRadioButton.Size = new System.Drawing.Size(58, 17);
- this.normalRadioButton.TabIndex = 1;
- this.normalRadioButton.TabStop = true;
- this.normalRadioButton.Text = "Normal";
- this.normalRadioButton.UseVisualStyleBackColor = true;
- this.normalRadioButton.CheckedChanged += new System.EventHandler(this.sync_Changed);
- //
- // fullRadioButton
- //
- this.fullRadioButton.AutoSize = true;
- this.fullRadioButton.Location = new System.Drawing.Point(6, 20);
- this.fullRadioButton.Name = "fullRadioButton";
- this.fullRadioButton.Size = new System.Drawing.Size(41, 17);
- this.fullRadioButton.TabIndex = 0;
- this.fullRadioButton.Text = "Full";
- this.fullRadioButton.UseVisualStyleBackColor = true;
- this.fullRadioButton.CheckedChanged += new System.EventHandler(this.sync_Changed);
- //
- // julianRadioButton
- //
- this.julianRadioButton.AutoSize = true;
- this.julianRadioButton.Location = new System.Drawing.Point(7, 44);
- this.julianRadioButton.Name = "julianRadioButton";
- this.julianRadioButton.Size = new System.Drawing.Size(74, 17);
- this.julianRadioButton.TabIndex = 2;
- this.julianRadioButton.TabStop = true;
- this.julianRadioButton.Text = "Julian Day";
- this.julianRadioButton.UseVisualStyleBackColor = true;
- this.julianRadioButton.CheckedChanged += new System.EventHandler(this.datetime_Changed);
- //
- // SQLiteConnectionUIControl
- //
- this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
- this.Controls.Add(syncGroup);
- this.Controls.Add(databaseGroup);
- this.Controls.Add(dateTimeGroup);
- this.Controls.Add(encodingGroup);
- this.Controls.Add(securityGroup);
- this.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.Name = "SQLiteConnectionUIControl";
- this.Size = new System.Drawing.Size(312, 322);
- securityGroup.ResumeLayout(false);
- securityGroup.PerformLayout();
- encodingGroup.ResumeLayout(false);
- encodingGroup.PerformLayout();
- dateTimeGroup.ResumeLayout(false);
- dateTimeGroup.PerformLayout();
- databaseGroup.ResumeLayout(false);
- databaseGroup.PerformLayout();
- syncGroup.ResumeLayout(false);
- syncGroup.PerformLayout();
- this.ResumeLayout(false);
-
- }
-
- #endregion
-
- private System.Windows.Forms.TextBox fileTextBox;
- private System.Windows.Forms.Button browseButton;
- private System.Windows.Forms.Button newDatabase;
- private System.Windows.Forms.TextBox passwordTextBox;
- private System.Windows.Forms.RadioButton utf16RadioButton;
- private System.Windows.Forms.RadioButton utf8RadioButton;
- private System.Windows.Forms.RadioButton ticksRadioButton;
- private System.Windows.Forms.RadioButton iso8601RadioButton;
- private System.Windows.Forms.TextBox pageSizeTextBox;
- private System.Windows.Forms.TextBox cacheSizeTextbox;
- private System.Windows.Forms.RadioButton offRadioButton;
- private System.Windows.Forms.RadioButton normalRadioButton;
- private System.Windows.Forms.RadioButton fullRadioButton;
- private System.Windows.Forms.RadioButton julianRadioButton;
- }
+ ********************************************************/
+
+namespace SQLite.Designer
+{
+ partial class SQLiteConnectionUIControl
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ System.Windows.Forms.Label labelPassword;
+ System.Windows.Forms.GroupBox securityGroup;
+ System.Windows.Forms.GroupBox encodingGroup;
+ System.Windows.Forms.GroupBox dateTimeGroup;
+ System.Windows.Forms.GroupBox databaseGroup;
+ System.Windows.Forms.Label cacheSizeLabel;
+ System.Windows.Forms.Label pageSizeLabel;
+ System.Windows.Forms.GroupBox syncGroup;
+ System.Windows.Forms.GroupBox providerGroup;
+ this.passwordTextBox = new System.Windows.Forms.TextBox();
+ this.utf16RadioButton = new System.Windows.Forms.RadioButton();
+ this.utf8RadioButton = new System.Windows.Forms.RadioButton();
+ this.ticksRadioButton = new System.Windows.Forms.RadioButton();
+ this.iso8601RadioButton = new System.Windows.Forms.RadioButton();
+ this.cacheSizeTextbox = new System.Windows.Forms.TextBox();
+ this.pageSizeTextBox = new System.Windows.Forms.TextBox();
+ this.fileTextBox = new System.Windows.Forms.TextBox();
+ this.browseButton = new System.Windows.Forms.Button();
+ this.newDatabase = new System.Windows.Forms.Button();
+ this.offRadioButton = new System.Windows.Forms.RadioButton();
+ this.normalRadioButton = new System.Windows.Forms.RadioButton();
+ this.fullRadioButton = new System.Windows.Forms.RadioButton();
+ this.julianRadioButton = new System.Windows.Forms.RadioButton();
+ this.providerComboBox = new System.Windows.Forms.ComboBox();
+ labelPassword = new System.Windows.Forms.Label();
+ securityGroup = new System.Windows.Forms.GroupBox();
+ encodingGroup = new System.Windows.Forms.GroupBox();
+ dateTimeGroup = new System.Windows.Forms.GroupBox();
+ databaseGroup = new System.Windows.Forms.GroupBox();
+ cacheSizeLabel = new System.Windows.Forms.Label();
+ pageSizeLabel = new System.Windows.Forms.Label();
+ syncGroup = new System.Windows.Forms.GroupBox();
+ providerGroup = new System.Windows.Forms.GroupBox();
+ securityGroup.SuspendLayout();
+ encodingGroup.SuspendLayout();
+ dateTimeGroup.SuspendLayout();
+ databaseGroup.SuspendLayout();
+ syncGroup.SuspendLayout();
+ providerGroup.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // labelPassword
+ //
+ labelPassword.AutoSize = true;
+ labelPassword.Location = new System.Drawing.Point(6, 23);
+ labelPassword.Name = "labelPassword";
+ labelPassword.Size = new System.Drawing.Size(53, 13);
+ labelPassword.TabIndex = 0;
+ labelPassword.Text = "Password";
+ //
+ // securityGroup
+ //
+ securityGroup.Controls.Add(this.passwordTextBox);
+ securityGroup.Controls.Add(labelPassword);
+ securityGroup.Location = new System.Drawing.Point(3, 263);
+ securityGroup.Name = "securityGroup";
+ securityGroup.Size = new System.Drawing.Size(306, 56);
+ securityGroup.TabIndex = 10;
+ securityGroup.TabStop = false;
+ securityGroup.Text = "Encryption";
+ //
+ // passwordTextBox
+ //
+ this.passwordTextBox.Location = new System.Drawing.Point(65, 20);
+ this.passwordTextBox.Name = "passwordTextBox";
+ this.passwordTextBox.Size = new System.Drawing.Size(235, 21);
+ this.passwordTextBox.TabIndex = 1;
+ this.passwordTextBox.UseSystemPasswordChar = true;
+ this.passwordTextBox.Leave += new System.EventHandler(this.passwordTextBox_Leave);
+ //
+ // encodingGroup
+ //
+ encodingGroup.Controls.Add(this.utf16RadioButton);
+ encodingGroup.Controls.Add(this.utf8RadioButton);
+ encodingGroup.Location = new System.Drawing.Point(3, 159);
+ encodingGroup.Name = "encodingGroup";
+ encodingGroup.Size = new System.Drawing.Size(75, 98);
+ encodingGroup.TabIndex = 7;
+ encodingGroup.TabStop = false;
+ encodingGroup.Text = "Encoding";
+ //
+ // utf16RadioButton
+ //
+ this.utf16RadioButton.AutoSize = true;
+ this.utf16RadioButton.Location = new System.Drawing.Point(6, 44);
+ this.utf16RadioButton.Name = "utf16RadioButton";
+ this.utf16RadioButton.Size = new System.Drawing.Size(60, 17);
+ this.utf16RadioButton.TabIndex = 1;
+ this.utf16RadioButton.TabStop = true;
+ this.utf16RadioButton.Text = "UTF-16";
+ this.utf16RadioButton.UseVisualStyleBackColor = true;
+ this.utf16RadioButton.CheckedChanged += new System.EventHandler(this.encoding_Changed);
+ //
+ // utf8RadioButton
+ //
+ this.utf8RadioButton.AutoSize = true;
+ this.utf8RadioButton.Checked = true;
+ this.utf8RadioButton.Location = new System.Drawing.Point(7, 21);
+ this.utf8RadioButton.Name = "utf8RadioButton";
+ this.utf8RadioButton.Size = new System.Drawing.Size(54, 17);
+ this.utf8RadioButton.TabIndex = 0;
+ this.utf8RadioButton.TabStop = true;
+ this.utf8RadioButton.Text = "UTF-8";
+ this.utf8RadioButton.UseVisualStyleBackColor = true;
+ this.utf8RadioButton.CheckedChanged += new System.EventHandler(this.encoding_Changed);
+ //
+ // dateTimeGroup
+ //
+ dateTimeGroup.Controls.Add(this.julianRadioButton);
+ dateTimeGroup.Controls.Add(this.ticksRadioButton);
+ dateTimeGroup.Controls.Add(this.iso8601RadioButton);
+ dateTimeGroup.Location = new System.Drawing.Point(84, 159);
+ dateTimeGroup.Name = "dateTimeGroup";
+ dateTimeGroup.Size = new System.Drawing.Size(113, 98);
+ dateTimeGroup.TabIndex = 8;
+ dateTimeGroup.TabStop = false;
+ dateTimeGroup.Text = "Date/Time Format";
+ //
+ // ticksRadioButton
+ //
+ this.ticksRadioButton.AutoSize = true;
+ this.ticksRadioButton.Location = new System.Drawing.Point(7, 66);
+ this.ticksRadioButton.Name = "ticksRadioButton";
+ this.ticksRadioButton.Size = new System.Drawing.Size(48, 17);
+ this.ticksRadioButton.TabIndex = 1;
+ this.ticksRadioButton.TabStop = true;
+ this.ticksRadioButton.Text = "Ticks";
+ this.ticksRadioButton.UseVisualStyleBackColor = true;
+ this.ticksRadioButton.CheckedChanged += new System.EventHandler(this.datetime_Changed);
+ //
+ // iso8601RadioButton
+ //
+ this.iso8601RadioButton.AutoSize = true;
+ this.iso8601RadioButton.Checked = true;
+ this.iso8601RadioButton.Location = new System.Drawing.Point(7, 21);
+ this.iso8601RadioButton.Name = "iso8601RadioButton";
+ this.iso8601RadioButton.Size = new System.Drawing.Size(71, 17);
+ this.iso8601RadioButton.TabIndex = 0;
+ this.iso8601RadioButton.TabStop = true;
+ this.iso8601RadioButton.Text = "ISO-8601";
+ this.iso8601RadioButton.UseVisualStyleBackColor = true;
+ this.iso8601RadioButton.CheckedChanged += new System.EventHandler(this.datetime_Changed);
+ //
+ // databaseGroup
+ //
+ databaseGroup.Controls.Add(cacheSizeLabel);
+ databaseGroup.Controls.Add(this.cacheSizeTextbox);
+ databaseGroup.Controls.Add(pageSizeLabel);
+ databaseGroup.Controls.Add(this.pageSizeTextBox);
+ databaseGroup.Controls.Add(this.fileTextBox);
+ databaseGroup.Controls.Add(this.browseButton);
+ databaseGroup.Controls.Add(this.newDatabase);
+ databaseGroup.Location = new System.Drawing.Point(3, 3);
+ databaseGroup.Name = "databaseGroup";
+ databaseGroup.Size = new System.Drawing.Size(306, 150);
+ databaseGroup.TabIndex = 8;
+ databaseGroup.TabStop = false;
+ databaseGroup.Text = "Database";
+ //
+ // cacheSizeLabel
+ //
+ cacheSizeLabel.AutoSize = true;
+ cacheSizeLabel.Location = new System.Drawing.Point(7, 116);
+ cacheSizeLabel.Name = "cacheSizeLabel";
+ cacheSizeLabel.Size = new System.Drawing.Size(59, 13);
+ cacheSizeLabel.TabIndex = 5;
+ cacheSizeLabel.Text = "Cache Size";
+ //
+ // cacheSizeTextbox
+ //
+ this.cacheSizeTextbox.Location = new System.Drawing.Point(72, 113);
+ this.cacheSizeTextbox.Name = "cacheSizeTextbox";
+ this.cacheSizeTextbox.Size = new System.Drawing.Size(100, 21);
+ this.cacheSizeTextbox.TabIndex = 6;
+ this.cacheSizeTextbox.Text = "2000";
+ this.cacheSizeTextbox.Leave += new System.EventHandler(this.cacheSizeTextbox_Leave);
+ //
+ // pageSizeLabel
+ //
+ pageSizeLabel.AutoSize = true;
+ pageSizeLabel.Location = new System.Drawing.Point(13, 89);
+ pageSizeLabel.Name = "pageSizeLabel";
+ pageSizeLabel.Size = new System.Drawing.Size(53, 13);
+ pageSizeLabel.TabIndex = 3;
+ pageSizeLabel.Text = "Page Size";
+ //
+ // pageSizeTextBox
+ //
+ this.pageSizeTextBox.Location = new System.Drawing.Point(72, 86);
+ this.pageSizeTextBox.Name = "pageSizeTextBox";
+ this.pageSizeTextBox.Size = new System.Drawing.Size(100, 21);
+ this.pageSizeTextBox.TabIndex = 4;
+ this.pageSizeTextBox.Text = "1024";
+ this.pageSizeTextBox.Leave += new System.EventHandler(this.pageSizeTextBox_Leave);
+ //
+ // fileTextBox
+ //
+ this.fileTextBox.Location = new System.Drawing.Point(6, 20);
+ this.fileTextBox.Name = "fileTextBox";
+ this.fileTextBox.Size = new System.Drawing.Size(294, 21);
+ this.fileTextBox.TabIndex = 0;
+ this.fileTextBox.Leave += new System.EventHandler(this.fileTextBox_Leave);
+ //
+ // browseButton
+ //
+ this.browseButton.Location = new System.Drawing.Point(6, 47);
+ this.browseButton.Name = "browseButton";
+ this.browseButton.Size = new System.Drawing.Size(75, 23);
+ this.browseButton.TabIndex = 1;
+ this.browseButton.Text = "&Browse ...";
+ this.browseButton.UseVisualStyleBackColor = true;
+ this.browseButton.Click += new System.EventHandler(this.browseButton_Click);
+ //
+ // newDatabase
+ //
+ this.newDatabase.Location = new System.Drawing.Point(87, 47);
+ this.newDatabase.Name = "newDatabase";
+ this.newDatabase.Size = new System.Drawing.Size(75, 23);
+ this.newDatabase.TabIndex = 2;
+ this.newDatabase.Text = "&New ...";
+ this.newDatabase.UseVisualStyleBackColor = true;
+ this.newDatabase.Click += new System.EventHandler(this.newDatabase_Click);
+ //
+ // syncGroup
+ //
+ syncGroup.Controls.Add(this.offRadioButton);
+ syncGroup.Controls.Add(this.normalRadioButton);
+ syncGroup.Controls.Add(this.fullRadioButton);
+ syncGroup.Location = new System.Drawing.Point(204, 159);
+ syncGroup.Name = "syncGroup";
+ syncGroup.Size = new System.Drawing.Size(105, 98);
+ syncGroup.TabIndex = 9;
+ syncGroup.TabStop = false;
+ syncGroup.Text = "Synchronization";
+ //
+ // offRadioButton
+ //
+ this.offRadioButton.AutoSize = true;
+ this.offRadioButton.Location = new System.Drawing.Point(6, 66);
+ this.offRadioButton.Name = "offRadioButton";
+ this.offRadioButton.Size = new System.Drawing.Size(41, 17);
+ this.offRadioButton.TabIndex = 2;
+ this.offRadioButton.Text = "Off";
+ this.offRadioButton.UseVisualStyleBackColor = true;
+ this.offRadioButton.CheckedChanged += new System.EventHandler(this.sync_Changed);
+ //
+ // normalRadioButton
+ //
+ this.normalRadioButton.AutoSize = true;
+ this.normalRadioButton.Checked = true;
+ this.normalRadioButton.Location = new System.Drawing.Point(6, 43);
+ this.normalRadioButton.Name = "normalRadioButton";
+ this.normalRadioButton.Size = new System.Drawing.Size(58, 17);
+ this.normalRadioButton.TabIndex = 1;
+ this.normalRadioButton.TabStop = true;
+ this.normalRadioButton.Text = "Normal";
+ this.normalRadioButton.UseVisualStyleBackColor = true;
+ this.normalRadioButton.CheckedChanged += new System.EventHandler(this.sync_Changed);
+ //
+ // fullRadioButton
+ //
+ this.fullRadioButton.AutoSize = true;
+ this.fullRadioButton.Location = new System.Drawing.Point(6, 20);
+ this.fullRadioButton.Name = "fullRadioButton";
+ this.fullRadioButton.Size = new System.Drawing.Size(41, 17);
+ this.fullRadioButton.TabIndex = 0;
+ this.fullRadioButton.Text = "Full";
+ this.fullRadioButton.UseVisualStyleBackColor = true;
+ this.fullRadioButton.CheckedChanged += new System.EventHandler(this.sync_Changed);
+ //
+ // julianRadioButton
+ //
+ this.julianRadioButton.AutoSize = true;
+ this.julianRadioButton.Location = new System.Drawing.Point(7, 44);
+ this.julianRadioButton.Name = "julianRadioButton";
+ this.julianRadioButton.Size = new System.Drawing.Size(74, 17);
+ this.julianRadioButton.TabIndex = 2;
+ this.julianRadioButton.TabStop = true;
+ this.julianRadioButton.Text = "Julian Day";
+ this.julianRadioButton.UseVisualStyleBackColor = true;
+ this.julianRadioButton.CheckedChanged += new System.EventHandler(this.datetime_Changed);
+ //
+ // providerGroup
+ //
+ providerGroup.Controls.Add(this.providerComboBox);
+ providerGroup.Location = new System.Drawing.Point(3, 325);
+ providerGroup.Name = "providerGroup";
+ providerGroup.Size = new System.Drawing.Size(306, 56);
+ providerGroup.TabIndex = 11;
+ providerGroup.TabStop = false;
+ providerGroup.Text = "Provider";
+ //
+ // providerComboBox
+ //
+ this.providerComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.providerComboBox.FormattingEnabled = true;
+ this.providerComboBox.Location = new System.Drawing.Point(6, 20);
+ this.providerComboBox.Name = "providerComboBox";
+ this.providerComboBox.Size = new System.Drawing.Size(294, 21);
+ this.providerComboBox.TabIndex = 0;
+ this.providerComboBox.SelectedIndexChanged += new System.EventHandler(this.provider_Changed);
+ //
+ // SQLiteConnectionUIControl
+ //
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+ this.Controls.Add(providerGroup);
+ this.Controls.Add(syncGroup);
+ this.Controls.Add(databaseGroup);
+ this.Controls.Add(dateTimeGroup);
+ this.Controls.Add(encodingGroup);
+ this.Controls.Add(securityGroup);
+ this.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.Name = "SQLiteConnectionUIControl";
+ this.Size = new System.Drawing.Size(312, 386);
+ securityGroup.ResumeLayout(false);
+ securityGroup.PerformLayout();
+ encodingGroup.ResumeLayout(false);
+ encodingGroup.PerformLayout();
+ dateTimeGroup.ResumeLayout(false);
+ dateTimeGroup.PerformLayout();
+ databaseGroup.ResumeLayout(false);
+ databaseGroup.PerformLayout();
+ syncGroup.ResumeLayout(false);
+ syncGroup.PerformLayout();
+ providerGroup.ResumeLayout(false);
+ providerGroup.PerformLayout();
+ this.ResumeLayout(false);
+ }
+ #endregion
+
+ private System.Windows.Forms.TextBox fileTextBox;
+ private System.Windows.Forms.Button browseButton;
+ private System.Windows.Forms.Button newDatabase;
+ private System.Windows.Forms.TextBox passwordTextBox;
+ private System.Windows.Forms.RadioButton utf16RadioButton;
+ private System.Windows.Forms.RadioButton utf8RadioButton;
+ private System.Windows.Forms.RadioButton ticksRadioButton;
+ private System.Windows.Forms.RadioButton iso8601RadioButton;
+ private System.Windows.Forms.TextBox pageSizeTextBox;
+ private System.Windows.Forms.TextBox cacheSizeTextbox;
+ private System.Windows.Forms.RadioButton offRadioButton;
+ private System.Windows.Forms.RadioButton normalRadioButton;
+ private System.Windows.Forms.RadioButton fullRadioButton;
+ private System.Windows.Forms.RadioButton julianRadioButton;
+ private System.Windows.Forms.ComboBox providerComboBox;
+ }
}
Index: SQLite.Designer/SQLiteConnectionUIControl.cs
==================================================================
--- SQLite.Designer/SQLiteConnectionUIControl.cs
+++ SQLite.Designer/SQLiteConnectionUIControl.cs
@@ -1,24 +1,19 @@
/********************************************************
* ADO.NET 2.0 Data Provider for SQLite Version 3.X
* Written by Robert Simpson (robert@blackcastlesoft.com)
- *
+ *
* Released to the public domain, use at your own risk!
********************************************************/
namespace SQLite.Designer
{
using System;
- using System.Collections.Generic;
using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.Text;
using System.Windows.Forms;
using System.Globalization;
using Microsoft.VisualStudio.Data;
- using Microsoft.Win32;
///
/// Provides a UI to edit/create SQLite database connections
///
[ToolboxItem(false)]
@@ -25,10 +20,11 @@
public partial class SQLiteConnectionUIControl : DataConnectionUIControl
{
public SQLiteConnectionUIControl()
{
InitializeComponent();
+ SQLiteOptions.AddProviderNames(providerComboBox.Items);
}
private void browseButton_Click(object sender, EventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
@@ -55,51 +51,75 @@
#region IDataConnectionUIControl Members
public override void LoadProperties()
{
+ SQLiteOptions.SelectProviderName(providerComboBox);
+
+ fileTextBox.Text = String.Empty;
+ passwordTextBox.Text = String.Empty;
+
+ if (ConnectionProperties == null)
+ return;
+
if (ConnectionProperties.Contains("data source"))
fileTextBox.Text = ConnectionProperties["data source"] as string;
- else
- fileTextBox.Text = String.Empty;
if (ConnectionProperties.Contains("password"))
passwordTextBox.Text = ConnectionProperties["password"] as string;
- else
- passwordTextBox.Text = String.Empty;
}
#endregion
private void passwordTextBox_Leave(object sender, EventArgs e)
{
+ if (ConnectionProperties == null)
+ return;
+
if (String.IsNullOrEmpty(passwordTextBox.Text))
ConnectionProperties.Remove("password");
else
ConnectionProperties["password"] = passwordTextBox.Text;
}
private void encoding_Changed(object sender, EventArgs e)
{
+ if (ConnectionProperties == null)
+ return;
+
if (utf8RadioButton.Checked == true)
ConnectionProperties.Remove("useutf16encoding");
else
ConnectionProperties["useutf16encoding"] = utf16RadioButton.Checked;
}
private void datetime_Changed(object sender, EventArgs e)
{
+ if (ConnectionProperties == null)
+ return;
+
if (iso8601RadioButton.Checked == true)
ConnectionProperties.Remove("datetimeformat");
else if (ticksRadioButton.Checked == true)
ConnectionProperties["datetimeformat"] = "Ticks";
else
ConnectionProperties["datetimeformat"] = "JulianDay";
}
+
+ private void provider_Changed(object sender, EventArgs e)
+ {
+ object item = providerComboBox.SelectedItem;
+
+ if (item != null)
+ SQLiteOptions.SetProviderName(item.ToString());
+ }
private void sync_Changed(object sender, EventArgs e)
{
+ if (ConnectionProperties == null)
+ return;
+
string sync = "Normal";
if (fullRadioButton.Checked == true) sync = "Full";
else if (offRadioButton.Checked == true) sync = "Off";
if (sync == "Normal")
@@ -108,21 +128,30 @@
ConnectionProperties["synchronous"] = sync;
}
private void pageSizeTextBox_Leave(object sender, EventArgs e)
{
+ if (ConnectionProperties == null)
+ return;
+
int n = Convert.ToInt32(pageSizeTextBox.Text, CultureInfo.CurrentCulture);
ConnectionProperties["page size"] = n;
}
private void cacheSizeTextbox_Leave(object sender, EventArgs e)
{
+ if (ConnectionProperties == null)
+ return;
+
int n = Convert.ToInt32(cacheSizeTextbox.Text, CultureInfo.CurrentCulture);
ConnectionProperties["cache size"] = n;
}
private void fileTextBox_Leave(object sender, EventArgs e)
{
+ if (ConnectionProperties == null)
+ return;
+
ConnectionProperties["data source"] = fileTextBox.Text;
}
}
}
Index: SQLite.Designer/SQLiteConnectionUIControl.resx
==================================================================
--- SQLite.Designer/SQLiteConnectionUIControl.resx
+++ SQLite.Designer/SQLiteConnectionUIControl.resx
@@ -1,144 +1,147 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- False
-
-
- False
-
-
- False
-
-
- False
-
-
- False
-
-
- False
-
-
- False
-
-
- False
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ False
+
+
+ False
+
+
+ False
+
+
+ False
+
+
+ False
+
+
+ False
+
+
+ False
+
+
+ False
+
+
+ False
+
Index: SQLite.Designer/SQLiteDataAdapterToolboxItem.cs
==================================================================
--- SQLite.Designer/SQLiteDataAdapterToolboxItem.cs
+++ SQLite.Designer/SQLiteDataAdapterToolboxItem.cs
@@ -61,11 +61,11 @@
///
/// The designer host
/// The components created by this toolbox item
protected override IComponent[] CreateComponentsCore(IDesignerHost host)
{
- DbProviderFactory fact = DbProviderFactories.GetFactory("System.Data.SQLite");
+ DbProviderFactory fact = DbProviderFactories.GetFactory(SQLiteOptions.GetProviderName());
DbDataAdapter dataAdapter = fact.CreateDataAdapter();
IContainer container = host.Container;
using (DbCommand adapterCommand = fact.CreateCommand())
Index: SQLite.Designer/SQLiteDataConnectionSupport.cs
==================================================================
--- SQLite.Designer/SQLiteDataConnectionSupport.cs
+++ SQLite.Designer/SQLiteDataConnectionSupport.cs
@@ -21,11 +21,11 @@
private SQLiteDataViewSupport _dataViewSupport;
private SQLiteDataObjectSupport _dataObjectSupport;
private SQLiteDataObjectIdentifierResolver _dataObjectIdentifierResolver;
public SQLiteDataConnectionSupport()
- : base("System.Data.SQLite")
+ : base(SQLiteOptions.GetProviderName())
{
}
protected override DataSourceInformation CreateDataSourceInformation()
{
ADDED SQLite.Designer/SQLiteOptions.cs
Index: SQLite.Designer/SQLiteOptions.cs
==================================================================
--- /dev/null
+++ SQLite.Designer/SQLiteOptions.cs
@@ -0,0 +1,585 @@
+/********************************************************
+ * 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;
+using System.Collections.Generic;
+using System.Data.Common;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Windows.Forms;
+using Microsoft.VisualStudio.Shell;
+
+namespace SQLite.Designer
+{
+ ///
+ /// This class keeps track of the options configured on a per-solution file
+ /// basis pertaining to the System.Data.SQLite design-time components.
+ ///
+ [Guid("5cf5656c-ccbe-4162-8780-0cbee936b90c")]
+ internal static class SQLiteOptions
+ {
+ #region Private Constants
+ ///
+ /// This is the name of the setting containing the configured ADO.NET
+ /// provider name.
+ ///
+ private static readonly string ProviderNameKey = "ProviderName";
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This is the name of the environment variable that will be checked
+ /// prior to setting the initial default value for the configured
+ /// ADO.NET provider name, thus allowing the default value to be
+ /// overridden via the environment.
+ ///
+ private static readonly string ProviderNameEnvVarName =
+ "ProviderName_SQLiteDesigner";
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This is the legacy provider name used by the System.Data.SQLite
+ /// design-time components. It is also the default value for the
+ /// associated option key.
+ ///
+ private static readonly string DefaultProviderName = "System.Data.SQLite";
+
+ ///////////////////////////////////////////////////////////////////////
+
+#if NET_40 || NET_45 || NET_451
+ ///
+ /// This is the provider name used when Entity Framework 6.x support is
+ /// required for use with the System.Data.SQLite design-time components.
+ /// This provider name is only available when this class is compiled for
+ /// the .NET Framework 4.0 or later.
+ ///
+ private static readonly string Ef6ProviderName = "System.Data.SQLite.EF6";
+#endif
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Private Static Data
+ ///
+ /// This is used to synchronize access to the static dictionary of
+ /// options (just below).
+ ///
+ private static readonly object syncRoot = new object();
+
+ ///
+ /// This dictionary contains the key/value pairs representing the
+ /// per-solution options configured for the current solution. When
+ /// a new solution is loaded by Visual Studio, this dictionary must
+ /// be reset.
+ ///
+ private static Dictionary options;
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Private Static Methods
+ ///
+ /// This method initializes (or resets) the per-solution configuration
+ /// options.
+ ///
+ ///
+ /// Non-zero to reset the options if they are already initialized.
+ /// When this method is called from the
+ /// constructor, this value should always be true.
+ ///
+ private static void Initialize(
+ bool reset
+ )
+ {
+ lock (syncRoot)
+ {
+ if (options != null)
+ options.Clear();
+ else
+ options = new Dictionary();
+
+ string key = ProviderNameKey;
+ string value = Environment.GetEnvironmentVariable(
+ ProviderNameEnvVarName);
+
+ if (IsValidValue(key, value))
+ options[key] = value;
+ else
+ options[key] = DefaultProviderName;
+ }
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Public Static Methods
+ #region Provider Name Handling
+ ///
+ /// This method determines the name of the ADO.NET provider for the
+ /// System.Data.SQLite design-time components to use.
+ ///
+ ///
+ /// The configured ADO.NET provider name for System.Data.SQLite -OR-
+ /// the default ADO.NET provider name for System.Data.SQLite in the
+ /// event of any failure. This method cannot return null.
+ ///
+ public static string GetProviderName()
+ {
+ return GetProviderName(DefaultProviderName);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method determines the name of the ADO.NET provider for the
+ /// System.Data.SQLite design-time components to use.
+ ///
+ ///
+ /// The value to return from this method if the name of the ADO.NET
+ /// provider is unavailable -OR- cannot be determined.
+ ///
+ ///
+ /// The configured ADO.NET provider name for System.Data.SQLite -OR-
+ /// the default ADO.NET provider name for System.Data.SQLite in the
+ /// event of any failure.
+ ///
+ private static string GetProviderName(
+ string @default
+ )
+ {
+ string key = ProviderNameKey;
+ string value;
+
+ if (GetValue(key, out value) && IsValidValue(key, value))
+ return value;
+
+ return @default;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method attempts to set the name of the ADO.NET provider for
+ /// the System.Data.SQLite design-time components to use.
+ ///
+ ///
+ /// The ADO.NET provider name to use.
+ ///
+ ///
+ /// Non-zero upon success; otherwise, zero. All ADO.NET provider names
+ /// unknown to this class are rejected.
+ ///
+ public static bool SetProviderName(
+ string value
+ )
+ {
+ string key = ProviderNameKey;
+
+ if (IsValidValue(key, value))
+ return SetValue(key, value);
+
+ return false;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region User-Interface Handling
+ ///
+ /// This method attempts to select the configured ADO.NET provider name
+ /// in the specified . This method will only
+ /// work correctly when called from the user-interface thread.
+ ///
+ ///
+ /// The object where the selection is to be
+ /// modified.
+ ///
+ ///
+ /// Non-zero upon success; otherwise, zero.
+ ///
+ public static bool SelectProviderName(
+ ComboBox comboBox
+ )
+ {
+ if (comboBox == null)
+ return false;
+
+ string value = GetProviderName(null);
+
+ for (int index = 0; index < comboBox.Items.Count; index++)
+ {
+ object item = comboBox.Items[index];
+
+ if (item == null)
+ continue;
+
+ if ((value == null) || String.Equals(
+ item.ToString(), value, StringComparison.Ordinal))
+ {
+ comboBox.SelectedIndex = index;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ private static bool CheckProviderName(
+ string name
+ )
+ {
+ DbProviderFactory dbProviderFactory = null;
+
+ try
+ {
+ dbProviderFactory = DbProviderFactories.GetFactory(
+ name); /* throw */
+
+ return (dbProviderFactory != null);
+ }
+ catch
+ {
+ // do nothing.
+ }
+ finally
+ {
+ if (dbProviderFactory != null)
+ {
+ IDisposable disposable = dbProviderFactory as IDisposable;
+
+ if (disposable != null)
+ {
+ disposable.Dispose();
+ disposable = null;
+ }
+
+ dbProviderFactory = null;
+ }
+ }
+
+ return false;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method populates the specified item
+ /// list with the recognized ADO.NET provider names. This method will
+ /// only work correctly when called from the user-interface thread.
+ ///
+ ///
+ /// The property value containing the
+ /// list of items to be modified. This value cannot be null.
+ ///
+ ///
+ /// The number of items actually added to the list, which may be zero.
+ ///
+ public static int AddProviderNames(
+ ComboBox.ObjectCollection items
+ )
+ {
+ int result = 0;
+
+ if (items == null)
+ return result;
+
+ IList names = new List();
+
+#if NET_40 || NET_45 || NET_451
+ names.Add(Ef6ProviderName);
+#endif
+
+ names.Add(DefaultProviderName);
+
+ foreach (string name in names)
+ {
+ if (CheckProviderName(name))
+ {
+ items.Add(name);
+ result++;
+ }
+ }
+
+ return result;
+ }
+ #endregion
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Hard-Coded Default Value Handling
+ ///
+ /// This method determines if the specified key/value pair represents
+ /// the default value for that option.
+ ///
+ ///
+ /// The name ("key") of the configuration option.
+ ///
+ ///
+ /// The value of the configuration option.
+ ///
+ ///
+ /// Non-zero if the key/value pair represents its default value.
+ ///
+ public static bool IsDefaultValue(
+ string key,
+ string value
+ )
+ {
+ if (String.Equals(
+ key, ProviderNameKey, StringComparison.Ordinal) &&
+ String.Equals(
+ value, DefaultProviderName, StringComparison.Ordinal))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method determines if the specified key/value pair is valid
+ /// and supported by this class.
+ ///
+ ///
+ /// The name ("key") of the configuration option.
+ ///
+ ///
+ /// The value of the configuration option.
+ ///
+ ///
+ /// Non-zero if the key/value pair represents a valid option key and
+ /// value supported by this class.
+ ///
+ public static bool IsValidValue(
+ string key,
+ string value
+ )
+ {
+ if (String.Equals(
+ key, ProviderNameKey, StringComparison.Ordinal) &&
+ (String.Equals(
+ value, DefaultProviderName, StringComparison.Ordinal)
+#if NET_40 || NET_45 || NET_451
+ || String.Equals(
+ value, Ef6ProviderName, StringComparison.Ordinal)
+#endif
+ ))
+ {
+ return true;
+ }
+
+ return false;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Core Option Handling
+ ///
+ /// This method returns the current list of option keys supported by
+ /// the System.Data.SQLite design-time components.
+ ///
+ ///
+ /// An of strings containing the list of
+ /// option keys supported by the System.Data.SQLite design-time
+ /// components -OR- null in the event of any failure.
+ ///
+ public static IEnumerable GetKeys(
+ bool reset
+ )
+ {
+ lock (syncRoot) /* TRANSACTIONAL */
+ {
+ Initialize(reset);
+
+ return (options != null) ?
+ new List(options.Keys) : null;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method determines if the specified option key is supported by
+ /// this class.
+ ///
+ ///
+ /// The name ("key") of the configuration option.
+ ///
+ ///
+ /// Non-zero if the specified option key is supported by this class.
+ ///
+ public static bool HaveKey(
+ string key
+ )
+ {
+ lock (syncRoot)
+ {
+ if ((key == null) || (options == null))
+ return false;
+
+ return options.ContainsKey(key);
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method attempts to query and return the current value of the
+ /// specified option key.
+ ///
+ ///
+ /// The name ("key") of the configuration option.
+ ///
+ ///
+ /// Upon success, the current value for the configuration option;
+ /// otherwise, null.
+ ///
+ ///
+ /// Non-zero for success; otherwise, zero.
+ ///
+ public static bool GetValue(
+ string key,
+ out string value
+ )
+ {
+ lock (syncRoot)
+ {
+ value = null;
+
+ if ((key == null) || (options == null))
+ return false;
+
+ if (options.TryGetValue(key, out value))
+ return true;
+
+ return false;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method attempts to set the value of the specified option key.
+ ///
+ ///
+ /// The name ("key") of the configuration option.
+ ///
+ ///
+ /// The new value for the configuration option.
+ ///
+ ///
+ /// Non-zero for success; otherwise, zero.
+ ///
+ public static bool SetValue(
+ string key,
+ string value
+ )
+ {
+ lock (syncRoot)
+ {
+ if ((key == null) || (options == null))
+ return false;
+
+ options[key] = value;
+ return true;
+ }
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Stream Handling
+ ///
+ /// This method attempts to read an option value from the specified
+ /// stream. The stream must be readable. After this method returns,
+ /// the stream may no longer be usable.
+ ///
+ ///
+ /// The stream to read the option value from.
+ ///
+ ///
+ /// Upon success, the read value for the configuration option;
+ /// otherwise, null.
+ ///
+ ///
+ /// Non-zero for success; otherwise, zero.
+ ///
+ public static bool ReadValue(
+ Stream stream,
+ out string value
+ )
+ {
+ value = null;
+
+ if ((stream == null) || !stream.CanRead)
+ return false;
+
+ try
+ {
+ using (StreamReader streamReader = new StreamReader(stream))
+ {
+ value = streamReader.ReadToEnd();
+ return true;
+ }
+ }
+ catch (Exception)
+ {
+ // do nothing.
+ }
+
+ return false;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method attempts to write an option value to the specified
+ /// stream. The stream must be writable. After this method returns,
+ /// the stream may no longer be usable.
+ ///
+ ///
+ /// The stream to write the option value to.
+ ///
+ ///
+ /// The option value to be written. This value may be null.
+ ///
+ ///
+ /// Non-zero for success; otherwise, zero.
+ ///
+ public static bool WriteValue(
+ Stream stream,
+ string value
+ )
+ {
+ if ((stream == null) || !stream.CanWrite)
+ return false;
+
+ try
+ {
+ using (StreamWriter streamWriter = new StreamWriter(stream))
+ {
+ streamWriter.Write(value);
+ return true;
+ }
+ }
+ catch (Exception)
+ {
+ // do nothing.
+ }
+
+ return false;
+ }
+ #endregion
+ #endregion
+ }
+}
Index: SQLite.Designer/SQLitePackage.cs
==================================================================
--- SQLite.Designer/SQLitePackage.cs
+++ SQLite.Designer/SQLitePackage.cs
@@ -1,15 +1,17 @@
/********************************************************
* ADO.NET 2.0 Data Provider for SQLite Version 3.X
* Written by Robert Simpson (robert@blackcastlesoft.com)
- *
+ *
* Released to the public domain, use at your own risk!
********************************************************/
namespace SQLite.Designer
{
using System;
+ using System.Collections.Generic;
+ using System.IO;
using Microsoft.VisualStudio.Shell;
using System.Runtime.InteropServices;
using System.ComponentModel.Design;
using Microsoft.VisualStudio.Shell.Interop;
@@ -20,10 +22,22 @@
[Guid("DCBE6C8D-0E57-4099-A183-98FF74C64D9C")]
internal sealed class SQLitePackage : Package
{
public SQLitePackage()
{
+ IEnumerable keys = SQLiteOptions.GetKeys(true);
+
+ if (keys != null)
+ {
+ foreach (string key in keys)
+ {
+ if (key == null)
+ continue;
+
+ AddOptionKey(key);
+ }
+ }
}
protected override void Initialize()
{
IServiceContainer sc = (IServiceContainer)this;
@@ -31,10 +45,47 @@
ToolboxInitialized += new EventHandler(SQLitePackage_ToolboxInitialized);
ToolboxUpgraded += new EventHandler(SQLitePackage_ToolboxUpgraded);
base.Initialize();
}
+
+ protected override void OnLoadOptions(string key, Stream stream)
+ {
+ if (SQLiteOptions.HaveKey(key))
+ {
+ string value;
+
+ if (SQLiteOptions.ReadValue(stream, out value) &&
+ SQLiteOptions.IsValidValue(key, value))
+ {
+ SQLiteOptions.SetValue(key, value);
+ }
+
+ return;
+ }
+
+ base.OnLoadOptions(key, stream);
+ }
+
+ protected override void OnSaveOptions(string key, Stream stream)
+ {
+ if (SQLiteOptions.HaveKey(key))
+ {
+ string value;
+
+ if (SQLiteOptions.GetValue(key, out value) &&
+ SQLiteOptions.IsValidValue(key, value) &&
+ !SQLiteOptions.IsDefaultValue(key, value))
+ {
+ SQLiteOptions.WriteValue(stream, value);
+ }
+
+ return;
+ }
+
+ base.OnSaveOptions(key, stream);
+ }
void SQLitePackage_ToolboxUpgraded(object sender, EventArgs e)
{
IVsToolbox vstbx = GetService(typeof(SVsToolbox)) as IVsToolbox;
Index: SQLite.Interop/props/sqlite3.props
==================================================================
--- SQLite.Interop/props/sqlite3.props
+++ SQLite.Interop/props/sqlite3.props
@@ -7,12 +7,12 @@
* Released to the public domain, use at your own risk!
*
-->
- 3.8.5
- 3,8,5
+ 3.8.6
+ 3,8,6
_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;SQLITE_THREADSAFE=1;SQLITE_USE_URI=1;SQLITE_ENABLE_COLUMN_METADATA=1;SQLITE_ENABLE_STAT4=1;SQLITE_ENABLE_FTS3=1;SQLITE_ENABLE_LOAD_EXTENSION=1;SQLITE_ENABLE_RTREE=1;SQLITE_SOUNDEX=1;SQLITE_ENABLE_MEMORY_MANAGEMENT=1
SQLITE_HAS_CODEC=1
SQLITE_OMIT_WAL=1
HAVE_ERRNO_H=1;SQLITE_MSVC_LOCALTIME_API=1
SQLITE_DEBUG=1;SQLITE_MEMDEBUG=1;SQLITE_ENABLE_EXPENSIVE_ASSERT=1
Index: SQLite.Interop/props/sqlite3.vsprops
==================================================================
--- SQLite.Interop/props/sqlite3.vsprops
+++ SQLite.Interop/props/sqlite3.vsprops
@@ -12,16 +12,16 @@
Version="8.00"
Name="sqlite3"
>
-** CorruptionFollowingBusyError wiki page for a discussion of why
-** this is important.
-**
** ^(There can only be a single busy handler defined for each
** [database connection]. Setting a new busy handler clears any
** previously set handler.)^ ^Note that calling [sqlite3_busy_timeout()]
-** will also set or clear the busy handler.
+** or evaluating [PRAGMA busy_timeout=N] will change the
+** busy handler and thus clear any previously set busy handler.
**
** The busy callback should not take any actions which modify the
-** database connection that invoked the busy handler. Any such actions
+** database connection that invoked the busy handler. In other words,
+** the busy handler is not reentrant. Any such actions
** result in undefined behavior.
**
** A busy handler must not close the database connection
** or [prepared statement] that invoked the busy handler.
*/
@@ -2221,19 +2206,21 @@
** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps
** for a specified amount of time when a table is locked. ^The handler
** will sleep multiple times until at least "ms" milliseconds of sleeping
** have accumulated. ^After at least "ms" milliseconds of sleeping,
** the handler returns 0 which causes [sqlite3_step()] to return
-** [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED].
+** [SQLITE_BUSY].
**
** ^Calling this routine with an argument less than or equal to zero
** turns off all busy handlers.
**
** ^(There can only be a single busy handler for a particular
** [database connection] any any given moment. If another busy handler
** was defined (using [sqlite3_busy_handler()]) prior to calling
** this routine, that other busy handler is cleared.)^
+**
+** See also: [PRAGMA busy_timeout]
*/
SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
/*
** CAPI3REF: Convenience Routines For Running Queries
@@ -2631,12 +2618,12 @@
** return either [SQLITE_OK] or one of these two constants in order
** to signal SQLite whether or not the action is permitted. See the
** [sqlite3_set_authorizer | authorizer documentation] for additional
** information.
**
-** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code]
-** from the [sqlite3_vtab_on_conflict()] interface.
+** Note that SQLITE_IGNORE is also used as a [conflict resolution mode]
+** returned from the [sqlite3_vtab_on_conflict()] interface.
*/
#define SQLITE_DENY 1 /* Abort the SQL statement with an error */
#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
/*
@@ -4818,10 +4805,17 @@
** the name of a folder (a.k.a. directory), then all temporary files
** created by SQLite when using a built-in [sqlite3_vfs | VFS]
** will be placed in that directory.)^ ^If this variable
** is a NULL pointer, then SQLite performs a search for an appropriate
** temporary file directory.
+**
+** Applications are strongly discouraged from using this global variable.
+** It is required to set a temporary folder on Windows Runtime (WinRT).
+** But for all other platforms, it is highly recommended that applications
+** neither read nor write this variable. This global variable is a relic
+** that exists for backwards compatibility of legacy applications and should
+** be avoided in new projects.
**
** It is not safe to read or modify this variable in more than one
** thread at a time. It is not safe to read or modify this variable
** if a [database connection] is being used at the same time in a separate
** thread.
@@ -4837,10 +4831,15 @@
** [sqlite3_malloc] and the pragma may attempt to free that memory
** using [sqlite3_free].
** Hence, if this variable is modified directly, either it should be
** made NULL or made to point to memory obtained from [sqlite3_malloc]
** or else the use of the [temp_store_directory pragma] should be avoided.
+** Except when requested by the [temp_store_directory pragma], SQLite
+** does not free the memory that sqlite3_temp_directory points to. If
+** the application wants that memory to be freed, it must do
+** so itself, taking care to only do so after all [database connection]
+** objects have been destroyed.
**
** Note to Windows Runtime users: The temporary directory must be set
** prior to calling [sqlite3_open] or [sqlite3_open_v2]. Otherwise, various
** features that require the use of temporary files may fail. Here is an
** example of how to do this using C++ with the Windows Runtime:
@@ -5971,14 +5970,16 @@
**
** - SQLITE_MUTEX_FAST
**
- SQLITE_MUTEX_RECURSIVE
**
- SQLITE_MUTEX_STATIC_MASTER
**
- SQLITE_MUTEX_STATIC_MEM
-**
- SQLITE_MUTEX_STATIC_MEM2
+**
- SQLITE_MUTEX_STATIC_OPEN
**
- SQLITE_MUTEX_STATIC_PRNG
**
- SQLITE_MUTEX_STATIC_LRU
-**
- SQLITE_MUTEX_STATIC_LRU2
+**
- SQLITE_MUTEX_STATIC_PMEM
+**
- SQLITE_MUTEX_STATIC_APP1
+**
- SQLITE_MUTEX_STATIC_APP2
**
)^
**
** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
** cause sqlite3_mutex_alloc() to create
** a new mutex. ^The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
@@ -6178,10 +6179,13 @@
#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */
#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */
#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
+#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */
+#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */
+#define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */
/*
** CAPI3REF: Retrieve the mutex for a database connection
**
** ^This interface returns a pointer the [sqlite3_mutex] object that
@@ -6273,11 +6277,12 @@
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
#define SQLITE_TESTCTRL_BYTEORDER 22
-#define SQLITE_TESTCTRL_LAST 22
+#define SQLITE_TESTCTRL_ISINIT 23
+#define SQLITE_TESTCTRL_LAST 23
/*
** CAPI3REF: SQLite Runtime Status
**
** ^This interface is used to retrieve runtime status information
@@ -7256,10 +7261,13 @@
** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism
** configured by this function.
**
** ^The [wal_autocheckpoint pragma] can be used to invoke this interface
** from SQL.
+**
+** ^Checkpoints initiated by this mechanism are
+** [sqlite3_wal_checkpoint_v2|PASSIVE].
**
** ^Every new [database connection] defaults to having the auto-checkpoint
** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT]
** pages. The use of this interface
** is only necessary if the default setting is found to be suboptimal
@@ -7273,10 +7281,14 @@
** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X
** on [database connection] D to be [checkpointed]. ^If X is NULL or an
** empty string, then a checkpoint is run on all databases of
** connection D. ^If the database connection D is not in
** [WAL | write-ahead log mode] then this interface is a harmless no-op.
+** ^The [sqlite3_wal_checkpoint(D,X)] interface initiates a
+** [sqlite3_wal_checkpoint_v2|PASSIVE] checkpoint.
+** Use the [sqlite3_wal_checkpoint_v2()] interface to get a FULL
+** or RESET checkpoint.
**
** ^The [wal_checkpoint pragma] can be used to invoke this interface
** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the
** [wal_autocheckpoint pragma] can be used to cause this interface to be
** run whenever the WAL reaches a certain size threshold.
@@ -7295,22 +7307,25 @@
**
** - SQLITE_CHECKPOINT_PASSIVE
-
** Checkpoint as many frames as possible without waiting for any database
** readers or writers to finish. Sync the db file if all frames in the log
** are checkpointed. This mode is the same as calling
-** sqlite3_wal_checkpoint(). The busy-handler callback is never invoked.
+** sqlite3_wal_checkpoint(). The [sqlite3_busy_handler|busy-handler callback]
+** is never invoked.
**
**
- SQLITE_CHECKPOINT_FULL
-
-** This mode blocks (calls the busy-handler callback) until there is no
+** This mode blocks (it invokes the
+** [sqlite3_busy_handler|busy-handler callback]) until there is no
** database writer and all readers are reading from the most recent database
** snapshot. It then checkpoints all frames in the log file and syncs the
** database file. This call blocks database writers while it is running,
** but not database readers.
**
**
- SQLITE_CHECKPOINT_RESTART
-
** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after
-** checkpointing the log file it blocks (calls the busy-handler callback)
+** checkpointing the log file it blocks (calls the
+** [sqlite3_busy_handler|busy-handler callback])
** until all readers are reading from the database file only. This ensures
** that the next client to write to the database file restarts the log file
** from the beginning. This call blocks database writers while it is running,
** but not database readers.
**
@@ -7444,10 +7459,11 @@
*/
SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
/*
** CAPI3REF: Conflict resolution modes
+** KEYWORDS: {conflict resolution mode}
**
** These constants are returned by [sqlite3_vtab_on_conflict()] to
** inform a [virtual table] implementation what the [ON CONFLICT] mode
** is for the SQL statement being evaluated.
**
@@ -9285,43 +9301,43 @@
#define OP_Affinity 47 /* synopsis: affinity(r[P1@P2]) */
#define OP_MakeRecord 48 /* synopsis: r[P3]=mkrec(r[P1@P2]) */
#define OP_Count 49 /* synopsis: r[P2]=count() */
#define OP_ReadCookie 50
#define OP_SetCookie 51
-#define OP_OpenRead 52 /* synopsis: root=P2 iDb=P3 */
-#define OP_OpenWrite 53 /* synopsis: root=P2 iDb=P3 */
-#define OP_OpenAutoindex 54 /* synopsis: nColumn=P2 */
-#define OP_OpenEphemeral 55 /* synopsis: nColumn=P2 */
-#define OP_SorterOpen 56
-#define OP_OpenPseudo 57 /* synopsis: P3 columns in r[P2] */
-#define OP_Close 58
-#define OP_SeekLT 59
-#define OP_SeekLE 60
-#define OP_SeekGE 61
-#define OP_SeekGT 62
-#define OP_Seek 63 /* synopsis: intkey=r[P2] */
-#define OP_NoConflict 64 /* synopsis: key=r[P3@P4] */
-#define OP_NotFound 65 /* synopsis: key=r[P3@P4] */
-#define OP_Found 66 /* synopsis: key=r[P3@P4] */
-#define OP_NotExists 67 /* synopsis: intkey=r[P3] */
-#define OP_Sequence 68 /* synopsis: r[P2]=cursor[P1].ctr++ */
-#define OP_NewRowid 69 /* synopsis: r[P2]=rowid */
-#define OP_Insert 70 /* synopsis: intkey=r[P3] data=r[P2] */
+#define OP_ReopenIdx 52 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenRead 53 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenWrite 54 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenAutoindex 55 /* synopsis: nColumn=P2 */
+#define OP_OpenEphemeral 56 /* synopsis: nColumn=P2 */
+#define OP_SorterOpen 57
+#define OP_OpenPseudo 58 /* synopsis: P3 columns in r[P2] */
+#define OP_Close 59
+#define OP_SeekLT 60 /* synopsis: key=r[P3@P4] */
+#define OP_SeekLE 61 /* synopsis: key=r[P3@P4] */
+#define OP_SeekGE 62 /* synopsis: key=r[P3@P4] */
+#define OP_SeekGT 63 /* synopsis: key=r[P3@P4] */
+#define OP_Seek 64 /* synopsis: intkey=r[P2] */
+#define OP_NoConflict 65 /* synopsis: key=r[P3@P4] */
+#define OP_NotFound 66 /* synopsis: key=r[P3@P4] */
+#define OP_Found 67 /* synopsis: key=r[P3@P4] */
+#define OP_NotExists 68 /* synopsis: intkey=r[P3] */
+#define OP_Sequence 69 /* synopsis: r[P2]=cursor[P1].ctr++ */
+#define OP_NewRowid 70 /* synopsis: r[P2]=rowid */
#define OP_Or 71 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
#define OP_And 72 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
-#define OP_InsertInt 73 /* synopsis: intkey=P3 data=r[P2] */
-#define OP_Delete 74
-#define OP_ResetCount 75
+#define OP_Insert 73 /* synopsis: intkey=r[P3] data=r[P2] */
+#define OP_InsertInt 74 /* synopsis: intkey=P3 data=r[P2] */
+#define OP_Delete 75
#define OP_IsNull 76 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
#define OP_NotNull 77 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
#define OP_Ne 78 /* same as TK_NE, synopsis: if r[P1]!=r[P3] goto P2 */
#define OP_Eq 79 /* same as TK_EQ, synopsis: if r[P1]==r[P3] goto P2 */
#define OP_Gt 80 /* same as TK_GT, synopsis: if r[P1]>r[P3] goto P2 */
#define OP_Le 81 /* same as TK_LE, synopsis: if r[P1]<=r[P3] goto P2 */
#define OP_Lt 82 /* same as TK_LT, synopsis: if r[P1]=r[P3] goto P2 */
-#define OP_SorterCompare 84 /* synopsis: if key(P1)!=rtrim(r[P3],P4) goto P2 */
+#define OP_ResetCount 84
#define OP_BitAnd 85 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
#define OP_BitOr 86 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
#define OP_ShiftLeft 87 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */
#define OP_Add 89 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
@@ -9328,73 +9344,74 @@
#define OP_Subtract 90 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
#define OP_Multiply 91 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
#define OP_Divide 92 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
#define OP_Remainder 93 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
#define OP_Concat 94 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
-#define OP_SorterData 95 /* synopsis: r[P2]=data */
+#define OP_SorterCompare 95 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
#define OP_BitNot 96 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */
#define OP_String8 97 /* same as TK_STRING, synopsis: r[P2]='P4' */
-#define OP_RowKey 98 /* synopsis: r[P2]=key */
-#define OP_RowData 99 /* synopsis: r[P2]=data */
-#define OP_Rowid 100 /* synopsis: r[P2]=rowid */
-#define OP_NullRow 101
-#define OP_Last 102
-#define OP_SorterSort 103
-#define OP_Sort 104
-#define OP_Rewind 105
-#define OP_SorterInsert 106
-#define OP_IdxInsert 107 /* synopsis: key=r[P2] */
-#define OP_IdxDelete 108 /* synopsis: key=r[P2@P3] */
-#define OP_IdxRowid 109 /* synopsis: r[P2]=rowid */
-#define OP_IdxLE 110 /* synopsis: key=r[P3@P4] */
-#define OP_IdxGT 111 /* synopsis: key=r[P3@P4] */
-#define OP_IdxLT 112 /* synopsis: key=r[P3@P4] */
-#define OP_IdxGE 113 /* synopsis: key=r[P3@P4] */
-#define OP_Destroy 114
-#define OP_Clear 115
-#define OP_ResetSorter 116
-#define OP_CreateIndex 117 /* synopsis: r[P2]=root iDb=P1 */
-#define OP_CreateTable 118 /* synopsis: r[P2]=root iDb=P1 */
-#define OP_ParseSchema 119
-#define OP_LoadAnalysis 120
-#define OP_DropTable 121
-#define OP_DropIndex 122
-#define OP_DropTrigger 123
-#define OP_IntegrityCk 124
-#define OP_RowSetAdd 125 /* synopsis: rowset(P1)=r[P2] */
-#define OP_RowSetRead 126 /* synopsis: r[P3]=rowset(P1) */
-#define OP_RowSetTest 127 /* synopsis: if r[P3] in rowset(P1) goto P2 */
-#define OP_Program 128
-#define OP_Param 129
-#define OP_FkCounter 130 /* synopsis: fkctr[P1]+=P2 */
-#define OP_FkIfZero 131 /* synopsis: if fkctr[P1]==0 goto P2 */
-#define OP_MemMax 132 /* synopsis: r[P1]=max(r[P1],r[P2]) */
+#define OP_SorterData 98 /* synopsis: r[P2]=data */
+#define OP_RowKey 99 /* synopsis: r[P2]=key */
+#define OP_RowData 100 /* synopsis: r[P2]=data */
+#define OP_Rowid 101 /* synopsis: r[P2]=rowid */
+#define OP_NullRow 102
+#define OP_Last 103
+#define OP_SorterSort 104
+#define OP_Sort 105
+#define OP_Rewind 106
+#define OP_SorterInsert 107
+#define OP_IdxInsert 108 /* synopsis: key=r[P2] */
+#define OP_IdxDelete 109 /* synopsis: key=r[P2@P3] */
+#define OP_IdxRowid 110 /* synopsis: r[P2]=rowid */
+#define OP_IdxLE 111 /* synopsis: key=r[P3@P4] */
+#define OP_IdxGT 112 /* synopsis: key=r[P3@P4] */
+#define OP_IdxLT 113 /* synopsis: key=r[P3@P4] */
+#define OP_IdxGE 114 /* synopsis: key=r[P3@P4] */
+#define OP_Destroy 115
+#define OP_Clear 116
+#define OP_ResetSorter 117
+#define OP_CreateIndex 118 /* synopsis: r[P2]=root iDb=P1 */
+#define OP_CreateTable 119 /* synopsis: r[P2]=root iDb=P1 */
+#define OP_ParseSchema 120
+#define OP_LoadAnalysis 121
+#define OP_DropTable 122
+#define OP_DropIndex 123
+#define OP_DropTrigger 124
+#define OP_IntegrityCk 125
+#define OP_RowSetAdd 126 /* synopsis: rowset(P1)=r[P2] */
+#define OP_RowSetRead 127 /* synopsis: r[P3]=rowset(P1) */
+#define OP_RowSetTest 128 /* synopsis: if r[P3] in rowset(P1) goto P2 */
+#define OP_Program 129
+#define OP_Param 130
+#define OP_FkCounter 131 /* synopsis: fkctr[P1]+=P2 */
+#define OP_FkIfZero 132 /* synopsis: if fkctr[P1]==0 goto P2 */
#define OP_Real 133 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
-#define OP_IfPos 134 /* synopsis: if r[P1]>0 goto P2 */
-#define OP_IfNeg 135 /* synopsis: if r[P1]<0 goto P2 */
-#define OP_IfZero 136 /* synopsis: r[P1]+=P3, if r[P1]==0 goto P2 */
-#define OP_AggFinal 137 /* synopsis: accum=r[P1] N=P2 */
-#define OP_IncrVacuum 138
-#define OP_Expire 139
-#define OP_TableLock 140 /* synopsis: iDb=P1 root=P2 write=P3 */
-#define OP_VBegin 141
-#define OP_VCreate 142
+#define OP_MemMax 134 /* synopsis: r[P1]=max(r[P1],r[P2]) */
+#define OP_IfPos 135 /* synopsis: if r[P1]>0 goto P2 */
+#define OP_IfNeg 136 /* synopsis: r[P1]+=P3, if r[P1]<0 goto P2 */
+#define OP_IfZero 137 /* synopsis: r[P1]+=P3, if r[P1]==0 goto P2 */
+#define OP_AggFinal 138 /* synopsis: accum=r[P1] N=P2 */
+#define OP_IncrVacuum 139
+#define OP_Expire 140
+#define OP_TableLock 141 /* synopsis: iDb=P1 root=P2 write=P3 */
+#define OP_VBegin 142
#define OP_ToText 143 /* same as TK_TO_TEXT */
#define OP_ToBlob 144 /* same as TK_TO_BLOB */
#define OP_ToNumeric 145 /* same as TK_TO_NUMERIC */
#define OP_ToInt 146 /* same as TK_TO_INT */
#define OP_ToReal 147 /* same as TK_TO_REAL */
-#define OP_VDestroy 148
-#define OP_VOpen 149
-#define OP_VColumn 150 /* synopsis: r[P3]=vcolumn(P2) */
-#define OP_VNext 151
-#define OP_VRename 152
-#define OP_Pagecount 153
-#define OP_MaxPgcnt 154
-#define OP_Init 155 /* synopsis: Start at P2 */
-#define OP_Noop 156
-#define OP_Explain 157
+#define OP_VCreate 148
+#define OP_VDestroy 149
+#define OP_VOpen 150
+#define OP_VColumn 151 /* synopsis: r[P3]=vcolumn(P2) */
+#define OP_VNext 152
+#define OP_VRename 153
+#define OP_Pagecount 154
+#define OP_MaxPgcnt 155
+#define OP_Init 156 /* synopsis: Start at P2 */
+#define OP_Noop 157
+#define OP_Explain 158
/* Properties such as "out2" or "jump" that are specified in
** comments following the "case" for each opcode in the vdbe.c
** are encoded into bitvectors as follows:
@@ -9412,23 +9429,23 @@
/* 16 */ 0x01, 0x01, 0x04, 0x24, 0x01, 0x04, 0x05, 0x10,\
/* 24 */ 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02,\
/* 32 */ 0x00, 0x00, 0x20, 0x00, 0x00, 0x04, 0x05, 0x04,\
/* 40 */ 0x00, 0x00, 0x01, 0x01, 0x05, 0x05, 0x00, 0x00,\
/* 48 */ 0x00, 0x02, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00,\
-/* 56 */ 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x08,\
-/* 64 */ 0x11, 0x11, 0x11, 0x11, 0x02, 0x02, 0x00, 0x4c,\
+/* 56 */ 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\
+/* 64 */ 0x08, 0x11, 0x11, 0x11, 0x11, 0x02, 0x02, 0x4c,\
/* 72 */ 0x4c, 0x00, 0x00, 0x00, 0x05, 0x05, 0x15, 0x15,\
/* 80 */ 0x15, 0x15, 0x15, 0x15, 0x00, 0x4c, 0x4c, 0x4c,\
/* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x00,\
-/* 96 */ 0x24, 0x02, 0x00, 0x00, 0x02, 0x00, 0x01, 0x01,\
-/* 104 */ 0x01, 0x01, 0x08, 0x08, 0x00, 0x02, 0x01, 0x01,\
-/* 112 */ 0x01, 0x01, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00,\
-/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x45, 0x15,\
-/* 128 */ 0x01, 0x02, 0x00, 0x01, 0x08, 0x02, 0x05, 0x05,\
-/* 136 */ 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04,\
-/* 144 */ 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x01,\
-/* 152 */ 0x00, 0x02, 0x02, 0x01, 0x00, 0x00,}
+/* 96 */ 0x24, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01,\
+/* 104 */ 0x01, 0x01, 0x01, 0x08, 0x08, 0x00, 0x02, 0x01,\
+/* 112 */ 0x01, 0x01, 0x01, 0x02, 0x00, 0x00, 0x02, 0x02,\
+/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x45,\
+/* 128 */ 0x15, 0x01, 0x02, 0x00, 0x01, 0x02, 0x08, 0x05,\
+/* 136 */ 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04,\
+/* 144 */ 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,\
+/* 152 */ 0x01, 0x00, 0x02, 0x02, 0x01, 0x00, 0x00,}
/************** End of opcodes.h *********************************************/
/************** Continuing where we left off in vdbe.h ***********************/
/*
@@ -9479,10 +9496,11 @@
SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8);
SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe*, int);
#ifndef SQLITE_OMIT_TRACE
SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*);
#endif
+SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*,int);
SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **);
@@ -10330,22 +10348,22 @@
Hash trigHash; /* All triggers indexed by name */
Hash fkeyHash; /* All foreign keys by referenced table name */
Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */
u8 file_format; /* Schema format version for this file */
u8 enc; /* Text encoding used by this database */
- u16 flags; /* Flags associated with this schema */
+ u16 schemaFlags; /* Flags associated with this schema */
int cache_size; /* Number of pages to use in the cache */
};
/*
** These macros can be used to test, set, or clear bits in the
** Db.pSchema->flags field.
*/
-#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))==(P))
-#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))!=0)
-#define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->flags|=(P)
-#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->flags&=~(P)
+#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))==(P))
+#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))!=0)
+#define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->schemaFlags|=(P)
+#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->schemaFlags&=~(P)
/*
** Allowed values for the DB.pSchema->flags field.
**
** The DB_SchemaLoaded flag is set after the database schema has been
@@ -10931,10 +10949,13 @@
int tnum; /* Root BTree node for this table (see note above) */
i16 iPKey; /* If not negative, use aCol[iPKey] as the primary key */
i16 nCol; /* Number of columns in this table */
u16 nRef; /* Number of pointers to this Table */
LogEst szTabRow; /* Estimated size of each table row in bytes */
+#ifdef SQLITE_ENABLE_COSTMULT
+ LogEst costMult; /* Cost multiplier for using this table */
+#endif
u8 tabFlags; /* Mask of TF_* values */
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
#ifndef SQLITE_OMIT_ALTERTABLE
int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */
#endif
@@ -11171,10 +11192,13 @@
#define SQLITE_IDXTYPE_PRIMARYKEY 2 /* Is the PRIMARY KEY for the table */
/* Return true if index X is a PRIMARY KEY index */
#define IsPrimaryKeyIndex(X) ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY)
+/* Return true if index X is a UNIQUE index */
+#define IsUniqueIndex(X) ((X)->onError!=OE_None)
+
/*
** Each sample stored in the sqlite_stat3 table is represented in memory
** using a structure of this type. See documentation at the top of the
** analyze.c source file for additional information.
*/
@@ -11590,10 +11614,11 @@
#define WHERE_AND_ONLY 0x0080 /* Don't use indices for OR terms */
#define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */
#define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */
#define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */
#define WHERE_SORTBYGROUP 0x0800 /* Support sqlite3WhereIsSorted() */
+#define WHERE_REOPEN_IDX 0x1000 /* Try to use OP_ReopenIdx */
/* Allowed return values from sqlite3WhereIsDistinct()
*/
#define WHERE_DISTINCT_NOOP 0 /* DISTINCT keyword not used */
#define WHERE_DISTINCT_UNIQUE 1 /* No duplicates */
@@ -11846,13 +11871,23 @@
/*
** The yDbMask datatype for the bitmask of all attached databases.
*/
#if SQLITE_MAX_ATTACHED>30
- typedef sqlite3_uint64 yDbMask;
+ typedef unsigned char yDbMask[(SQLITE_MAX_ATTACHED+9)/8];
+# define DbMaskTest(M,I) (((M)[(I)/8]&(1<<((I)&7)))!=0)
+# define DbMaskZero(M) memset((M),0,sizeof(M))
+# define DbMaskSet(M,I) (M)[(I)/8]|=(1<<((I)&7))
+# define DbMaskAllZero(M) sqlite3DbMaskAllZero(M)
+# define DbMaskNonZero(M) (sqlite3DbMaskAllZero(M)==0)
#else
typedef unsigned int yDbMask;
+# define DbMaskTest(M,I) (((M)&(((yDbMask)1)<<(I)))!=0)
+# define DbMaskZero(M) (M)=0
+# define DbMaskSet(M,I) (M)|=(((yDbMask)1)<<(I))
+# define DbMaskAllZero(M) (M)==0
+# define DbMaskNonZero(M) (M)!=0
#endif
/*
** An SQL parser context. A copy of this structure is passed through
** the parser and down into all the parser action routine in order to
@@ -12521,10 +12556,13 @@
SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse*,Table*);
#else
# define sqlite3ViewGetColumnNames(A,B) 0
#endif
+#if SQLITE_MAX_ATTACHED>30
+SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask);
+#endif
SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int);
SQLITE_PRIVATE void sqlite3CodeDropTable(Parse*, Table*, int, int);
SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3*, Table*);
#ifndef SQLITE_OMIT_AUTOINCREMENT
SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse);
@@ -12771,10 +12809,11 @@
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int);
SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2);
SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr);
SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8);
+SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*);
SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...);
SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
SQLITE_PRIVATE u8 sqlite3HexToInt(int h);
SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
@@ -12800,11 +12839,11 @@
#ifdef SQLITE_ENABLE_8_3_NAMES
SQLITE_PRIVATE void sqlite3FileSuffix3(const char*, char*);
#else
# define sqlite3FileSuffix3(X,Y)
#endif
-SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z,int);
+SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z,u8);
SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8);
SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8);
SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
void(*)(void*));
@@ -12885,11 +12924,13 @@
SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *);
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
SQLITE_PRIVATE void sqlite3AnalyzeFunctions(void);
SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue(Parse*,Index*,UnpackedRecord**,Expr*,u8,int,int*);
+SQLITE_PRIVATE int sqlite3Stat4ValueFromExpr(Parse*, Expr*, u8, sqlite3_value**);
SQLITE_PRIVATE void sqlite3Stat4ProbeFree(UnpackedRecord*);
+SQLITE_PRIVATE int sqlite3Stat4Column(sqlite3*, const void*, int, int, sqlite3_value**);
#endif
/*
** The interface to the LEMON-generated parser
*/
@@ -13022,15 +13063,25 @@
#else
#define sqlite3BeginBenignMalloc()
#define sqlite3EndBenignMalloc()
#endif
-#define IN_INDEX_ROWID 1
-#define IN_INDEX_EPH 2
-#define IN_INDEX_INDEX_ASC 3
-#define IN_INDEX_INDEX_DESC 4
-SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, int*);
+/*
+** Allowed return values from sqlite3FindInIndex()
+*/
+#define IN_INDEX_ROWID 1 /* Search the rowid of the table */
+#define IN_INDEX_EPH 2 /* Search an ephemeral b-tree */
+#define IN_INDEX_INDEX_ASC 3 /* Existing index ASCENDING */
+#define IN_INDEX_INDEX_DESC 4 /* Existing index DESCENDING */
+#define IN_INDEX_NOOP 5 /* No table available. Use comparisons */
+/*
+** Allowed flags for the 3rd parameter to sqlite3FindInIndex().
+*/
+#define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */
+#define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */
+#define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */
+SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, u32, int*);
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *);
SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *);
@@ -13873,18 +13924,22 @@
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
int seekResult; /* Result of previous sqlite3BtreeMoveto() */
int pseudoTableReg; /* Register holding pseudotable content. */
i16 nField; /* Number of fields in the header */
u16 nHdrParsed; /* Number of header fields parsed so far */
+#ifdef SQLITE_DEBUG
+ u8 seekOp; /* Most recent seek operation on this cursor */
+#endif
i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
u8 nullRow; /* True if pointing to a row with no data */
u8 rowidIsValid; /* True if lastRowid is valid */
u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
Bool isEphemeral:1; /* True for an ephemeral table */
Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
Bool isTable:1; /* True if a table requiring integer keys */
Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
+ Pgno pgnoRoot; /* Root page of the open btree cursor */
sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
i64 seqCount; /* Sequence counter */
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
i64 lastRowid; /* Rowid being deleted by OP_Delete */
VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */
@@ -14199,11 +14254,10 @@
SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe*, int, int);
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*);
SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor *, i64 *);
-SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
SQLITE_PRIVATE int sqlite3VdbeExec(Vdbe*);
SQLITE_PRIVATE int sqlite3VdbeList(Vdbe*);
SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe*);
SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *, int);
SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem*);
@@ -18394,11 +18448,11 @@
/*
** Retrieve a pointer to a static mutex or allocate a new dynamic one.
*/
SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int id){
#ifndef SQLITE_OMIT_AUTOINIT
- if( sqlite3_initialize() ) return 0;
+ if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;
#endif
return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
}
SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int id){
@@ -18575,11 +18629,11 @@
** The sqlite3_mutex_alloc() routine allocates a new
** mutex and returns a pointer to it. If it returns NULL
** that means that a mutex could not be allocated.
*/
static sqlite3_mutex *debugMutexAlloc(int id){
- static sqlite3_debug_mutex aStatic[6];
+ static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_APP3 - 1];
sqlite3_debug_mutex *pNew = 0;
switch( id ){
case SQLITE_MUTEX_FAST:
case SQLITE_MUTEX_RECURSIVE: {
pNew = sqlite3Malloc(sizeof(*pNew));
@@ -18772,14 +18826,17 @@
**
** - SQLITE_MUTEX_FAST
**
- SQLITE_MUTEX_RECURSIVE
**
- SQLITE_MUTEX_STATIC_MASTER
**
- SQLITE_MUTEX_STATIC_MEM
-**
- SQLITE_MUTEX_STATIC_MEM2
+**
- SQLITE_MUTEX_STATIC_OPEN
**
- SQLITE_MUTEX_STATIC_PRNG
**
- SQLITE_MUTEX_STATIC_LRU
**
- SQLITE_MUTEX_STATIC_PMEM
+**
- SQLITE_MUTEX_STATIC_APP1
+**
- SQLITE_MUTEX_STATIC_APP2
+**
- SQLITE_MUTEX_STATIC_APP3
**
**
** The first two constants cause sqlite3_mutex_alloc() to create
** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
@@ -18804,10 +18861,13 @@
** mutex types, the same mutex is returned on every call that has
** the same type number.
*/
static sqlite3_mutex *pthreadMutexAlloc(int iType){
static sqlite3_mutex staticMutexes[] = {
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
@@ -19039,14 +19099,227 @@
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
-** This file contains the C functions that implement mutexes for win32
+** This file contains the C functions that implement mutexes for Win32.
*/
#if SQLITE_OS_WIN
+/*
+** Include code that is common to all os_*.c files
+*/
+/************** Include os_common.h in the middle of mutex_w32.c *************/
+/************** Begin file os_common.h ***************************************/
+/*
+** 2004 May 22
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains macros and a little bit of code that is common to
+** all of the platform-specific files (os_*.c) and is #included into those
+** files.
+**
+** This file should be #included by the os_*.c files only. It is not a
+** general purpose header file.
+*/
+#ifndef _OS_COMMON_H_
+#define _OS_COMMON_H_
+
+/*
+** At least two bugs have slipped in because we changed the MEMORY_DEBUG
+** macro to SQLITE_DEBUG and some older makefiles have not yet made the
+** switch. The following code should catch this problem at compile-time.
+*/
+#ifdef MEMORY_DEBUG
+# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
+#endif
+
+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+# ifndef SQLITE_DEBUG_OS_TRACE
+# define SQLITE_DEBUG_OS_TRACE 0
+# endif
+ int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE;
+# define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X
+#else
+# define OSTRACE(X)
+#endif
+
+/*
+** Macros for performance tracing. Normally turned off. Only works
+** on i486 hardware.
+*/
+#ifdef SQLITE_PERFORMANCE_TRACE
+
+/*
+** hwtime.h contains inline assembler code for implementing
+** high-performance timing routines.
+*/
+/************** Include hwtime.h in the middle of os_common.h ****************/
+/************** Begin file hwtime.h ******************************************/
+/*
+** 2008 May 27
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains inline asm code for retrieving "high-performance"
+** counters for x86 class CPUs.
+*/
+#ifndef _HWTIME_H_
+#define _HWTIME_H_
+
+/*
+** The following routine only works on pentium-class (or newer) processors.
+** It uses the RDTSC opcode to read the cycle count value out of the
+** processor and returns that value. This can be used for high-res
+** profiling.
+*/
+#if (defined(__GNUC__) || defined(_MSC_VER)) && \
+ (defined(i386) || defined(__i386__) || defined(_M_IX86))
+
+ #if defined(__GNUC__)
+
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){
+ unsigned int lo, hi;
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
+ return (sqlite_uint64)hi << 32 | lo;
+ }
+
+ #elif defined(_MSC_VER)
+
+ __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
+ __asm {
+ rdtsc
+ ret ; return value at EDX:EAX
+ }
+ }
+
+ #endif
+
+#elif (defined(__GNUC__) && defined(__x86_64__))
+
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){
+ unsigned long val;
+ __asm__ __volatile__ ("rdtsc" : "=A" (val));
+ return val;
+ }
+
+#elif (defined(__GNUC__) && defined(__ppc__))
+
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){
+ unsigned long long retval;
+ unsigned long junk;
+ __asm__ __volatile__ ("\n\
+ 1: mftbu %1\n\
+ mftb %L0\n\
+ mftbu %0\n\
+ cmpw %0,%1\n\
+ bne 1b"
+ : "=r" (retval), "=r" (junk));
+ return retval;
+ }
+
+#else
+
+ #error Need implementation of sqlite3Hwtime() for your platform.
+
+ /*
+ ** To compile without implementing sqlite3Hwtime() for your platform,
+ ** you can remove the above #error and use the following
+ ** stub function. You will lose timing support for many
+ ** of the debugging and testing utilities, but it should at
+ ** least compile and run.
+ */
+SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
+
+#endif
+
+#endif /* !defined(_HWTIME_H_) */
+
+/************** End of hwtime.h **********************************************/
+/************** Continuing where we left off in os_common.h ******************/
+
+static sqlite_uint64 g_start;
+static sqlite_uint64 g_elapsed;
+#define TIMER_START g_start=sqlite3Hwtime()
+#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start
+#define TIMER_ELAPSED g_elapsed
+#else
+#define TIMER_START
+#define TIMER_END
+#define TIMER_ELAPSED ((sqlite_uint64)0)
+#endif
+
+/*
+** If we compile with the SQLITE_TEST macro set, then the following block
+** of code will give us the ability to simulate a disk I/O error. This
+** is used for testing the I/O recovery logic.
+*/
+#ifdef SQLITE_TEST
+SQLITE_API int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */
+SQLITE_API int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */
+SQLITE_API int sqlite3_io_error_pending = 0; /* Count down to first I/O error */
+SQLITE_API int sqlite3_io_error_persist = 0; /* True if I/O errors persist */
+SQLITE_API int sqlite3_io_error_benign = 0; /* True if errors are benign */
+SQLITE_API int sqlite3_diskfull_pending = 0;
+SQLITE_API int sqlite3_diskfull = 0;
+#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
+#define SimulateIOError(CODE) \
+ if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
+ || sqlite3_io_error_pending-- == 1 ) \
+ { local_ioerr(); CODE; }
+static void local_ioerr(){
+ IOTRACE(("IOERR\n"));
+ sqlite3_io_error_hit++;
+ if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++;
+}
+#define SimulateDiskfullError(CODE) \
+ if( sqlite3_diskfull_pending ){ \
+ if( sqlite3_diskfull_pending == 1 ){ \
+ local_ioerr(); \
+ sqlite3_diskfull = 1; \
+ sqlite3_io_error_hit = 1; \
+ CODE; \
+ }else{ \
+ sqlite3_diskfull_pending--; \
+ } \
+ }
+#else
+#define SimulateIOErrorBenign(X)
+#define SimulateIOError(A)
+#define SimulateDiskfullError(A)
+#endif
+
+/*
+** When testing, keep a count of the number of open files.
+*/
+#ifdef SQLITE_TEST
+SQLITE_API int sqlite3_open_file_count = 0;
+#define OpenCounter(X) sqlite3_open_file_count+=(X)
+#else
+#define OpenCounter(X)
+#endif
+
+#endif /* !defined(_OS_COMMON_H_) */
+
+/************** End of os_common.h *******************************************/
+/************** Continuing where we left off in mutex_w32.c ******************/
+
/*
** Include the header file for the Windows VFS.
*/
/************** Include os_win.h in the middle of mutex_w32.c ****************/
/************** Begin file os_win.h ******************************************/
@@ -19122,11 +19395,11 @@
/************** Continuing where we left off in mutex_w32.c ******************/
#endif
/*
** The code in this file is only used if we are compiling multithreaded
-** on a win32 system.
+** on a Win32 system.
*/
#ifdef SQLITE_MUTEX_W32
/*
** Each recursive mutex is an instance of the following structure.
@@ -19135,94 +19408,75 @@
CRITICAL_SECTION mutex; /* Mutex controlling the lock */
int id; /* Mutex type */
#ifdef SQLITE_DEBUG
volatile int nRef; /* Number of enterances */
volatile DWORD owner; /* Thread holding this mutex */
- int trace; /* True to trace changes */
+ volatile int trace; /* True to trace changes */
#endif
};
+
+/*
+** These are the initializer values used when declaring a "static" mutex
+** on Win32. It should be noted that all mutexes require initialization
+** on the Win32 platform.
+*/
#define SQLITE_W32_MUTEX_INITIALIZER { 0 }
+
#ifdef SQLITE_DEBUG
-#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, 0L, (DWORD)0, 0 }
+#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, \
+ 0L, (DWORD)0, 0 }
#else
#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 }
#endif
-/*
-** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
-** or WinCE. Return false (zero) for Win95, Win98, or WinME.
-**
-** Here is an interesting observation: Win95, Win98, and WinME lack
-** the LockFileEx() API. But we can still statically link against that
-** API as long as we don't call it win running Win95/98/ME. A call to
-** this routine is used to determine if the host is Win95/98/ME or
-** WinNT/2K/XP so that we will know whether or not we can safely call
-** the LockFileEx() API.
-**
-** mutexIsNT() is only used for the TryEnterCriticalSection() API call,
-** which is only available if your application was compiled with
-** _WIN32_WINNT defined to a value >= 0x0400. Currently, the only
-** call to TryEnterCriticalSection() is #ifdef'ed out, so #ifdef
-** this out as well.
-*/
-#if 0
-#if SQLITE_OS_WINCE || SQLITE_OS_WINRT
-# define mutexIsNT() (1)
-#else
- static int mutexIsNT(void){
- static int osType = 0;
- if( osType==0 ){
- OSVERSIONINFO sInfo;
- sInfo.dwOSVersionInfoSize = sizeof(sInfo);
- GetVersionEx(&sInfo);
- osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
- }
- return osType==2;
- }
-#endif /* SQLITE_OS_WINCE || SQLITE_OS_WINRT */
-#endif
-
#ifdef SQLITE_DEBUG
/*
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
** intended for use only inside assert() statements.
*/
static int winMutexHeld(sqlite3_mutex *p){
return p->nRef!=0 && p->owner==GetCurrentThreadId();
}
+
static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){
return p->nRef==0 || p->owner!=tid;
}
+
static int winMutexNotheld(sqlite3_mutex *p){
- DWORD tid = GetCurrentThreadId();
+ DWORD tid = GetCurrentThreadId();
return winMutexNotheld2(p, tid);
}
#endif
-
/*
** Initialize and deinitialize the mutex subsystem.
*/
-static sqlite3_mutex winMutex_staticMutexes[6] = {
+static sqlite3_mutex winMutex_staticMutexes[] = {
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER
};
+
static int winMutex_isInit = 0;
-/* As winMutexInit() and winMutexEnd() are called as part
-** of the sqlite3_initialize and sqlite3_shutdown()
-** processing, the "interlocked" magic is probably not
-** strictly necessary.
+static int winMutex_isNt = -1; /* <0 means "need to query" */
+
+/* As the winMutexInit() and winMutexEnd() functions are called as part
+** of the sqlite3_initialize() and sqlite3_shutdown() processing, the
+** "interlocked" magic used here is probably not strictly necessary.
*/
-static LONG winMutex_lock = 0;
+static LONG volatile winMutex_lock = 0;
+SQLITE_API int sqlite3_win32_is_nt(void); /* os_win.c */
SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */
-static int winMutexInit(void){
+static int winMutexInit(void){
/* The first to increment to 1 does actual initialization */
if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){
int i;
for(i=0; i
** - SQLITE_MUTEX_FAST
**
- SQLITE_MUTEX_RECURSIVE
**
- SQLITE_MUTEX_STATIC_MASTER
**
- SQLITE_MUTEX_STATIC_MEM
-**
- SQLITE_MUTEX_STATIC_MEM2
+**
- SQLITE_MUTEX_STATIC_OPEN
**
- SQLITE_MUTEX_STATIC_PRNG
**
- SQLITE_MUTEX_STATIC_LRU
**
- SQLITE_MUTEX_STATIC_PMEM
+**
- SQLITE_MUTEX_STATIC_APP1
+**
- SQLITE_MUTEX_STATIC_APP2
+**
- SQLITE_MUTEX_STATIC_APP3
**
**
** The first two constants cause sqlite3_mutex_alloc() to create
** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
@@ -19292,11 +19550,11 @@
** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
** SQLITE_MUTEX_RECURSIVE.
**
** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
-** returns a different mutex on every call. But for the static
+** returns a different mutex on every call. But for the static
** mutex types, the same mutex is returned on every call that has
** the same type number.
*/
static sqlite3_mutex *winMutexAlloc(int iType){
sqlite3_mutex *p;
@@ -19303,13 +19561,16 @@
switch( iType ){
case SQLITE_MUTEX_FAST:
case SQLITE_MUTEX_RECURSIVE: {
p = sqlite3MallocZero( sizeof(*p) );
- if( p ){
+ if( p ){
#ifdef SQLITE_DEBUG
p->id = iType;
+#ifdef SQLITE_WIN32_MUTEX_TRACE_DYNAMIC
+ p->trace = 1;
+#endif
#endif
#if SQLITE_OS_WINRT
InitializeCriticalSectionEx(&p->mutex, 0, 0);
#else
InitializeCriticalSection(&p->mutex);
@@ -19316,16 +19577,19 @@
#endif
}
break;
}
default: {
- assert( winMutex_isInit==1 );
assert( iType-2 >= 0 );
assert( iType-2 < ArraySize(winMutex_staticMutexes) );
+ assert( winMutex_isInit==1 );
p = &winMutex_staticMutexes[iType-2];
#ifdef SQLITE_DEBUG
p->id = iType;
+#ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC
+ p->trace = 1;
+#endif
#endif
break;
}
}
return p;
@@ -19337,12 +19601,15 @@
** allocated mutex. SQLite is careful to deallocate every
** mutex that it allocates.
*/
static void winMutexFree(sqlite3_mutex *p){
assert( p );
+#ifdef SQLITE_DEBUG
assert( p->nRef==0 && p->owner==0 );
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
+#endif
+ assert( winMutex_isInit==1 );
DeleteCriticalSection(&p->mutex);
sqlite3_free(p);
}
/*
@@ -19355,53 +19622,71 @@
** mutex must be exited an equal number of times before another thread
** can enter. If the same thread tries to enter any other kind of mutex
** more than once, the behavior is undefined.
*/
static void winMutexEnter(sqlite3_mutex *p){
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
+ DWORD tid = GetCurrentThreadId();
+#endif
#ifdef SQLITE_DEBUG
- DWORD tid = GetCurrentThreadId();
+ assert( p );
assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
+#else
+ assert( p );
#endif
+ assert( winMutex_isInit==1 );
EnterCriticalSection(&p->mutex);
#ifdef SQLITE_DEBUG
assert( p->nRef>0 || p->owner==0 );
- p->owner = tid;
+ p->owner = tid;
p->nRef++;
if( p->trace ){
- printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
+ OSTRACE(("ENTER-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n",
+ tid, p, p->trace, p->nRef));
}
#endif
}
+
static int winMutexTry(sqlite3_mutex *p){
-#ifndef NDEBUG
- DWORD tid = GetCurrentThreadId();
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
+ DWORD tid = GetCurrentThreadId();
#endif
int rc = SQLITE_BUSY;
+ assert( p );
assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
/*
** The sqlite3_mutex_try() routine is very rarely used, and when it
** is used it is merely an optimization. So it is OK for it to always
- ** fail.
+ ** fail.
**
** The TryEnterCriticalSection() interface is only available on WinNT.
** And some windows compilers complain if you try to use it without
** first doing some #defines that prevent SQLite from building on Win98.
** For that reason, we will omit this optimization for now. See
** ticket #2685.
*/
-#if 0
- if( mutexIsNT() && TryEnterCriticalSection(&p->mutex) ){
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400
+ assert( winMutex_isInit==1 );
+ assert( winMutex_isNt>=-1 && winMutex_isNt<=1 );
+ if( winMutex_isNt<0 ){
+ winMutex_isNt = sqlite3_win32_is_nt();
+ }
+ assert( winMutex_isNt==0 || winMutex_isNt==1 );
+ if( winMutex_isNt && TryEnterCriticalSection(&p->mutex) ){
+#ifdef SQLITE_DEBUG
p->owner = tid;
p->nRef++;
+#endif
rc = SQLITE_OK;
}
#else
UNUSED_PARAMETER(p);
#endif
#ifdef SQLITE_DEBUG
- if( rc==SQLITE_OK && p->trace ){
- printf("try mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
+ if( p->trace ){
+ OSTRACE(("TRY-MUTEX tid=%lu, mutex=%p (%d), owner=%lu, nRef=%d, rc=%s\n",
+ tid, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc)));
}
#endif
return rc;
}
@@ -19410,22 +19695,27 @@
** previously entered by the same thread. The behavior
** is undefined if the mutex is not currently entered or
** is not currently allocated. SQLite will never do either.
*/
static void winMutexLeave(sqlite3_mutex *p){
-#ifndef NDEBUG
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
DWORD tid = GetCurrentThreadId();
+#endif
+ assert( p );
+#ifdef SQLITE_DEBUG
assert( p->nRef>0 );
assert( p->owner==tid );
p->nRef--;
if( p->nRef==0 ) p->owner = 0;
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
#endif
+ assert( winMutex_isInit==1 );
LeaveCriticalSection(&p->mutex);
#ifdef SQLITE_DEBUG
if( p->trace ){
- printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
+ OSTRACE(("LEAVE-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n",
+ tid, p, p->trace, p->nRef));
}
#endif
}
SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
@@ -19443,13 +19733,13 @@
#else
0,
0
#endif
};
-
return &sMutex;
}
+
#endif /* SQLITE_MUTEX_W32 */
/************** End of mutex_w32.c *******************************************/
/************** Begin file malloc.c ******************************************/
/*
@@ -21562,12 +21852,12 @@
** * Bytes in the range of 0x80 through 0xbf which occur as the first
** byte of a character are interpreted as single-byte characters
** and rendered as themselves even though they are technically
** invalid characters.
**
-** * This routine accepts an infinite number of different UTF8 encodings
-** for unicode values 0x80 and greater. It do not change over-length
+** * This routine accepts over-length UTF8 encodings
+** for unicode values 0x80 and greater. It does not change over-length
** encodings to 0xfffd as some systems recommend.
*/
#define READ_UTF8(zIn, zTerm, c) \
c = *(zIn++); \
if( c>=0xc0 ){ \
@@ -22420,13 +22710,13 @@
testcase( c==(+1) );
}
return c;
}
-
/*
-** Convert zNum to a 64-bit signed integer.
+** Convert zNum to a 64-bit signed integer. zNum must be decimal. This
+** routine does *not* accept hexadecimal notation.
**
** If the zNum value is representable as a 64-bit twos-complement
** integer, then write that value into *pNum and return 0.
**
** If zNum is exactly 9223372036854775808, return 2. This special
@@ -22509,14 +22799,48 @@
assert( u-1==LARGEST_INT64 );
return neg ? 0 : 2;
}
}
}
+
+/*
+** Transform a UTF-8 integer literal, in either decimal or hexadecimal,
+** into a 64-bit signed integer. This routine accepts hexadecimal literals,
+** whereas sqlite3Atoi64() does not.
+**
+** Returns:
+**
+** 0 Successful transformation. Fits in a 64-bit signed integer.
+** 1 Integer too large for a 64-bit signed integer or is malformed
+** 2 Special case of 9223372036854775808
+*/
+SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
+#ifndef SQLITE_OMIT_HEX_INTEGER
+ if( z[0]=='0'
+ && (z[1]=='x' || z[1]=='X')
+ && sqlite3Isxdigit(z[2])
+ ){
+ u64 u = 0;
+ int i, k;
+ for(i=2; z[i]=='0'; i++){}
+ for(k=i; sqlite3Isxdigit(z[k]); k++){
+ u = u*16 + sqlite3HexToInt(z[k]);
+ }
+ memcpy(pOut, &u, 8);
+ return (z[k]==0 && k-i<=16) ? 0 : 1;
+ }else
+#endif /* SQLITE_OMIT_HEX_INTEGER */
+ {
+ return sqlite3Atoi64(z, pOut, sqlite3Strlen30(z), SQLITE_UTF8);
+ }
+}
/*
** If zNum represents an integer that will fit in 32-bits, then set
** *pValue to that integer and return true. Otherwise return false.
+**
+** This routine accepts both decimal and hexadecimal notation for integers.
**
** Any non-numeric characters that following zNum are ignored.
** This is different from sqlite3Atoi64() which requires the
** input number to be zero-terminated.
*/
@@ -22528,11 +22852,29 @@
neg = 1;
zNum++;
}else if( zNum[0]=='+' ){
zNum++;
}
- while( zNum[0]=='0' ) zNum++;
+#ifndef SQLITE_OMIT_HEX_INTEGER
+ else if( zNum[0]=='0'
+ && (zNum[1]=='x' || zNum[1]=='X')
+ && sqlite3Isxdigit(zNum[2])
+ ){
+ u32 u = 0;
+ zNum += 2;
+ while( zNum[0]=='0' ) zNum++;
+ for(i=0; sqlite3Isxdigit(zNum[i]) && i<8; i++){
+ u = u*16 + sqlite3HexToInt(zNum[i]);
+ }
+ if( (u&0x80000000)==0 && sqlite3Isxdigit(zNum[i])==0 ){
+ memcpy(pValue, &u, 4);
+ return 1;
+ }else{
+ return 0;
+ }
+ }
+#endif
for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){
v = v*10 + c;
}
/* The longest decimal representation of a 32 bit integer is 10 digits:
@@ -23604,43 +23946,43 @@
/* 47 */ "Affinity" OpHelp("affinity(r[P1@P2])"),
/* 48 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"),
/* 49 */ "Count" OpHelp("r[P2]=count()"),
/* 50 */ "ReadCookie" OpHelp(""),
/* 51 */ "SetCookie" OpHelp(""),
- /* 52 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
- /* 53 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
- /* 54 */ "OpenAutoindex" OpHelp("nColumn=P2"),
- /* 55 */ "OpenEphemeral" OpHelp("nColumn=P2"),
- /* 56 */ "SorterOpen" OpHelp(""),
- /* 57 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
- /* 58 */ "Close" OpHelp(""),
- /* 59 */ "SeekLT" OpHelp(""),
- /* 60 */ "SeekLE" OpHelp(""),
- /* 61 */ "SeekGE" OpHelp(""),
- /* 62 */ "SeekGT" OpHelp(""),
- /* 63 */ "Seek" OpHelp("intkey=r[P2]"),
- /* 64 */ "NoConflict" OpHelp("key=r[P3@P4]"),
- /* 65 */ "NotFound" OpHelp("key=r[P3@P4]"),
- /* 66 */ "Found" OpHelp("key=r[P3@P4]"),
- /* 67 */ "NotExists" OpHelp("intkey=r[P3]"),
- /* 68 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
- /* 69 */ "NewRowid" OpHelp("r[P2]=rowid"),
- /* 70 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
+ /* 52 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"),
+ /* 53 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
+ /* 54 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
+ /* 55 */ "OpenAutoindex" OpHelp("nColumn=P2"),
+ /* 56 */ "OpenEphemeral" OpHelp("nColumn=P2"),
+ /* 57 */ "SorterOpen" OpHelp(""),
+ /* 58 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
+ /* 59 */ "Close" OpHelp(""),
+ /* 60 */ "SeekLT" OpHelp("key=r[P3@P4]"),
+ /* 61 */ "SeekLE" OpHelp("key=r[P3@P4]"),
+ /* 62 */ "SeekGE" OpHelp("key=r[P3@P4]"),
+ /* 63 */ "SeekGT" OpHelp("key=r[P3@P4]"),
+ /* 64 */ "Seek" OpHelp("intkey=r[P2]"),
+ /* 65 */ "NoConflict" OpHelp("key=r[P3@P4]"),
+ /* 66 */ "NotFound" OpHelp("key=r[P3@P4]"),
+ /* 67 */ "Found" OpHelp("key=r[P3@P4]"),
+ /* 68 */ "NotExists" OpHelp("intkey=r[P3]"),
+ /* 69 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
+ /* 70 */ "NewRowid" OpHelp("r[P2]=rowid"),
/* 71 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
/* 72 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
- /* 73 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"),
- /* 74 */ "Delete" OpHelp(""),
- /* 75 */ "ResetCount" OpHelp(""),
+ /* 73 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
+ /* 74 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"),
+ /* 75 */ "Delete" OpHelp(""),
/* 76 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
/* 77 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
/* 78 */ "Ne" OpHelp("if r[P1]!=r[P3] goto P2"),
/* 79 */ "Eq" OpHelp("if r[P1]==r[P3] goto P2"),
/* 80 */ "Gt" OpHelp("if r[P1]>r[P3] goto P2"),
/* 81 */ "Le" OpHelp("if r[P1]<=r[P3] goto P2"),
/* 82 */ "Lt" OpHelp("if r[P1]
=r[P3] goto P2"),
- /* 84 */ "SorterCompare" OpHelp("if key(P1)!=rtrim(r[P3],P4) goto P2"),
+ /* 84 */ "ResetCount" OpHelp(""),
/* 85 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
/* 86 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
/* 87 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"),
/* 89 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"),
@@ -23647,73 +23989,74 @@
/* 90 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"),
/* 91 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
/* 92 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
/* 93 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
/* 94 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
- /* 95 */ "SorterData" OpHelp("r[P2]=data"),
+ /* 95 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
/* 96 */ "BitNot" OpHelp("r[P1]= ~r[P1]"),
/* 97 */ "String8" OpHelp("r[P2]='P4'"),
- /* 98 */ "RowKey" OpHelp("r[P2]=key"),
- /* 99 */ "RowData" OpHelp("r[P2]=data"),
- /* 100 */ "Rowid" OpHelp("r[P2]=rowid"),
- /* 101 */ "NullRow" OpHelp(""),
- /* 102 */ "Last" OpHelp(""),
- /* 103 */ "SorterSort" OpHelp(""),
- /* 104 */ "Sort" OpHelp(""),
- /* 105 */ "Rewind" OpHelp(""),
- /* 106 */ "SorterInsert" OpHelp(""),
- /* 107 */ "IdxInsert" OpHelp("key=r[P2]"),
- /* 108 */ "IdxDelete" OpHelp("key=r[P2@P3]"),
- /* 109 */ "IdxRowid" OpHelp("r[P2]=rowid"),
- /* 110 */ "IdxLE" OpHelp("key=r[P3@P4]"),
- /* 111 */ "IdxGT" OpHelp("key=r[P3@P4]"),
- /* 112 */ "IdxLT" OpHelp("key=r[P3@P4]"),
- /* 113 */ "IdxGE" OpHelp("key=r[P3@P4]"),
- /* 114 */ "Destroy" OpHelp(""),
- /* 115 */ "Clear" OpHelp(""),
- /* 116 */ "ResetSorter" OpHelp(""),
- /* 117 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"),
- /* 118 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"),
- /* 119 */ "ParseSchema" OpHelp(""),
- /* 120 */ "LoadAnalysis" OpHelp(""),
- /* 121 */ "DropTable" OpHelp(""),
- /* 122 */ "DropIndex" OpHelp(""),
- /* 123 */ "DropTrigger" OpHelp(""),
- /* 124 */ "IntegrityCk" OpHelp(""),
- /* 125 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
- /* 126 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
- /* 127 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
- /* 128 */ "Program" OpHelp(""),
- /* 129 */ "Param" OpHelp(""),
- /* 130 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
- /* 131 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
- /* 132 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
+ /* 98 */ "SorterData" OpHelp("r[P2]=data"),
+ /* 99 */ "RowKey" OpHelp("r[P2]=key"),
+ /* 100 */ "RowData" OpHelp("r[P2]=data"),
+ /* 101 */ "Rowid" OpHelp("r[P2]=rowid"),
+ /* 102 */ "NullRow" OpHelp(""),
+ /* 103 */ "Last" OpHelp(""),
+ /* 104 */ "SorterSort" OpHelp(""),
+ /* 105 */ "Sort" OpHelp(""),
+ /* 106 */ "Rewind" OpHelp(""),
+ /* 107 */ "SorterInsert" OpHelp(""),
+ /* 108 */ "IdxInsert" OpHelp("key=r[P2]"),
+ /* 109 */ "IdxDelete" OpHelp("key=r[P2@P3]"),
+ /* 110 */ "IdxRowid" OpHelp("r[P2]=rowid"),
+ /* 111 */ "IdxLE" OpHelp("key=r[P3@P4]"),
+ /* 112 */ "IdxGT" OpHelp("key=r[P3@P4]"),
+ /* 113 */ "IdxLT" OpHelp("key=r[P3@P4]"),
+ /* 114 */ "IdxGE" OpHelp("key=r[P3@P4]"),
+ /* 115 */ "Destroy" OpHelp(""),
+ /* 116 */ "Clear" OpHelp(""),
+ /* 117 */ "ResetSorter" OpHelp(""),
+ /* 118 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"),
+ /* 119 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"),
+ /* 120 */ "ParseSchema" OpHelp(""),
+ /* 121 */ "LoadAnalysis" OpHelp(""),
+ /* 122 */ "DropTable" OpHelp(""),
+ /* 123 */ "DropIndex" OpHelp(""),
+ /* 124 */ "DropTrigger" OpHelp(""),
+ /* 125 */ "IntegrityCk" OpHelp(""),
+ /* 126 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
+ /* 127 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
+ /* 128 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
+ /* 129 */ "Program" OpHelp(""),
+ /* 130 */ "Param" OpHelp(""),
+ /* 131 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
+ /* 132 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
/* 133 */ "Real" OpHelp("r[P2]=P4"),
- /* 134 */ "IfPos" OpHelp("if r[P1]>0 goto P2"),
- /* 135 */ "IfNeg" OpHelp("if r[P1]<0 goto P2"),
- /* 136 */ "IfZero" OpHelp("r[P1]+=P3, if r[P1]==0 goto P2"),
- /* 137 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
- /* 138 */ "IncrVacuum" OpHelp(""),
- /* 139 */ "Expire" OpHelp(""),
- /* 140 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
- /* 141 */ "VBegin" OpHelp(""),
- /* 142 */ "VCreate" OpHelp(""),
+ /* 134 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
+ /* 135 */ "IfPos" OpHelp("if r[P1]>0 goto P2"),
+ /* 136 */ "IfNeg" OpHelp("r[P1]+=P3, if r[P1]<0 goto P2"),
+ /* 137 */ "IfZero" OpHelp("r[P1]+=P3, if r[P1]==0 goto P2"),
+ /* 138 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
+ /* 139 */ "IncrVacuum" OpHelp(""),
+ /* 140 */ "Expire" OpHelp(""),
+ /* 141 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
+ /* 142 */ "VBegin" OpHelp(""),
/* 143 */ "ToText" OpHelp(""),
/* 144 */ "ToBlob" OpHelp(""),
/* 145 */ "ToNumeric" OpHelp(""),
/* 146 */ "ToInt" OpHelp(""),
/* 147 */ "ToReal" OpHelp(""),
- /* 148 */ "VDestroy" OpHelp(""),
- /* 149 */ "VOpen" OpHelp(""),
- /* 150 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
- /* 151 */ "VNext" OpHelp(""),
- /* 152 */ "VRename" OpHelp(""),
- /* 153 */ "Pagecount" OpHelp(""),
- /* 154 */ "MaxPgcnt" OpHelp(""),
- /* 155 */ "Init" OpHelp("Start at P2"),
- /* 156 */ "Noop" OpHelp(""),
- /* 157 */ "Explain" OpHelp(""),
+ /* 148 */ "VCreate" OpHelp(""),
+ /* 149 */ "VDestroy" OpHelp(""),
+ /* 150 */ "VOpen" OpHelp(""),
+ /* 151 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
+ /* 152 */ "VNext" OpHelp(""),
+ /* 153 */ "VRename" OpHelp(""),
+ /* 154 */ "Pagecount" OpHelp(""),
+ /* 155 */ "MaxPgcnt" OpHelp(""),
+ /* 156 */ "Init" OpHelp("Start at P2"),
+ /* 157 */ "Noop" OpHelp(""),
+ /* 158 */ "Explain" OpHelp(""),
};
return azName[i];
}
#endif
@@ -23812,15 +24155,14 @@
#include
/* #include */
#include
#include
#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
-#include
+# include
#endif
-
-#if SQLITE_ENABLE_LOCKING_STYLE
+#if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS
# include
# if OS_VXWORKS
# include
# include
# else
@@ -24244,11 +24586,15 @@
** On some systems, calls to fchown() will trigger a message in a security
** log if they come from non-root processes. So avoid calling fchown() if
** we are not running as root.
*/
static int posixFchown(int fd, uid_t uid, gid_t gid){
+#if OS_VXWORKS
+ return 0;
+#else
return geteuid() ? 0 : fchown(fd,uid,gid);
+#endif
}
/* Forward reference */
static int openDirectory(const char*, int*);
static int unixGetpagesize(void);
@@ -24300,11 +24646,11 @@
#define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent)
{ "read", (sqlite3_syscall_ptr)read, 0 },
#define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent)
-#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE
+#if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS)
{ "pread", (sqlite3_syscall_ptr)pread, 0 },
#else
{ "pread", (sqlite3_syscall_ptr)0, 0 },
#endif
#define osPread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent)
@@ -24317,11 +24663,11 @@
#define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent)
{ "write", (sqlite3_syscall_ptr)write, 0 },
#define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
-#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE
+#if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS)
{ "pwrite", (sqlite3_syscall_ptr)pwrite, 0 },
#else
{ "pwrite", (sqlite3_syscall_ptr)0, 0 },
#endif
#define osPwrite ((ssize_t(*)(int,const void*,size_t,off_t))\
@@ -24371,14 +24717,14 @@
{ "mremap", (sqlite3_syscall_ptr)mremap, 0 },
#else
{ "mremap", (sqlite3_syscall_ptr)0, 0 },
#endif
#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
-#endif
-
{ "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 },
#define osGetpagesize ((int(*)(void))aSyscall[24].pCurrent)
+
+#endif
}; /* End of the overrideable system calls */
/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
@@ -24687,20 +25033,10 @@
}
/* else fall through */
case EPERM:
return SQLITE_PERM;
- /* EDEADLK is only possible if a call to fcntl(F_SETLKW) is made. And
- ** this module never makes such a call. And the code in SQLite itself
- ** asserts that SQLITE_IOERR_BLOCKED is never returned. For these reasons
- ** this case is also commented out. If the system does set errno to EDEADLK,
- ** the default SQLITE_IOERR_XXX code will be returned. */
-#if 0
- case EDEADLK:
- return SQLITE_IOERR_BLOCKED;
-#endif
-
#if EOPNOTSUPP!=ENOTSUP
case EOPNOTSUPP:
/* something went terribly awry, unless during file system support
* introspection, in which it actually means what it says */
#endif
@@ -25229,13 +25565,17 @@
/*
** Return TRUE if pFile has been renamed or unlinked since it was first opened.
*/
static int fileHasMoved(unixFile *pFile){
+#if OS_VXWORKS
+ return pFile->pInode!=0 && pFile->pId!=pFile->pInode->fileId.pId;
+#else
struct stat buf;
return pFile->pInode!=0 &&
- (osStat(pFile->zPath, &buf)!=0 || buf.st_ino!=pFile->pInode->fileId.ino);
+ (osStat(pFile->zPath, &buf)!=0 || buf.st_ino!=pFile->pInode->fileId.ino);
+#endif
}
/*
** Check a unixFile that is a database. Verify the following:
@@ -25844,10 +26184,17 @@
osUnlink(pFile->pId->zCanonicalName);
}
vxworksReleaseFileId(pFile->pId);
pFile->pId = 0;
}
+#endif
+#ifdef SQLITE_UNLINK_AFTER_CLOSE
+ if( pFile->ctrlFlags & UNIXFILE_DELETE ){
+ osUnlink(pFile->zPath);
+ sqlite3_free(*(char**)&pFile->zPath);
+ pFile->zPath = 0;
+ }
#endif
OSTRACE(("CLOSE %-3d\n", pFile->h));
OpenCounter(-1);
sqlite3_free(pFile->pUnused);
memset(pFile, 0, sizeof(unixFile));
@@ -26367,11 +26714,10 @@
}
/* Otherwise see if some other process holds it. */
if( !reserved ){
sem_t *pSem = pFile->pInode->pSem;
- struct stat statBuf;
if( sem_trywait(pSem)==-1 ){
int tErrno = errno;
if( EAGAIN != tErrno ){
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);
@@ -26420,11 +26766,10 @@
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
static int semLock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
- int fd;
sem_t *pSem = pFile->pInode->pSem;
int rc = SQLITE_OK;
/* if we already have a lock, it is exclusive.
** Just adjust level and punt on outta here. */
@@ -27883,12 +28228,29 @@
rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
}
return rc;
}
+#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
+
+/*
+** Return the system page size.
+**
+** This function should not be called directly by other code in this file.
+** Instead, it should be called via macro osGetpagesize().
+*/
+static int unixGetpagesize(void){
+#if defined(_BSD_SOURCE)
+ return getpagesize();
+#else
+ return (int)sysconf(_SC_PAGESIZE);
+#endif
+}
+
+#endif /* !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 */
+
#ifndef SQLITE_OMIT_WAL
-
/*
** Object used to represent an shared memory buffer.
**
** When multiple threads all reference the same wal-index, each thread
@@ -28035,24 +28397,10 @@
#endif
return rc;
}
-/*
-** Return the system page size.
-**
-** This function should not be called directly by other code in this file.
-** Instead, it should be called via macro osGetpagesize().
-*/
-static int unixGetpagesize(void){
-#if defined(_BSD_SOURCE)
- return getpagesize();
-#else
- return (int)sysconf(_SC_PAGESIZE);
-#endif
-}
-
/*
** Return the minimum number of 32KB shm regions that should be mapped at
** a time, assuming that each mapping must be an integer multiple of the
** current system page-size.
**
@@ -29698,10 +30046,16 @@
}
if( isDelete ){
#if OS_VXWORKS
zPath = zName;
+#elif defined(SQLITE_UNLINK_AFTER_CLOSE)
+ zPath = sqlite3_mprintf("%s", zName);
+ if( zPath==0 ){
+ robust_close(p, fd, __LINE__);
+ return SQLITE_NOMEM;
+ }
#else
osUnlink(zName);
#endif
}
#if SQLITE_ENABLE_LOCKING_STYLE
@@ -29798,11 +30152,15 @@
){
int rc = SQLITE_OK;
UNUSED_PARAMETER(NotUsed);
SimulateIOError(return SQLITE_IOERR_DELETE);
if( osUnlink(zPath)==(-1) ){
- if( errno==ENOENT ){
+ if( errno==ENOENT
+#if OS_VXWORKS
+ || errno==0x380003
+#endif
+ ){
rc = SQLITE_IOERR_DELETE_NOENT;
}else{
rc = unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath);
}
return rc;
@@ -31695,22 +32053,18 @@
#ifndef NTDDI_WINBLUE
# define NTDDI_WINBLUE 0x06030000
#endif
/*
-** Check if the GetVersionEx[AW] functions should be considered deprecated
-** and avoid using them in that case. It should be noted here that if the
-** value of the SQLITE_WIN32_GETVERSIONEX pre-processor macro is zero
-** (whether via this block or via being manually specified), that implies
-** the underlying operating system will always be based on the Windows NT
-** Kernel.
+** Check to see if the GetVersionEx[AW] functions are deprecated on the
+** target system. GetVersionEx was first deprecated in Win8.1.
*/
#ifndef SQLITE_WIN32_GETVERSIONEX
# if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINBLUE
-# define SQLITE_WIN32_GETVERSIONEX 0
+# define SQLITE_WIN32_GETVERSIONEX 0 /* GetVersionEx() is deprecated */
# else
-# define SQLITE_WIN32_GETVERSIONEX 1
+# define SQLITE_WIN32_GETVERSIONEX 1 /* GetVersionEx() is current */
# endif
#endif
/*
** This constant should already be defined (in the "WinDef.h" SDK file).
@@ -31778,11 +32132,11 @@
/*
** This macro is used when a local variable is set to a value that is
** [sometimes] not used by the code (e.g. via conditional compilation).
*/
#ifndef UNUSED_VARIABLE_VALUE
-# define UNUSED_VARIABLE_VALUE(x) (void)(x)
+# define UNUSED_VARIABLE_VALUE(x) (void)(x)
#endif
/*
** Returns the character that should be used as the directory separator.
*/
@@ -31827,11 +32181,11 @@
/*
** Some Microsoft compilers lack this definition.
*/
#ifndef INVALID_FILE_ATTRIBUTES
-# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif
#ifndef FILE_FLAG_MASK
# define FILE_FLAG_MASK (0xFF3C0000)
#endif
@@ -31877,11 +32231,11 @@
#endif
const char *zPath; /* Full pathname of this file */
int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */
#if SQLITE_OS_WINCE
LPWSTR zDeleteOnClose; /* Name of file to delete when closing */
- HANDLE hMutex; /* Mutex used to control access to shared lock */
+ HANDLE hMutex; /* Mutex used to control access to shared lock */
HANDLE hShared; /* Shared memory segment used for locking */
winceLock local; /* Locks obtained by this instance of winFile */
winceLock *shared; /* Global shared lock memory for the file */
#endif
#if SQLITE_MAX_MMAP_SIZE>0
@@ -32037,14 +32391,13 @@
**
** In order to facilitate testing on a WinNT system, the test fixture
** can manually set this value to 1 to emulate Win98 behavior.
*/
#ifdef SQLITE_TEST
-SQLITE_API int sqlite3_os_type = 0;
-#elif !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \
- defined(SQLITE_WIN32_HAS_ANSI) && defined(SQLITE_WIN32_HAS_WIDE)
-static int sqlite3_os_type = 0;
+SQLITE_API LONG volatile sqlite3_os_type = 0;
+#else
+static LONG volatile sqlite3_os_type = 0;
#endif
#ifndef SYSCALL
# define SYSCALL sqlite3_syscall_ptr
#endif
@@ -32671,10 +33024,26 @@
#endif
#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \
LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent)
+/*
+** NOTE: On some sub-platforms, the InterlockedCompareExchange "function"
+** is really just a macro that uses a compiler intrinsic (e.g. x64).
+** So do not try to make this is into a redefinable interface.
+*/
+#if defined(InterlockedCompareExchange)
+ { "InterlockedCompareExchange", (SYSCALL)0, 0 },
+
+#define osInterlockedCompareExchange InterlockedCompareExchange
+#else
+ { "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 },
+
+#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG volatile*, \
+ LONG,LONG))aSyscall[76].pCurrent)
+#endif /* defined(InterlockedCompareExchange) */
+
}; /* End of the overrideable system calls */
/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
** "win32" VFSes. Return SQLITE_OK opon successfully updating the
@@ -32921,26 +33290,42 @@
#elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI)
# define osIsNT() (1)
#elif !defined(SQLITE_WIN32_HAS_WIDE)
# define osIsNT() (0)
#else
- static int osIsNT(void){
- if( sqlite3_os_type==0 ){
-#if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WIN8
- OSVERSIONINFOW sInfo;
- sInfo.dwOSVersionInfoSize = sizeof(sInfo);
- osGetVersionExW(&sInfo);
+# define osIsNT() ((sqlite3_os_type==2) || sqlite3_win32_is_nt())
+#endif
+
+/*
+** This function determines if the machine is running a version of Windows
+** based on the NT kernel.
+*/
+SQLITE_API int sqlite3_win32_is_nt(void){
+#if defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX
+ if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){
+#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
+ defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WIN8
+ OSVERSIONINFOW sInfo;
+ sInfo.dwOSVersionInfoSize = sizeof(sInfo);
+ osGetVersionExW(&sInfo);
+ osInterlockedCompareExchange(&sqlite3_os_type,
+ (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
+#elif defined(SQLITE_WIN32_HAS_ANSI)
+ OSVERSIONINFOA sInfo;
+ sInfo.dwOSVersionInfoSize = sizeof(sInfo);
+ osGetVersionExA(&sInfo);
+ osInterlockedCompareExchange(&sqlite3_os_type,
+ (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
+#endif
+ }
+ return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
+#elif SQLITE_TEST
+ return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
#else
- OSVERSIONINFOA sInfo;
- sInfo.dwOSVersionInfoSize = sizeof(sInfo);
- osGetVersionExA(&sInfo);
-#endif
- sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
- }
- return sqlite3_os_type==2;
- }
-#endif
+ return 1;
+#endif
+}
#ifdef SQLITE_WIN32_MALLOC
/*
** Allocate nBytes of memory.
*/
@@ -33144,11 +33529,11 @@
sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetWin32());
}
#endif /* SQLITE_WIN32_MALLOC */
/*
-** Convert a UTF-8 string to Microsoft Unicode (UTF-16?).
+** Convert a UTF-8 string to Microsoft Unicode (UTF-16?).
**
** Space to hold the returned string is obtained from malloc.
*/
static LPWSTR winUtf8ToUnicode(const char *zFilename){
int nChar;
@@ -33197,11 +33582,11 @@
}
/*
** Convert an ANSI string to Microsoft Unicode, based on the
** current codepage settings for file apis.
-**
+**
** Space to hold the returned string is obtained
** from sqlite3_malloc.
*/
static LPWSTR winMbcsToUnicode(const char *zFilename){
int nByte;
@@ -33271,11 +33656,11 @@
sqlite3_free(zTmpWide);
return zFilenameUtf8;
}
/*
-** Convert UTF-8 to multibyte character string. Space to hold the
+** Convert UTF-8 to multibyte character string. Space to hold the
** returned string is obtained from sqlite3_malloc().
*/
SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){
char *zFilenameMbcs;
LPWSTR zTmpWide;
@@ -33411,15 +33796,15 @@
** This function - winLogErrorAtLine() - is only ever called via the macro
** winLogError().
**
** This routine is invoked after an error occurs in an OS function.
** It logs a message using sqlite3_log() containing the current value of
-** error code and, if possible, the human-readable equivalent from
+** error code and, if possible, the human-readable equivalent from
** FormatMessage.
**
** The first argument passed to the macro should be the error code that
-** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN).
+** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN).
** The two subsequent arguments should be the name of the OS function that
** failed and the associated file-system path, if any.
*/
#define winLogError(a,b,c,d) winLogErrorAtLine(a,b,c,d,__LINE__)
static int winLogErrorAtLine(
@@ -33446,11 +33831,11 @@
return errcode;
}
/*
** The number of times that a ReadFile(), WriteFile(), and DeleteFile()
-** will be retried following a locking error - probably caused by
+** will be retried following a locking error - probably caused by
** antivirus software. Also the initial delay before the first retry.
** The delay increases linearly with each retry.
*/
#ifndef SQLITE_WIN32_IOERR_RETRY
# define SQLITE_WIN32_IOERR_RETRY 10
@@ -33521,11 +33906,11 @@
/*
** Log a I/O error retry episode.
*/
static void winLogIoerr(int nRetry){
if( nRetry ){
- sqlite3_log(SQLITE_IOERR,
+ sqlite3_log(SQLITE_IOERR,
"delayed %dms for lock/sharing conflict",
winIoerrRetryDelay*nRetry*(nRetry+1)/2
);
}
}
@@ -33615,21 +34000,21 @@
"winceCreateLock1", zFilename);
}
/* Acquire the mutex before continuing */
winceMutexAcquire(pFile->hMutex);
-
- /* Since the names of named mutexes, semaphores, file mappings etc are
+
+ /* Since the names of named mutexes, semaphores, file mappings etc are
** case-sensitive, take advantage of that by uppercasing the mutex name
** and using that as the shared filemapping name.
*/
osCharUpperW(zName);
pFile->hShared = osCreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
PAGE_READWRITE, 0, sizeof(winceLock),
- zName);
+ zName);
- /* Set a flag that indicates we're the first to create the memory so it
+ /* Set a flag that indicates we're the first to create the memory so it
** must be zero-initialized */
lastErrno = osGetLastError();
if (lastErrno == ERROR_ALREADY_EXISTS){
bInit = FALSE;
}
@@ -33636,11 +34021,11 @@
sqlite3_free(zName);
/* If we succeeded in making the shared memory handle, map it. */
if( pFile->hShared ){
- pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared,
+ pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared,
FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock));
/* If mapping failed, close the shared memory handle and erase it */
if( !pFile->shared ){
pFile->lastErrno = osGetLastError();
winLogError(SQLITE_IOERR, pFile->lastErrno,
@@ -33662,11 +34047,11 @@
winceMutexRelease(pFile->hMutex);
osCloseHandle(pFile->hMutex);
pFile->hMutex = NULL;
return SQLITE_IOERR;
}
-
+
/* Initialize the shared memory if we're supposed to */
if( bInit ){
memset(pFile->shared, 0, sizeof(winceLock));
}
@@ -33700,17 +34085,17 @@
/* De-reference and close our copy of the shared memory handle */
osUnmapViewOfFile(pFile->shared);
osCloseHandle(pFile->hShared);
/* Done with the mutex */
- winceMutexRelease(pFile->hMutex);
+ winceMutexRelease(pFile->hMutex);
osCloseHandle(pFile->hMutex);
pFile->hMutex = NULL;
}
}
-/*
+/*
** An implementation of the LockFile() API of Windows for CE
*/
static BOOL winceLockFile(
LPHANDLE phFile,
DWORD dwFileOffsetLow,
@@ -33917,12 +34302,12 @@
#ifndef INVALID_SET_FILE_POINTER
# define INVALID_SET_FILE_POINTER ((DWORD)-1)
#endif
/*
-** Move the current position of the file handle passed as the first
-** argument to offset iOffset within the file. If successful, return 0.
+** Move the current position of the file handle passed as the first
+** argument to offset iOffset within the file. If successful, return 0.
** Otherwise, set pFile->lastErrno and return non-zero.
*/
static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){
#if !SQLITE_OS_WINRT
LONG upperBits; /* Most sig. 32 bits of new offset */
@@ -33933,15 +34318,15 @@
OSTRACE(("SEEK file=%p, offset=%lld\n", pFile->h, iOffset));
upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
lowerBits = (LONG)(iOffset & 0xffffffff);
- /* API oddity: If successful, SetFilePointer() returns a dword
+ /* API oddity: If successful, SetFilePointer() returns a dword
** containing the lower 32-bits of the new file-offset. Or, if it fails,
- ** it returns INVALID_SET_FILE_POINTER. However according to MSDN,
- ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine
- ** whether an error has actually occurred, it is also necessary to call
+ ** it returns INVALID_SET_FILE_POINTER. However according to MSDN,
+ ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine
+ ** whether an error has actually occurred, it is also necessary to call
** GetLastError().
*/
dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
if( (dwRet==INVALID_SET_FILE_POINTER
@@ -34020,11 +34405,11 @@
winceDestroyLock(pFile);
if( pFile->zDeleteOnClose ){
int cnt = 0;
while(
osDeleteFileW(pFile->zDeleteOnClose)==0
- && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff
+ && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff
&& cnt++ < WINCE_DELETION_ATTEMPTS
){
sqlite3_win32_sleep(100); /* Wait a little before trying again */
}
sqlite3_free(pFile->zDeleteOnClose);
@@ -34868,11 +35253,11 @@
winFile *p = (winFile*)id;
return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN |
((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
}
-/*
+/*
** Windows will only let you create file view mappings
** on allocation size granularity boundaries.
** During sqlite3_os_init() we do a GetSystemInfo()
** to get the granularity size.
*/
@@ -34880,15 +35265,15 @@
#ifndef SQLITE_OMIT_WAL
/*
** Helper functions to obtain and relinquish the global mutex. The
-** global mutex is used to protect the winLockInfo objects used by
+** global mutex is used to protect the winLockInfo objects used by
** this file, all of which may be shared by multiple threads.
**
-** Function winShmMutexHeld() is used to assert() that the global mutex
-** is held when required. This function is only used as part of assert()
+** Function winShmMutexHeld() is used to assert() that the global mutex
+** is held when required. This function is only used as part of assert()
** statements. e.g.
**
** winShmEnterMutex()
** assert( winShmMutexHeld() );
** winShmLeaveMutex()
@@ -34914,14 +35299,14 @@
**
** winShmMutexHeld() must be true when creating or destroying
** this object or while reading or writing the following fields:
**
** nRef
-** pNext
+** pNext
**
** The following fields are read-only after the object is created:
-**
+**
** fid
** zFilename
**
** Either winShmNode.mutex must be held or winShmNode.nRef==0 and
** winShmMutexHeld() is true when reading or writing any other field
@@ -35013,11 +35398,11 @@
/* Initialize the locking parameters */
DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0);
}
-
+
if( rc!= 0 ){
rc = SQLITE_OK;
}else{
pFile->lastErrno = osGetLastError();
rc = SQLITE_BUSY;
@@ -35109,11 +35494,11 @@
sqlite3_free(p);
return SQLITE_IOERR_NOMEM;
}
pNew->zFilename = (char*)&pNew[1];
sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
- sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename);
+ sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename);
/* Look to see if there is an existing winShmNode that can be used.
** If no matching winShmNode currently exists, create a new one.
*/
winShmEnterMutex();
@@ -35146,11 +35531,11 @@
if( SQLITE_OK!=rc ){
goto shm_open_err;
}
/* Check to see if another process is holding the dead-man switch.
- ** If not, truncate the file to zero length.
+ ** If not, truncate the file to zero length.
*/
if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
if( rc!=SQLITE_OK ){
rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
@@ -35175,11 +35560,11 @@
/* The reference count on pShmNode has already been incremented under
** the cover of the winShmEnterMutex() mutex and the pointer from the
** new (struct winShm) object to the pShmNode has been set. All that is
** left to do is to link the new object into the linked list starting
- ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex
+ ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex
** mutex.
*/
sqlite3_mutex_enter(pShmNode->mutex);
p->pNext = pShmNode->pFirst;
pShmNode->pFirst = p;
@@ -35195,11 +35580,11 @@
winShmLeaveMutex();
return rc;
}
/*
-** Close a connection to shared-memory. Delete the underlying
+** Close a connection to shared-memory. Delete the underlying
** storage if deleteFlag is true.
*/
static int winShmUnmap(
sqlite3_file *fd, /* Database holding shared memory */
int deleteFlag /* Delete after closing if true */
@@ -35284,11 +35669,11 @@
/* Undo the local locks */
if( rc==SQLITE_OK ){
p->exclMask &= ~mask;
p->sharedMask &= ~mask;
- }
+ }
}else if( flags & SQLITE_SHM_SHARED ){
u16 allShared = 0; /* Union of locks held by connections other than "p" */
/* Find out which shared locks are already held by sibling connections.
** If any sibling already holds an exclusive lock, go ahead and return
@@ -35323,11 +35708,11 @@
if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
rc = SQLITE_BUSY;
break;
}
}
-
+
/* Get the exclusive locks at the system level. Then if successful
** also mark the local connection as being locked.
*/
if( rc==SQLITE_OK ){
rc = winShmSystemLock(pShmNode, _SHM_WRLCK, ofst+WIN_SHM_BASE, n);
@@ -35343,11 +35728,11 @@
sqlite3ErrName(rc)));
return rc;
}
/*
-** Implement a memory barrier or memory fence on shared memory.
+** Implement a memory barrier or memory fence on shared memory.
**
** All loads and stores begun before the barrier must complete before
** any load or store begun after the barrier.
*/
static void winShmBarrier(
@@ -35358,26 +35743,26 @@
winShmEnterMutex();
winShmLeaveMutex();
}
/*
-** This function is called to obtain a pointer to region iRegion of the
-** shared-memory associated with the database file fd. Shared-memory regions
-** are numbered starting from zero. Each shared-memory region is szRegion
+** This function is called to obtain a pointer to region iRegion of the
+** shared-memory associated with the database file fd. Shared-memory regions
+** are numbered starting from zero. Each shared-memory region is szRegion
** bytes in size.
**
** If an error occurs, an error code is returned and *pp is set to NULL.
**
** Otherwise, if the isWrite parameter is 0 and the requested shared-memory
** region has not been allocated (by any client, including one running in a
-** separate process), then *pp is set to NULL and SQLITE_OK returned. If
-** isWrite is non-zero and the requested shared-memory region has not yet
+** separate process), then *pp is set to NULL and SQLITE_OK returned. If
+** isWrite is non-zero and the requested shared-memory region has not yet
** been allocated, it is allocated by this function.
**
** If the shared-memory region has already been allocated or is allocated by
-** this call as described above, then it is mapped into this processes
-** address space (if it is not already), *pp is set to point to the mapped
+** this call as described above, then it is mapped into this processes
+** address space (if it is not already), *pp is set to point to the mapped
** memory and SQLITE_OK returned.
*/
static int winShmMap(
sqlite3_file *fd, /* Handle open on database file */
int iRegion, /* Region to retrieve */
@@ -35445,21 +35830,21 @@
pShmNode->aRegion = apNew;
while( pShmNode->nRegion<=iRegion ){
HANDLE hMap = NULL; /* file-mapping handle */
void *pMap = 0; /* Mapped memory region */
-
+
#if SQLITE_OS_WINRT
hMap = osCreateFileMappingFromApp(pShmNode->hFile.h,
NULL, PAGE_READWRITE, nByte, NULL
);
#elif defined(SQLITE_WIN32_HAS_WIDE)
- hMap = osCreateFileMappingW(pShmNode->hFile.h,
+ hMap = osCreateFileMappingW(pShmNode->hFile.h,
NULL, PAGE_READWRITE, 0, nByte, NULL
);
#elif defined(SQLITE_WIN32_HAS_ANSI)
- hMap = osCreateFileMappingA(pShmNode->hFile.h,
+ hMap = osCreateFileMappingA(pShmNode->hFile.h,
NULL, PAGE_READWRITE, 0, nByte, NULL
);
#endif
OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n",
osGetCurrentProcessId(), pShmNode->nRegion, nByte,
@@ -35552,18 +35937,18 @@
return SQLITE_OK;
}
/*
** Memory map or remap the file opened by file-descriptor pFd (if the file
-** is already mapped, the existing mapping is replaced by the new). Or, if
-** there already exists a mapping for this file, and there are still
+** is already mapped, the existing mapping is replaced by the new). Or, if
+** there already exists a mapping for this file, and there are still
** outstanding xFetch() references to it, this function is a no-op.
**
-** If parameter nByte is non-negative, then it is the requested size of
-** the mapping to create. Otherwise, if nByte is less than zero, then the
+** If parameter nByte is non-negative, then it is the requested size of
+** the mapping to create. Otherwise, if nByte is less than zero, then the
** requested size is the size of the file on disk. The actual size of the
-** created mapping is either the requested size or the value configured
+** created mapping is either the requested size or the value configured
** using SQLITE_FCNTL_MMAP_SIZE, whichever is smaller.
**
** SQLITE_OK is returned if no error occurs (even if the mapping is not
** recreated as a result of outstanding references) or an SQLite error
** code otherwise.
@@ -35588,11 +35973,11 @@
}
if( nMap>pFd->mmapSizeMax ){
nMap = pFd->mmapSizeMax;
}
nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1);
-
+
if( nMap==0 && pFd->mmapSize>0 ){
winUnmapfile(pFd);
}
if( nMap!=pFd->mmapSize ){
void *pNew = 0;
@@ -35660,11 +36045,11 @@
** If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
** Finally, if an error does occur, return an SQLite error code. The final
** value of *pp is undefined in this case.
**
-** If this function does return a pointer, the caller must eventually
+** If this function does return a pointer, the caller must eventually
** release the reference by calling winUnfetch().
*/
static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
#if SQLITE_MAX_MMAP_SIZE>0
winFile *pFd = (winFile*)fd; /* The underlying database file */
@@ -35695,24 +36080,24 @@
osGetCurrentProcessId(), fd, pp, *pp));
return SQLITE_OK;
}
/*
-** If the third argument is non-NULL, then this function releases a
+** If the third argument is non-NULL, then this function releases a
** reference obtained by an earlier call to winFetch(). The second
** argument passed to this function must be the same as the corresponding
-** argument that was passed to the winFetch() invocation.
+** argument that was passed to the winFetch() invocation.
**
-** Or, if the third argument is NULL, then this function is being called
-** to inform the VFS layer that, according to POSIX, any existing mapping
+** Or, if the third argument is NULL, then this function is being called
+** to inform the VFS layer that, according to POSIX, any existing mapping
** may now be invalid and should be unmapped.
*/
static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){
#if SQLITE_MAX_MMAP_SIZE>0
winFile *pFd = (winFile*)fd; /* The underlying database file */
- /* If p==0 (unmap the entire file) then there must be no outstanding
+ /* If p==0 (unmap the entire file) then there must be no outstanding
** xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
** then there must be at least one outstanding. */
assert( (p==0)==(pFd->nFetchOut==0) );
/* If p!=0, it must match the iOff value. */
@@ -35854,11 +36239,11 @@
int nMax, nBuf, nDir, nLen;
char *zBuf;
/* It's odd to simulate an io-error here, but really this is just
** using the io-error infrastructure to test that SQLite handles this
- ** function failing.
+ ** function failing.
*/
SimulateIOError( return SQLITE_IOERR );
/* Allocate a temporary buffer to store the fully qualified file
** name for the temporary file. If this fails, we cannot continue.
@@ -36036,11 +36421,11 @@
OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
return winLogError(SQLITE_ERROR, 0, "winGetTempname4", 0);
}
/*
- ** Check that the output buffer is large enough for the temporary file
+ ** Check that the output buffer is large enough for the temporary file
** name in the following format:
**
** "/etilqs_XXXXXXXXXXXXXXX\0\0"
**
** If not, return SQLITE_ERROR. The number 17 is used here in order to
@@ -36139,42 +36524,42 @@
int isReadonly = (flags & SQLITE_OPEN_READONLY);
int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
#ifndef NDEBUG
int isOpenJournal = (isCreate && (
- eType==SQLITE_OPEN_MASTER_JOURNAL
- || eType==SQLITE_OPEN_MAIN_JOURNAL
+ eType==SQLITE_OPEN_MASTER_JOURNAL
+ || eType==SQLITE_OPEN_MAIN_JOURNAL
|| eType==SQLITE_OPEN_WAL
));
#endif
OSTRACE(("OPEN name=%s, pFile=%p, flags=%x, pOutFlags=%p\n",
zUtf8Name, id, flags, pOutFlags));
- /* Check the following statements are true:
+ /* Check the following statements are true:
**
- ** (a) Exactly one of the READWRITE and READONLY flags must be set, and
+ ** (a) Exactly one of the READWRITE and READONLY flags must be set, and
** (b) if CREATE is set, then READWRITE must also be set, and
** (c) if EXCLUSIVE is set, then CREATE must also be set.
** (d) if DELETEONCLOSE is set, then CREATE must also be set.
*/
assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
assert(isCreate==0 || isReadWrite);
assert(isExclusive==0 || isCreate);
assert(isDelete==0 || isCreate);
- /* The main DB, main journal, WAL file and master journal are never
+ /* The main DB, main journal, WAL file and master journal are never
** automatically deleted. Nor are they ever temporary files. */
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
/* Assert that the upper layer has set one of the "file-type" flags. */
- assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
- || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
- || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
+ assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
+ || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
+ || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
);
assert( pFile!=0 );
memset(pFile, 0, sizeof(winFile));
@@ -36185,12 +36570,12 @@
sqlite3_log(SQLITE_ERROR,
"sqlite3_temp_directory variable should be set for WinRT");
}
#endif
- /* If the second argument to this function is NULL, generate a
- ** temporary file name to use
+ /* If the second argument to this function is NULL, generate a
+ ** temporary file name to use
*/
if( !zUtf8Name ){
assert( isDelete && !isOpenJournal );
rc = winGetTempname(pVfs, &zTmpname);
if( rc!=SQLITE_OK ){
@@ -36226,12 +36611,12 @@
dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
}else{
dwDesiredAccess = GENERIC_READ;
}
- /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is
- ** created. SQLite doesn't use it to indicate "exclusive access"
+ /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is
+ ** created. SQLite doesn't use it to indicate "exclusive access"
** as it is usually understood.
*/
if( isExclusive ){
/* Creates a new file, only if it does not already exist. */
/* If the file exists, it fails. */
@@ -36316,11 +36701,11 @@
pFile->lastErrno = lastErrno;
winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
sqlite3_free(zConverted);
sqlite3_free(zTmpname);
if( isReadWrite && !isExclusive ){
- return winOpen(pVfs, zName, id,
+ return winOpen(pVfs, zName, id,
((flags|SQLITE_OPEN_READONLY) &
~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
pOutFlags);
}else{
return SQLITE_CANTOPEN_BKPT;
@@ -36525,18 +36910,18 @@
if( osIsNT() ){
int cnt = 0;
WIN32_FILE_ATTRIBUTE_DATA sAttrData;
memset(&sAttrData, 0, sizeof(sAttrData));
while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
- GetFileExInfoStandard,
+ GetFileExInfoStandard,
&sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){}
if( rc ){
/* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file
** as if it does not exist.
*/
if( flags==SQLITE_ACCESS_EXISTS
- && sAttrData.nFileSizeHigh==0
+ && sAttrData.nFileSizeHigh==0
&& sAttrData.nFileSizeLow==0 ){
attr = INVALID_FILE_ATTRIBUTES;
}else{
attr = sAttrData.dwFileAttributes;
}
@@ -36631,11 +37016,11 @@
sqlite3_vfs *pVfs, /* Pointer to vfs object */
const char *zRelative, /* Possibly relative input path */
int nFull, /* Size of output buffer in bytes */
char *zFull /* Output buffer */
){
-
+
#if defined(__CYGWIN__)
SimulateIOError( return SQLITE_ERROR );
UNUSED_PARAMETER(nFull);
assert( nFull>=pVfs->mxPathname );
if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){
@@ -36944,24 +37329,24 @@
** the current time and date as a Julian Day number times 86_400_000. In
** other words, write into *piNow the number of milliseconds since the Julian
** epoch of noon in Greenwich on November 24, 4714 B.C according to the
** proleptic Gregorian calendar.
**
-** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
+** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
** cannot be found.
*/
static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
- /* FILETIME structure is a 64-bit value representing the number of
- 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
+ /* FILETIME structure is a 64-bit value representing the number of
+ 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
*/
FILETIME ft;
static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000;
#ifdef SQLITE_TEST
static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
#endif
/* 2^32 - to avoid use of LL and warnings in gcc */
- static const sqlite3_int64 max32BitValue =
+ static const sqlite3_int64 max32BitValue =
(sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 +
(sqlite3_int64)294967296;
#if SQLITE_OS_WINCE
SYSTEMTIME time;
@@ -36973,11 +37358,11 @@
#else
osGetSystemTimeAsFileTime( &ft );
#endif
*piNow = winFiletimeEpoch +
- ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) +
+ ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) +
(sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000;
#ifdef SQLITE_TEST
if( sqlite3_current_time ){
*piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
@@ -37092,11 +37477,11 @@
};
#endif
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
- assert( ArraySize(aSyscall)==76 );
+ assert( ArraySize(aSyscall)==77 );
/* get memory map allocation granularity */
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
#if SQLITE_OS_WINRT
osGetNativeSystemInfo(&winSysInfo);
@@ -37110,14 +37495,14 @@
#if defined(SQLITE_WIN32_HAS_WIDE)
sqlite3_vfs_register(&winLongPathVfs, 0);
#endif
- return SQLITE_OK;
+ return SQLITE_OK;
}
-SQLITE_API int sqlite3_os_end(void){
+SQLITE_API int sqlite3_os_end(void){
#if SQLITE_OS_WINRT
if( sleepObj!=NULL ){
osCloseHandle(sleepObj);
sleepObj = NULL;
}
@@ -49189,20 +49574,20 @@
**
** After 5 RETRYs, we begin calling sqlite3OsSleep(). The first few
** calls to sqlite3OsSleep() have a delay of 1 microsecond. Really this
** is more of a scheduler yield than an actual delay. But on the 10th
** an subsequent retries, the delays start becoming longer and longer,
- ** so that on the 100th (and last) RETRY we delay for 21 milliseconds.
- ** The total delay time before giving up is less than 1 second.
+ ** so that on the 100th (and last) RETRY we delay for 323 milliseconds.
+ ** The total delay time before giving up is less than 10 seconds.
*/
if( cnt>5 ){
int nDelay = 1; /* Pause time in microseconds */
if( cnt>100 ){
VVA_ONLY( pWal->lockError = 1; )
return SQLITE_PROTOCOL;
}
- if( cnt>=10 ) nDelay = (cnt-9)*238; /* Max delay 21ms. Total delay 996ms */
+ if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39;
sqlite3OsSleep(pWal->pVfs, nDelay);
}
if( !useWal ){
rc = walIndexReadHdr(pWal, pChanged);
@@ -51314,11 +51699,11 @@
/* If the client is reading or writing an index and the schema is
** not loaded, then it is too difficult to actually check to see if
** the correct locks are held. So do not bother - just return true.
** This case does not come up very often anyhow.
*/
- if( isIndex && (!pSchema || (pSchema->flags&DB_SchemaLoaded)==0) ){
+ if( isIndex && (!pSchema || (pSchema->schemaFlags&DB_SchemaLoaded)==0) ){
return 1;
}
/* Figure out the root-page that the lock should be held on. For table
** b-trees, this is just the root page of the b-tree being read or
@@ -52784,11 +53169,11 @@
return pBt->nPage;
}
SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){
assert( sqlite3BtreeHoldsMutex(p) );
assert( ((p->pBt->nPage)&0x8000000)==0 );
- return (int)btreePagecount(p->pBt);
+ return btreePagecount(p->pBt);
}
/*
** Get a page from the pager and initialize it. This routine is just a
** convenience wrapper around separate calls to btreeGetPage() and
@@ -56893,11 +57278,12 @@
int nSkip = (iChild ? 4 : 0);
if( *pRC ) return;
assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
- assert( pPage->nCell<=MX_CELL(pPage->pBt) && MX_CELL(pPage->pBt)<=10921 );
+ assert( MX_CELL(pPage->pBt)<=10921 );
+ assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB );
assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) );
assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
/* The cell should normally be sized correctly. However, when moving a
** malformed cell from a leaf page to an interior page, if the cell size
@@ -61582,10 +61968,72 @@
FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAnalyzeTableFuncs);
for(i=0; idb;
+
+ /* Skip over any TK_COLLATE nodes */
+ pExpr = sqlite3ExprSkipCollate(pExpr);
+
+ if( !pExpr ){
+ pVal = valueNew(db, pAlloc);
+ if( pVal ){
+ sqlite3VdbeMemSetNull((Mem*)pVal);
+ }
+ }else if( pExpr->op==TK_VARIABLE
+ || NEVER(pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
+ ){
+ Vdbe *v;
+ int iBindVar = pExpr->iColumn;
+ sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar);
+ if( (v = pParse->pReprepare)!=0 ){
+ pVal = valueNew(db, pAlloc);
+ if( pVal ){
+ rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]);
+ if( rc==SQLITE_OK ){
+ sqlite3ValueApplyAffinity(pVal, affinity, ENC(db));
+ }
+ pVal->db = pParse->db;
+ }
+ }
+ }else{
+ rc = valueFromExpr(db, pExpr, ENC(db), affinity, &pVal, pAlloc);
+ }
+
+ assert( pVal==0 || pVal->db==db );
+ *ppVal = pVal;
+ return rc;
+}
/*
** This function is used to allocate and populate UnpackedRecord
** structures intended to be compared against sample index keys stored
** in the sqlite_stat4 table.
@@ -61622,52 +62070,90 @@
Expr *pExpr, /* The expression to extract a value from */
u8 affinity, /* Affinity to use */
int iVal, /* Array element to populate */
int *pbOk /* OUT: True if value was extracted */
){
- int rc = SQLITE_OK;
+ int rc;
sqlite3_value *pVal = 0;
- sqlite3 *db = pParse->db;
-
-
struct ValueNewStat4Ctx alloc;
+
alloc.pParse = pParse;
alloc.pIdx = pIdx;
alloc.ppRec = ppRec;
alloc.iVal = iVal;
- /* Skip over any TK_COLLATE nodes */
- pExpr = sqlite3ExprSkipCollate(pExpr);
-
- if( !pExpr ){
- pVal = valueNew(db, &alloc);
- if( pVal ){
- sqlite3VdbeMemSetNull((Mem*)pVal);
- }
- }else if( pExpr->op==TK_VARIABLE
- || NEVER(pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
- ){
- Vdbe *v;
- int iBindVar = pExpr->iColumn;
- sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar);
- if( (v = pParse->pReprepare)!=0 ){
- pVal = valueNew(db, &alloc);
- if( pVal ){
- rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]);
- if( rc==SQLITE_OK ){
- sqlite3ValueApplyAffinity(pVal, affinity, ENC(db));
- }
- pVal->db = pParse->db;
- }
- }
- }else{
- rc = valueFromExpr(db, pExpr, ENC(db), affinity, &pVal, &alloc);
- }
+ rc = stat4ValueFromExpr(pParse, pExpr, affinity, &alloc, &pVal);
+ assert( pVal==0 || pVal->db==pParse->db );
*pbOk = (pVal!=0);
+ return rc;
+}
- assert( pVal==0 || pVal->db==db );
- return rc;
+/*
+** Attempt to extract a value from expression pExpr using the methods
+** as described for sqlite3Stat4ProbeSetValue() above.
+**
+** If successful, set *ppVal to point to a new value object and return
+** SQLITE_OK. If no value can be extracted, but no other error occurs
+** (e.g. OOM), return SQLITE_OK and set *ppVal to NULL. Or, if an error
+** does occur, return an SQLite error code. The final value of *ppVal
+** is undefined in this case.
+*/
+SQLITE_PRIVATE int sqlite3Stat4ValueFromExpr(
+ Parse *pParse, /* Parse context */
+ Expr *pExpr, /* The expression to extract a value from */
+ u8 affinity, /* Affinity to use */
+ sqlite3_value **ppVal /* OUT: New value object (or NULL) */
+){
+ return stat4ValueFromExpr(pParse, pExpr, affinity, 0, ppVal);
+}
+
+/*
+** Extract the iCol-th column from the nRec-byte record in pRec. Write
+** the column value into *ppVal. If *ppVal is initially NULL then a new
+** sqlite3_value object is allocated.
+**
+** If *ppVal is initially NULL then the caller is responsible for
+** ensuring that the value written into *ppVal is eventually freed.
+*/
+SQLITE_PRIVATE int sqlite3Stat4Column(
+ sqlite3 *db, /* Database handle */
+ const void *pRec, /* Pointer to buffer containing record */
+ int nRec, /* Size of buffer pRec in bytes */
+ int iCol, /* Column to extract */
+ sqlite3_value **ppVal /* OUT: Extracted value */
+){
+ u32 t; /* a column type code */
+ int nHdr; /* Size of the header in the record */
+ int iHdr; /* Next unread header byte */
+ int iField; /* Next unread data byte */
+ int szField; /* Size of the current data field */
+ int i; /* Column index */
+ u8 *a = (u8*)pRec; /* Typecast byte array */
+ Mem *pMem = *ppVal; /* Write result into this Mem object */
+
+ assert( iCol>0 );
+ iHdr = getVarint32(a, nHdr);
+ if( nHdr>nRec || iHdr>=nHdr ) return SQLITE_CORRUPT_BKPT;
+ iField = nHdr;
+ for(i=0; i<=iCol; i++){
+ iHdr += getVarint32(&a[iHdr], t);
+ testcase( iHdr==nHdr );
+ testcase( iHdr==nHdr+1 );
+ if( iHdr>nHdr ) return SQLITE_CORRUPT_BKPT;
+ szField = sqlite3VdbeSerialTypeLen(t);
+ iField += szField;
+ }
+ testcase( iField==nRec );
+ testcase( iField==nRec+1 );
+ if( iField>nRec ) return SQLITE_CORRUPT_BKPT;
+ if( pMem==0 ){
+ pMem = *ppVal = sqlite3ValueNew(db);
+ if( pMem==0 ) return SQLITE_NOMEM;
+ }
+ sqlite3VdbeSerialGet(&a[iField-szField], t, pMem);
+ pMem->enc = ENC(db);
+ return SQLITE_OK;
}
/*
** Unless it is NULL, the argument must be an UnpackedRecord object returned
** by an earlier call to sqlite3Stat4ProbeSetValue(). This call deletes
@@ -61810,22 +62296,39 @@
pB->zSql = zTmp;
pB->isPrepareV2 = pA->isPrepareV2;
}
/*
-** Resize the Vdbe.aOp array so that it is at least one op larger than
-** it was.
+** Resize the Vdbe.aOp array so that it is at least nOp elements larger
+** than its current size. nOp is guaranteed to be less than or equal
+** to 1024/sizeof(Op).
**
** If an out-of-memory error occurs while resizing the array, return
-** SQLITE_NOMEM. In this case Vdbe.aOp and Vdbe.nOpAlloc remain
+** SQLITE_NOMEM. In this case Vdbe.aOp and Parse.nOpAlloc remain
** unchanged (this is so that any opcodes already allocated can be
** correctly deallocated along with the rest of the Vdbe).
*/
-static int growOpArray(Vdbe *v){
+static int growOpArray(Vdbe *v, int nOp){
VdbeOp *pNew;
Parse *p = v->pParse;
+
+ /* The SQLITE_TEST_REALLOC_STRESS compile-time option is designed to force
+ ** more frequent reallocs and hence provide more opportunities for
+ ** simulated OOM faults. SQLITE_TEST_REALLOC_STRESS is generally used
+ ** during testing only. With SQLITE_TEST_REALLOC_STRESS grow the op array
+ ** by the minimum* amount required until the size reaches 512. Normal
+ ** operation (without SQLITE_TEST_REALLOC_STRESS) is to double the current
+ ** size of the op array or add 1KB of space, whichever is smaller. */
+#ifdef SQLITE_TEST_REALLOC_STRESS
+ int nNew = (p->nOpAlloc>=512 ? p->nOpAlloc*2 : p->nOpAlloc+nOp);
+#else
int nNew = (p->nOpAlloc ? p->nOpAlloc*2 : (int)(1024/sizeof(Op)));
+ UNUSED_PARAMETER(nOp);
+#endif
+
+ assert( nOp<=(1024/sizeof(Op)) );
+ assert( nNew>=(p->nOpAlloc+nOp) );
pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op));
if( pNew ){
p->nOpAlloc = sqlite3DbMallocSize(p->db, pNew)/sizeof(Op);
v->aOp = pNew;
}
@@ -61865,11 +62368,11 @@
i = p->nOp;
assert( p->magic==VDBE_MAGIC_INIT );
assert( op>0 && op<0xff );
if( p->pParse->nOpAlloc<=i ){
- if( growOpArray(p) ){
+ if( growOpArray(p, 1) ){
return 1;
}
}
p->nOp++;
pOp = &p->aOp[i];
@@ -62225,11 +62728,11 @@
}
sqlite3DbFree(p->db, pParse->aLabel);
pParse->aLabel = 0;
pParse->nLabel = 0;
*pMaxFuncArgs = nMaxArgs;
- assert( p->bIsReader!=0 || p->btreeMask==0 );
+ assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) );
}
/*
** Return the address of the next instruction to be inserted.
*/
@@ -62252,11 +62755,11 @@
SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){
VdbeOp *aOp = p->aOp;
assert( aOp && !p->db->mallocFailed );
/* Check that sqlite3VdbeUsesBtree() was not called on this VM */
- assert( p->btreeMask==0 );
+ assert( DbMaskAllZero(p->btreeMask) );
resolveP2Values(p, pnMaxArg);
*pnOp = p->nOp;
p->aOp = 0;
return aOp;
@@ -62267,11 +62770,11 @@
** address of the first operation added.
*/
SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){
int addr;
assert( p->magic==VDBE_MAGIC_INIT );
- if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p) ){
+ if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){
return 0;
}
addr = p->nOp;
if( ALWAYS(nOp>0) ){
int i;
@@ -62452,11 +62955,11 @@
/*
** Change the opcode at addr into OP_Noop
*/
SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
- if( p->aOp ){
+ if( addrnOp ){
VdbeOp *pOp = &p->aOp[addr];
sqlite3 *db = p->db;
freeP4(db, pOp->p4type, pOp->p4.p);
memset(pOp, 0, sizeof(pOp[0]));
pOp->opcode = OP_Noop;
@@ -62837,13 +63340,13 @@
** p->btreeMask of databases that will require a lock.
*/
SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){
assert( i>=0 && idb->nDb && i<(int)sizeof(yDbMask)*8 );
assert( i<(int)sizeof(p->btreeMask)*8 );
- p->btreeMask |= ((yDbMask)1)<btreeMask, i);
if( i!=1 && sqlite3BtreeSharable(p->db->aDb[i].pBt) ){
- p->lockMask |= ((yDbMask)1)<lockMask, i);
}
}
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
/*
@@ -62867,20 +63370,19 @@
** this routine is N*N. But as N is rarely more than 1, this should not
** be a problem.
*/
SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe *p){
int i;
- yDbMask mask;
sqlite3 *db;
Db *aDb;
int nDb;
- if( p->lockMask==0 ) return; /* The common case */
+ if( DbMaskAllZero(p->lockMask) ) return; /* The common case */
db = p->db;
aDb = db->aDb;
nDb = db->nDb;
- for(i=0, mask=1; ilockMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){
+ for(i=0; ilockMask,i) && ALWAYS(aDb[i].pBt!=0) ){
sqlite3BtreeEnter(aDb[i].pBt);
}
}
}
#endif
@@ -62889,20 +63391,19 @@
/*
** Unlock all of the btrees previously locked by a call to sqlite3VdbeEnter().
*/
SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe *p){
int i;
- yDbMask mask;
sqlite3 *db;
Db *aDb;
int nDb;
- if( p->lockMask==0 ) return; /* The common case */
+ if( DbMaskAllZero(p->lockMask) ) return; /* The common case */
db = p->db;
aDb = db->aDb;
nDb = db->nDb;
- for(i=0, mask=1; ilockMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){
+ for(i=0; ilockMask,i) && ALWAYS(aDb[i].pBt!=0) ){
sqlite3BtreeLeave(aDb[i].pBt);
}
}
}
#endif
@@ -63869,11 +64370,11 @@
int cnt = 0;
int nWrite = 0;
int nRead = 0;
p = db->pVdbe;
while( p ){
- if( p->magic==VDBE_MAGIC_RUN && p->pc>=0 ){
+ if( sqlite3_stmt_busy((sqlite3_stmt*)p) ){
cnt++;
if( p->readOnly==0 ) nWrite++;
if( p->bIsReader ) nRead++;
}
p = p->pNext;
@@ -64029,11 +64530,10 @@
/* Lock all btrees used by the statement */
sqlite3VdbeEnter(p);
/* Check for one of the special errors */
mrc = p->rc & 0xff;
- assert( p->rc!=SQLITE_IOERR_BLOCKED ); /* This error no longer exists */
isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR
|| mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL;
if( isSpecialError ){
/* If the query was read-only and the error code is SQLITE_INTERRUPT,
** no rollback is necessary. Otherwise, at least a savepoint
@@ -64514,11 +65014,11 @@
/*
** Return the serial-type for the value stored in pMem.
*/
SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
int flags = pMem->flags;
- int n;
+ u32 n;
if( flags&MEM_Null ){
return 0;
}
if( flags&MEM_Int ){
@@ -64544,15 +65044,15 @@
}
if( flags&MEM_Real ){
return 7;
}
assert( pMem->db->mallocFailed || flags&(MEM_Str|MEM_Blob) );
- n = pMem->n;
+ assert( pMem->n>=0 );
+ n = (u32)pMem->n;
if( flags & MEM_Zero ){
n += pMem->u.nZero;
}
- assert( n>=0 );
return ((n*2) + 12 + ((flags&MEM_Str)!=0));
}
/*
** Return the length of the data corresponding to the supplied serial-type.
@@ -65315,10 +65815,11 @@
/* rc==0 here means that one or both of the keys ran out of fields and
** all the fields up to that point were equal. Return the the default_rc
** value. */
assert( CORRUPT_DB
|| pPKey2->default_rc==vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)
+ || pKeyInfo->db->mallocFailed
);
return pPKey2->default_rc;
}
/*
@@ -65480,10 +65981,11 @@
assert( (res==0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)==0)
|| (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0)
|| (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0)
|| CORRUPT_DB
+ || pPKey2->pKeyInfo->db->mallocFailed
);
return res;
}
/*
@@ -67064,11 +67566,11 @@
/*
** Return true if the prepared statement is in need of being reset.
*/
SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){
Vdbe *v = (Vdbe*)pStmt;
- return v!=0 && v->pc>0 && v->magic==VDBE_MAGIC_RUN;
+ return v!=0 && v->pc>=0 && v->magic==VDBE_MAGIC_RUN;
}
/*
** Return a pointer to the next prepared statement after pStmt associated
** with database connection pDb. If pStmt is NULL, return the first
@@ -67514,10 +68016,16 @@
**
** M is an integer, 2 or 3, that indices how many different ways the
** branch can go. It is usually 2. "I" is the direction the branch
** goes. 0 means falls through. 1 means branch is taken. 2 means the
** second alternative branch is taken.
+**
+** iSrcLine is the source code line (from the __LINE__ macro) that
+** generated the VDBE instruction. This instrumentation assumes that all
+** source code is in a single file (the amalgamation). Special values 1
+** and 2 for the iSrcLine parameter mean that this particular branch is
+** always taken or never taken, respectively.
*/
#if !defined(SQLITE_VDBE_COVERAGE)
# define VdbeBranchTaken(I,M)
#else
# define VdbeBranchTaken(I,M) vdbeTakeBranch(pOp->iSrcLine,I,M)
@@ -67622,25 +68130,25 @@
** do so without loss of information. In other words, if the string
** looks like a number, convert it into a number. If it does not
** look like a number, leave it alone.
*/
static void applyNumericAffinity(Mem *pRec){
- if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){
- double rValue;
- i64 iValue;
- u8 enc = pRec->enc;
- if( (pRec->flags&MEM_Str)==0 ) return;
- if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return;
- if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){
- pRec->u.i = iValue;
- pRec->flags |= MEM_Int;
- }else{
- pRec->r = rValue;
- pRec->flags |= MEM_Real;
- }
- }
-}
+ double rValue;
+ i64 iValue;
+ u8 enc = pRec->enc;
+ if( (pRec->flags&MEM_Str)==0 ) return;
+ if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return;
+ if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){
+ pRec->u.i = iValue;
+ pRec->flags |= MEM_Int;
+ }else{
+ pRec->r = rValue;
+ pRec->flags |= MEM_Real;
+ }
+}
+#define ApplyNumericAffinity(X) \
+ if(((X)->flags&(MEM_Real|MEM_Int))==0){applyNumericAffinity(X);}
/*
** Processing is determine by the affinity parameter:
**
** SQLITE_AFF_INTEGER:
@@ -67673,11 +68181,11 @@
}
pRec->flags &= ~(MEM_Real|MEM_Int);
}else if( affinity!=SQLITE_AFF_NONE ){
assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
|| affinity==SQLITE_AFF_NUMERIC );
- applyNumericAffinity(pRec);
+ ApplyNumericAffinity(pRec);
if( pRec->flags & MEM_Real ){
sqlite3VdbeIntegerAffinity(pRec);
}
}
}
@@ -68254,16 +68762,18 @@
break;
}
/* Opcode: InitCoroutine P1 P2 P3 * *
**
-** Set up register P1 so that it will OP_Yield to the co-routine
+** Set up register P1 so that it will Yield to the coroutine
** located at address P3.
**
-** If P2!=0 then the co-routine implementation immediately follows
-** this opcode. So jump over the co-routine implementation to
+** If P2!=0 then the coroutine implementation immediately follows
+** this opcode. So jump over the coroutine implementation to
** address P2.
+**
+** See also: EndCoroutine
*/
case OP_InitCoroutine: { /* jump */
assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
assert( pOp->p2>=0 && pOp->p2nOp );
assert( pOp->p3>=0 && pOp->p3nOp );
@@ -68275,13 +68785,15 @@
break;
}
/* Opcode: EndCoroutine P1 * * * *
**
-** The instruction at the address in register P1 is an OP_Yield.
-** Jump to the P2 parameter of that OP_Yield.
+** The instruction at the address in register P1 is a Yield.
+** Jump to the P2 parameter of that Yield.
** After the jump, register P1 becomes undefined.
+**
+** See also: InitCoroutine
*/
case OP_EndCoroutine: { /* in1 */
VdbeOp *pCaller;
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags==MEM_Int );
@@ -68294,15 +68806,20 @@
break;
}
/* Opcode: Yield P1 P2 * * *
**
-** Swap the program counter with the value in register P1.
+** Swap the program counter with the value in register P1. This
+** has the effect of yielding to a coroutine.
**
-** If the co-routine ends with OP_Yield or OP_Return then continue
-** to the next instruction. But if the co-routine ends with
-** OP_EndCoroutine, jump immediately to P2.
+** If the coroutine that is launched by this instruction ends with
+** Yield or Return then continue to the next instruction. But if
+** the coroutine launched by this instruction ends with
+** EndCoroutine, then jump to P2 rather than continuing with the
+** next instruction.
+**
+** See also: InitCoroutine
*/
case OP_Yield: { /* in1, jump */
int pcDest;
pIn1 = &aMem[pOp->p1];
assert( VdbeMemDynamic(pIn1)==0 );
@@ -68461,11 +68978,11 @@
/* Opcode: String8 * P2 * P4 *
** Synopsis: r[P2]='P4'
**
** P4 points to a nul terminated UTF-8 string. This opcode is transformed
-** into an OP_String before it is executed for the first time. During
+** into a String before it is executed for the first time. During
** this transformation, the length of string P4 is computed and stored
** as the P1 parameter.
*/
case OP_String8: { /* same as TK_STRING, out2-prerelease */
assert( pOp->p4.z!=0 );
@@ -69683,14 +70200,18 @@
break;
}
/* Opcode: Once P1 P2 * * *
**
-** Check if OP_Once flag P1 is set. If so, jump to instruction P2. Otherwise,
-** set the flag and fall through to the next instruction. In other words,
-** this opcode causes all following opcodes up through P2 (but not including
-** P2) to run just once and to be skipped on subsequent times through the loop.
+** Check the "once" flag number P1. If it is set, jump to instruction P2.
+** Otherwise, set the flag and fall through to the next instruction.
+** In other words, this opcode causes all following opcodes up through P2
+** (but not including P2) to run just once and to be skipped on subsequent
+** times through the loop.
+**
+** All "once" flags are initially cleared whenever a prepared statement
+** first begins to run.
*/
case OP_Once: { /* jump */
assert( pOp->p1nOnceFlag );
VdbeBranchTaken(p->aOnceFlag[pOp->p1]!=0, 2);
if( p->aOnceFlag[pOp->p1] ){
@@ -69703,17 +70224,17 @@
/* Opcode: If P1 P2 P3 * *
**
** Jump to P2 if the value in register P1 is true. The value
** is considered true if it is numeric and non-zero. If the value
-** in P1 is NULL then take the jump if P3 is non-zero.
+** in P1 is NULL then take the jump if and only if P3 is non-zero.
*/
/* Opcode: IfNot P1 P2 P3 * *
**
** Jump to P2 if the value in register P1 is False. The value
** is considered false if it has a numeric value of zero. If the value
-** in P1 is NULL then take the jump if P3 is zero.
+** in P1 is NULL then take the jump if and only if P3 is non-zero.
*/
case OP_If: /* jump, in1 */
case OP_IfNot: { /* jump, in1 */
int c;
pIn1 = &aMem[pOp->p1];
@@ -70521,11 +71042,11 @@
int iGen;
assert( p->bIsReader );
assert( p->readOnly==0 || pOp->p2==0 );
assert( pOp->p1>=0 && pOp->p1nDb );
- assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 );
+ assert( DbMaskTest(p->btreeMask, pOp->p1) );
if( pOp->p2 && (db->flags & SQLITE_QueryOnly)!=0 ){
rc = SQLITE_READONLY;
goto abort_due_to_error;
}
pBt = db->aDb[pOp->p1].pBt;
@@ -70616,11 +71137,11 @@
iDb = pOp->p1;
iCookie = pOp->p3;
assert( pOp->p3=0 && iDbnDb );
assert( db->aDb[iDb].pBt!=0 );
- assert( (p->btreeMask & (((yDbMask)1)<btreeMask, iDb) );
sqlite3BtreeGetMeta(db->aDb[iDb].pBt, iCookie, (u32 *)&iMeta);
pOut->u.i = iMeta;
break;
}
@@ -70637,11 +71158,11 @@
*/
case OP_SetCookie: { /* in3 */
Db *pDb;
assert( pOp->p2p1>=0 && pOp->p1nDb );
- assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 );
+ assert( DbMaskTest(p->btreeMask, pOp->p1) );
assert( p->readOnly==0 );
pDb = &db->aDb[pOp->p1];
assert( pDb->pBt!=0 );
assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) );
pIn3 = &aMem[pOp->p3];
@@ -70692,11 +71213,25 @@
** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo
** structure, then said structure defines the content and collating
** sequence of the index being opened. Otherwise, if P4 is an integer
** value, it is set to the number of columns in the table.
**
-** See also OpenWrite.
+** See also: OpenWrite, ReopenIdx
+*/
+/* Opcode: ReopenIdx P1 P2 P3 P4 P5
+** Synopsis: root=P2 iDb=P3
+**
+** The ReopenIdx opcode works exactly like ReadOpen except that it first
+** checks to see if the cursor on P1 is already open with a root page
+** number of P2 and if it is this opcode becomes a no-op. In other words,
+** if the cursor is already open, do not reopen it.
+**
+** The ReopenIdx opcode may only be used with P5==0 and with P4 being
+** a P4_KEYINFO object. Furthermore, the P3 value must be the same as
+** every other ReopenIdx or OpenRead for the same cursor number.
+**
+** See the OpenRead opcode documentation for additional information.
*/
/* Opcode: OpenWrite P1 P2 P3 P4 P5
** Synopsis: root=P2 iDb=P3
**
** Open a read/write cursor named P1 on the table or index whose root
@@ -70714,10 +71249,23 @@
** in read/write mode. For a given table, there can be one or more read-only
** cursors or a single read/write cursor but not both.
**
** See also OpenRead.
*/
+case OP_ReopenIdx: {
+ VdbeCursor *pCur;
+
+ assert( pOp->p5==0 );
+ assert( pOp->p4type==P4_KEYINFO );
+ pCur = p->apCsr[pOp->p1];
+ if( pCur && pCur->pgnoRoot==(u32)pOp->p2 ){
+ assert( pCur->iDb==pOp->p3 ); /* Guaranteed by the code generator */
+ break;
+ }
+ /* If the cursor is not currently open or is open on a different
+ ** index, then fall through into OP_OpenRead to force a reopen */
+}
case OP_OpenRead:
case OP_OpenWrite: {
int nField;
KeyInfo *pKeyInfo;
int p2;
@@ -70728,11 +71276,12 @@
Db *pDb;
assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR))==pOp->p5 );
assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 );
assert( p->bIsReader );
- assert( pOp->opcode==OP_OpenRead || p->readOnly==0 );
+ assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx
+ || p->readOnly==0 );
if( p->expired ){
rc = SQLITE_ABORT;
break;
}
@@ -70740,11 +71289,11 @@
nField = 0;
pKeyInfo = 0;
p2 = pOp->p2;
iDb = pOp->p3;
assert( iDb>=0 && iDbnDb );
- assert( (p->btreeMask & (((yDbMask)1)<btreeMask, iDb) );
pDb = &db->aDb[iDb];
pX = pDb->pBt;
assert( pX!=0 );
if( pOp->opcode==OP_OpenWrite ){
wrFlag = 1;
@@ -70785,10 +71334,11 @@
testcase( nField==0 ); /* Table with INTEGER PRIMARY KEY and nothing else */
pCur = allocateCursor(p, pOp->p1, nField, iDb, 1);
if( pCur==0 ) goto no_mem;
pCur->nullRow = 1;
pCur->isOrdered = 1;
+ pCur->pgnoRoot = p2;
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor);
pCur->pKeyInfo = pKeyInfo;
assert( OPFLAG_BULKCSR==BTREE_BULKLOAD );
sqlite3BtreeCursorHints(pCur->pCursor, (pOp->p5 & OPFLAG_BULKCSR));
@@ -70939,11 +71489,11 @@
sqlite3VdbeFreeCursor(p, p->apCsr[pOp->p1]);
p->apCsr[pOp->p1] = 0;
break;
}
-/* Opcode: SeekGe P1 P2 P3 P4 *
+/* Opcode: SeekGE P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
** use the value in register P3 as the key. If cursor P1 refers
** to an SQL index, then P3 is the first in an array of P4 registers
@@ -70950,14 +71500,18 @@
** that are used as an unpacked index key.
**
** Reposition cursor P1 so that it points to the smallest entry that
** is greater than or equal to the key value. If there are no records
** greater than or equal to the key and P2 is not zero, then jump to P2.
+**
+** This opcode leaves the cursor configured to move in forward order,
+** from the beginning toward the end. In other words, the cursor is
+** configured to use Next, not Prev.
**
** See also: Found, NotFound, SeekLt, SeekGt, SeekLe
*/
-/* Opcode: SeekGt P1 P2 P3 P4 *
+/* Opcode: SeekGT P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
** use the value in register P3 as a key. If cursor P1 refers
** to an SQL index, then P3 is the first in an array of P4 registers
@@ -70964,14 +71518,18 @@
** that are used as an unpacked index key.
**
** Reposition cursor P1 so that it points to the smallest entry that
** is greater than the key value. If there are no records greater than
** the key and P2 is not zero, then jump to P2.
+**
+** This opcode leaves the cursor configured to move in forward order,
+** from the beginning toward the end. In other words, the cursor is
+** configured to use Next, not Prev.
**
** See also: Found, NotFound, SeekLt, SeekGe, SeekLe
*/
-/* Opcode: SeekLt P1 P2 P3 P4 *
+/* Opcode: SeekLT P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
** use the value in register P3 as a key. If cursor P1 refers
** to an SQL index, then P3 is the first in an array of P4 registers
@@ -70978,14 +71536,18 @@
** that are used as an unpacked index key.
**
** Reposition cursor P1 so that it points to the largest entry that
** is less than the key value. If there are no records less than
** the key and P2 is not zero, then jump to P2.
+**
+** This opcode leaves the cursor configured to move in reverse order,
+** from the end toward the beginning. In other words, the cursor is
+** configured to use Prev, not Next.
**
** See also: Found, NotFound, SeekGt, SeekGe, SeekLe
*/
-/* Opcode: SeekLe P1 P2 P3 P4 *
+/* Opcode: SeekLE P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
** use the value in register P3 as a key. If cursor P1 refers
** to an SQL index, then P3 is the first in an array of P4 registers
@@ -70992,10 +71554,14 @@
** that are used as an unpacked index key.
**
** Reposition cursor P1 so that it points to the largest entry that
** is less than or equal to the key value. If there are no records
** less than or equal to the key and P2 is not zero, then jump to P2.
+**
+** This opcode leaves the cursor configured to move in reverse order,
+** from the end toward the beginning. In other words, the cursor is
+** configured to use Prev, not Next.
**
** See also: Found, NotFound, SeekGt, SeekGe, SeekLt
*/
case OP_SeekLT: /* jump, in3 */
case OP_SeekLE: /* jump, in3 */
@@ -71018,16 +71584,19 @@
assert( OP_SeekGT == OP_SeekLT+3 );
assert( pC->isOrdered );
assert( pC->pCursor!=0 );
oc = pOp->opcode;
pC->nullRow = 0;
+#ifdef SQLITE_DEBUG
+ pC->seekOp = pOp->opcode;
+#endif
if( pC->isTable ){
/* The input value in P3 might be of any type: integer, real, string,
** blob, or NULL. But it needs to be an integer before we can do
** the seek, so covert it. */
pIn3 = &aMem[pOp->p3];
- applyNumericAffinity(pIn3);
+ ApplyNumericAffinity(pIn3);
iKey = sqlite3VdbeIntValue(pIn3);
pC->rowidIsValid = 0;
/* If the P3 value could not be converted into an integer without
** loss of information, then special processing is required... */
@@ -71172,10 +71741,14 @@
** record.
**
** Cursor P1 is on an index btree. If the record identified by P3 and P4
** is a prefix of any entry in P1 then a jump is made to P2 and
** P1 is left pointing at the matching entry.
+**
+** This operation leaves the cursor in a state where it can be
+** advanced in the forward direction. The Next instruction will work,
+** but not the Prev instruction.
**
** See also: NotFound, NoConflict, NotExists. SeekGe
*/
/* Opcode: NotFound P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
@@ -71187,10 +71760,14 @@
** Cursor P1 is on an index btree. If the record identified by P3 and P4
** is not the prefix of any entry in P1 then a jump is made to P2. If P1
** does contain an entry whose prefix matches the P3/P4 record then control
** falls through to the next instruction and P1 is left pointing at the
** matching entry.
+**
+** This operation leaves the cursor in a state where it cannot be
+** advanced in either direction. In other words, the Next and Prev
+** opcodes do not work after this operation.
**
** See also: Found, NotExists, NoConflict
*/
/* Opcode: NoConflict P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
@@ -71206,10 +71783,14 @@
** immediately to P2. If there is a match, fall through and leave the P1
** cursor pointing to the matching row.
**
** This opcode is similar to OP_NotFound with the exceptions that the
** branch is always taken if any part of the search key input is NULL.
+**
+** This operation leaves the cursor in a state where it cannot be
+** advanced in either direction. In other words, the Next and Prev
+** opcodes do not work after this operation.
**
** See also: NotFound, Found, NotExists
*/
case OP_NoConflict: /* jump, in3 */
case OP_NotFound: /* jump, in3 */
@@ -71229,10 +71810,13 @@
assert( pOp->p1>=0 && pOp->p1nCursor );
assert( pOp->p4type==P4_INT32 );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
+#ifdef SQLITE_DEBUG
+ pC->seekOp = pOp->opcode;
+#endif
pIn3 = &aMem[pOp->p3];
assert( pC->pCursor!=0 );
assert( pC->isTable==0 );
pFree = 0; /* Not needed. Only used to suppress a compiler warning. */
if( pOp->p4.i>0 ){
@@ -71299,10 +71883,14 @@
** with rowid P3 then leave the cursor pointing at that record and fall
** through to the next instruction.
**
** The OP_NotFound opcode performs the same operation on index btrees
** (with arbitrary multi-value keys).
+**
+** This opcode leaves the cursor in a state where it cannot be advanced
+** in either direction. In other words, the Next and Prev opcodes will
+** not work following this opcode.
**
** See also: Found, NotFound, NoConflict
*/
case OP_NotExists: { /* jump, in3 */
VdbeCursor *pC;
@@ -71313,10 +71901,13 @@
pIn3 = &aMem[pOp->p3];
assert( pIn3->flags & MEM_Int );
assert( pOp->p1>=0 && pOp->p1nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
+#ifdef SQLITE_DEBUG
+ pC->seekOp = 0;
+#endif
assert( pC->isTable );
assert( pC->pseudoTableReg==0 );
pCrsr = pC->pCursor;
assert( pCrsr!=0 );
res = 0;
@@ -71615,11 +72206,11 @@
** Delete the record at which the P1 cursor is currently pointing.
**
** The cursor will be left pointing at either the next or the previous
** record in the table. If it is left pointing at the next record, then
** the next Next instruction will be a no-op. Hence it is OK to delete
-** a record from within an Next loop.
+** a record from within a Next loop.
**
** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
** incremented (otherwise not).
**
** P1 must not be pseudo-table. It has to be a real table with
@@ -71675,16 +72266,16 @@
p->nChange = 0;
break;
}
/* Opcode: SorterCompare P1 P2 P3 P4
-** Synopsis: if key(P1)!=rtrim(r[P3],P4) goto P2
+** Synopsis: if key(P1)!=trim(r[P3],P4) goto P2
**
** P1 is a sorter cursor. This instruction compares a prefix of the
-** the record blob in register P3 against a prefix of the entry that
-** the sorter cursor currently points to. The final P4 fields of both
-** the P3 and sorter record are ignored.
+** record blob in register P3 against a prefix of the entry that
+** the sorter cursor currently points to. Only the first P4 fields
+** of r[P3] and the sorter record are compared.
**
** If either P3 or the sorter contains a NULL in one of their significant
** fields (not counting the P4 fields at the end which are ignored) then
** the comparison is assumed to be equal.
**
@@ -71692,18 +72283,18 @@
** each other. Jump to P2 if they are different.
*/
case OP_SorterCompare: {
VdbeCursor *pC;
int res;
- int nIgnore;
+ int nKeyCol;
pC = p->apCsr[pOp->p1];
assert( isSorter(pC) );
assert( pOp->p4type==P4_INT32 );
pIn3 = &aMem[pOp->p3];
- nIgnore = pOp->p4.i;
- rc = sqlite3VdbeSorterCompare(pC, pIn3, nIgnore, &res);
+ nKeyCol = pOp->p4.i;
+ rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res);
VdbeBranchTaken(res!=0,2);
if( res ){
pc = pOp->p2-1;
}
break;
@@ -71879,15 +72470,19 @@
break;
}
/* Opcode: Last P1 P2 * * *
**
-** The next use of the Rowid or Column or Next instruction for P1
+** The next use of the Rowid or Column or Prev instruction for P1
** will refer to the last entry in the database table or index.
** If the table or index is empty and P2>0, then jump immediately to P2.
** If P2 is 0 or if the table or index is not empty, fall through
** to the following instruction.
+**
+** This opcode leaves the cursor configured to move in reverse order,
+** from the end toward the beginning. In other words, the cursor is
+** configured to use Prev, not Next.
*/
case OP_Last: { /* jump */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
@@ -71901,10 +72496,13 @@
rc = sqlite3BtreeLast(pCrsr, &res);
pC->nullRow = (u8)res;
pC->deferredMoveto = 0;
pC->rowidIsValid = 0;
pC->cacheStatus = CACHE_STALE;
+#ifdef SQLITE_DEBUG
+ pC->seekOp = OP_Last;
+#endif
if( pOp->p2>0 ){
VdbeBranchTaken(res!=0,2);
if( res ) pc = pOp->p2 - 1;
}
break;
@@ -71937,10 +72535,14 @@
** The next use of the Rowid or Column or Next instruction for P1
** will refer to the first entry in the database table or index.
** If the table or index is empty and P2>0, then jump immediately to P2.
** If P2 is 0 or if the table or index is not empty, fall through
** to the following instruction.
+**
+** This opcode leaves the cursor configured to move in forward order,
+** from the beginning toward the end. In other words, the cursor is
+** configured to use Next, not Prev.
*/
case OP_Rewind: { /* jump */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
@@ -71948,10 +72550,13 @@
assert( pOp->p1>=0 && pOp->p1nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) );
res = 1;
+#ifdef SQLITE_DEBUG
+ pC->seekOp = OP_Rewind;
+#endif
if( isSorter(pC) ){
rc = sqlite3VdbeSorterRewind(db, pC, &res);
}else{
pCrsr = pC->pCursor;
assert( pCrsr );
@@ -71973,10 +72578,14 @@
**
** Advance cursor P1 so that it points to the next key/data pair in its
** table or index. If there are no more key/value pairs then fall through
** to the following instruction. But if the cursor advance was successful,
** jump immediately to P2.
+**
+** The Next opcode is only valid following an SeekGT, SeekGE, or
+** OP_Rewind opcode used to position the cursor. Next is not allowed
+** to follow SeekLT, SeekLE, or OP_Last.
**
** The P1 cursor must be for a real table, not a pseudo-table. P1 must have
** been opened prior to this opcode or the program will segfault.
**
** The P3 value is a hint to the btree implementation. If P3==1, that
@@ -71992,20 +72601,25 @@
**
** See also: Prev, NextIfOpen
*/
/* Opcode: NextIfOpen P1 P2 P3 P4 P5
**
-** This opcode works just like OP_Next except that if cursor P1 is not
+** This opcode works just like Next except that if cursor P1 is not
** open it behaves a no-op.
*/
/* Opcode: Prev P1 P2 P3 P4 P5
**
** Back up cursor P1 so that it points to the previous key/data pair in its
** table or index. If there is no previous key/value pairs then fall through
** to the following instruction. But if the cursor backup was successful,
** jump immediately to P2.
**
+**
+** The Prev opcode is only valid following an SeekLT, SeekLE, or
+** OP_Last opcode used to position the cursor. Prev is not allowed
+** to follow SeekGT, SeekGE, or OP_Rewind.
+**
** The P1 cursor must be for a real table, not a pseudo-table. If P1 is
** not open then the behavior is undefined.
**
** The P3 value is a hint to the btree implementation. If P3==1, that
** means P1 is an SQL index and that this instruction could have been
@@ -72018,11 +72632,11 @@
** If P5 is positive and the jump is taken, then event counter
** number P5-1 in the prepared statement is incremented.
*/
/* Opcode: PrevIfOpen P1 P2 P3 P4 P5
**
-** This opcode works just like OP_Prev except that if cursor P1 is not
+** This opcode works just like Prev except that if cursor P1 is not
** open it behaves a no-op.
*/
case OP_SorterNext: { /* jump */
VdbeCursor *pC;
int res;
@@ -72049,10 +72663,20 @@
testcase( res==1 );
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext );
assert( pOp->opcode!=OP_PrevIfOpen || pOp->p4.xAdvance==sqlite3BtreePrevious);
+
+ /* The Next opcode is only used after SeekGT, SeekGE, and Rewind.
+ ** The Prev opcode is only used after SeekLT, SeekLE, and Last. */
+ assert( pOp->opcode!=OP_Next || pOp->opcode!=OP_NextIfOpen
+ || pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE
+ || pC->seekOp==OP_Rewind || pC->seekOp==OP_Found);
+ assert( pOp->opcode!=OP_Prev || pOp->opcode!=OP_PrevIfOpen
+ || pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE
+ || pC->seekOp==OP_Last );
+
rc = pOp->p4.xAdvance(pC->pCursor, &res);
next_tail:
pC->cacheStatus = CACHE_STALE;
VdbeBranchTaken(res==0,2);
if( res==0 ){
@@ -72331,11 +72955,11 @@
rc = SQLITE_LOCKED;
p->errorAction = OE_Abort;
}else{
iDb = pOp->p3;
assert( iCnt==1 );
- assert( (p->btreeMask & (((yDbMask)1)<btreeMask, iDb) );
iMoved = 0; /* Not needed. Only to silence a warning. */
rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved);
pOut->flags = MEM_Int;
pOut->u.i = iMoved;
#ifndef SQLITE_OMIT_AUTOVACUUM
@@ -72371,11 +72995,11 @@
case OP_Clear: {
int nChange;
nChange = 0;
assert( p->readOnly==0 );
- assert( (p->btreeMask & (((yDbMask)1)<p2))!=0 );
+ assert( DbMaskTest(p->btreeMask, pOp->p2) );
rc = sqlite3BtreeClearTable(
db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0)
);
if( pOp->p3 ){
p->nChange += nChange;
@@ -72441,11 +73065,11 @@
int flags;
Db *pDb;
pgno = 0;
assert( pOp->p1>=0 && pOp->p1nDb );
- assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 );
+ assert( DbMaskTest(p->btreeMask, pOp->p1) );
assert( p->readOnly==0 );
pDb = &db->aDb[pOp->p1];
assert( pDb->pBt!=0 );
if( pOp->opcode==OP_CreateTable ){
/* flags = BTREE_INTKEY; */
@@ -72529,11 +73153,12 @@
/* Opcode: DropTable P1 * * P4 *
**
** Remove the internal (in-memory) data structures that describe
** the table named P4 in database P1. This is called after a table
-** is dropped in order to keep the internal representation of the
+** is dropped from disk (using the Destroy opcode) in order to keep
+** the internal representation of the
** schema consistent with what is on disk.
*/
case OP_DropTable: {
sqlite3UnlinkAndDeleteTable(db, pOp->p1, pOp->p4.z);
break;
@@ -72541,11 +73166,12 @@
/* Opcode: DropIndex P1 * * P4 *
**
** Remove the internal (in-memory) data structures that describe
** the index named P4 in database P1. This is called after an index
-** is dropped in order to keep the internal representation of the
+** is dropped from disk (using the Destroy opcode)
+** in order to keep the internal representation of the
** schema consistent with what is on disk.
*/
case OP_DropIndex: {
sqlite3UnlinkAndDeleteIndex(db, pOp->p1, pOp->p4.z);
break;
@@ -72553,11 +73179,12 @@
/* Opcode: DropTrigger P1 * * P4 *
**
** Remove the internal (in-memory) data structures that describe
** the trigger named P4 in database P1. This is called after a trigger
-** is dropped in order to keep the internal representation of the
+** is dropped from disk (using the Destroy opcode) in order to keep
+** the internal representation of the
** schema consistent with what is on disk.
*/
case OP_DropTrigger: {
sqlite3UnlinkAndDeleteTrigger(db, pOp->p1, pOp->p4.z);
break;
@@ -72606,11 +73233,11 @@
for(j=0; jp5nDb );
- assert( (p->btreeMask & (((yDbMask)1)<p5))!=0 );
+ assert( DbMaskTest(p->btreeMask, pOp->p5) );
z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot,
(int)pnErr->u.i, &nErr);
sqlite3DbFree(db, aRoot);
pnErr->u.i -= nErr;
sqlite3VdbeMemSetNull(pIn1);
@@ -72968,21 +73595,20 @@
pc = pOp->p2 - 1;
}
break;
}
-/* Opcode: IfNeg P1 P2 * * *
-** Synopsis: if r[P1]<0 goto P2
+/* Opcode: IfNeg P1 P2 P3 * *
+** Synopsis: r[P1]+=P3, if r[P1]<0 goto P2
**
-** If the value of register P1 is less than zero, jump to P2.
-**
-** It is illegal to use this instruction on a register that does
-** not contain an integer. An assertion fault will result if you try.
+** Register P1 must contain an integer. Add literal P3 to the value in
+** register P1 then if the value of register P1 is less than zero, jump to P2.
*/
case OP_IfNeg: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
+ pIn1->u.i += pOp->p3;
VdbeBranchTaken(pIn1->u.i<0, 2);
if( pIn1->u.i<0 ){
pc = pOp->p2 - 1;
}
break;
@@ -72991,13 +73617,10 @@
/* Opcode: IfZero P1 P2 P3 * *
** Synopsis: r[P1]+=P3, if r[P1]==0 goto P2
**
** The register P1 must contain an integer. Add literal P3 to the
** value in register P1. If the result is exactly 0, jump to P2.
-**
-** It is illegal to use this instruction on a register that does
-** not contain an integer. An assertion fault will result if you try.
*/
case OP_IfZero: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
pIn1->u.i += pOp->p3;
@@ -73266,11 +73889,11 @@
*/
case OP_IncrVacuum: { /* jump */
Btree *pBt;
assert( pOp->p1>=0 && pOp->p1nDb );
- assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 );
+ assert( DbMaskTest(p->btreeMask, pOp->p1) );
assert( p->readOnly==0 );
pBt = db->aDb[pOp->p1].pBt;
rc = sqlite3BtreeIncrVacuum(pBt);
VdbeBranchTaken(rc==SQLITE_DONE,2);
if( rc==SQLITE_DONE ){
@@ -73281,16 +73904,17 @@
}
#endif
/* Opcode: Expire P1 * * * *
**
-** Cause precompiled statements to become expired. An expired statement
-** fails with an error code of SQLITE_SCHEMA if it is ever executed
-** (via sqlite3_step()).
+** Cause precompiled statements to expire. When an expired statement
+** is executed using sqlite3_step() it will either automatically
+** reprepare itself (if it was originally created using sqlite3_prepare_v2())
+** or it will fail with SQLITE_SCHEMA.
**
** If P1 is 0, then all SQL statements become expired. If P1 is non-zero,
-** then only the currently executing statement is affected.
+** then only the currently executing statement is expired.
*/
case OP_Expire: {
if( !pOp->p1 ){
sqlite3ExpirePreparedStatements(db);
}else{
@@ -73318,11 +73942,11 @@
case OP_TableLock: {
u8 isWriteLock = (u8)pOp->p3;
if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){
int p1 = pOp->p1;
assert( p1>=0 && p1nDb );
- assert( (p->btreeMask & (((yDbMask)1)<btreeMask, p1) );
assert( isWriteLock==0 || isWriteLock==1 );
rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock);
if( (rc&0xFF)==SQLITE_LOCKED ){
const char *z = pOp->p4.z;
sqlite3SetString(&p->zErrMsg, db, "database table is locked: %s", z);
@@ -73768,11 +74392,11 @@
#ifdef SQLITE_USE_FCNTL_TRACE
zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
if( zTrace ){
int i;
for(i=0; inDb; i++){
- if( (MASKBIT(i) & p->btreeMask)==0 ) continue;
+ if( DbMaskTest(p->btreeMask, i)==0 ) continue;
sqlite3_file_control(db, db->aDb[i].zName, SQLITE_FCNTL_TRACE, zTrace);
}
}
#endif /* SQLITE_USE_FCNTL_TRACE */
#ifdef SQLITE_DEBUG
@@ -74758,11 +75382,11 @@
** If pKey2 is passed a NULL pointer, then it is assumed that the pCsr->aSpace
** has been allocated and contains an unpacked record that is used as key2.
*/
static void vdbeSorterCompare(
const VdbeCursor *pCsr, /* Cursor object (for pKeyInfo) */
- int nIgnore, /* Ignore the last nIgnore fields */
+ int nKeyCol, /* Num of columns. 0 means "all" */
const void *pKey1, int nKey1, /* Left side of comparison */
const void *pKey2, int nKey2, /* Right side of comparison */
int *pRes /* OUT: Result of comparison */
){
KeyInfo *pKeyInfo = pCsr->pKeyInfo;
@@ -74772,14 +75396,13 @@
if( pKey2 ){
sqlite3VdbeRecordUnpack(pKeyInfo, nKey2, pKey2, r2);
}
- if( nIgnore ){
- r2->nField = pKeyInfo->nField - nIgnore;
- assert( r2->nField>0 );
- for(i=0; inField; i++){
+ if( nKeyCol ){
+ r2->nField = nKeyCol;
+ for(i=0; iaMem[i].flags & MEM_Null ){
*pRes = -1;
return;
}
}
@@ -75457,18 +76080,18 @@
** key.
*/
SQLITE_PRIVATE int sqlite3VdbeSorterCompare(
const VdbeCursor *pCsr, /* Sorter cursor */
Mem *pVal, /* Value to compare to current sorter key */
- int nIgnore, /* Ignore this many fields at the end */
+ int nKeyCol, /* Only compare this many fields */
int *pRes /* OUT: Result of comparison */
){
VdbeSorter *pSorter = pCsr->pSorter;
void *pKey; int nKey; /* Sorter key to compare pVal with */
pKey = vdbeSorterRowkey(pSorter, &nKey);
- vdbeSorterCompare(pCsr, nIgnore, pVal->z, pVal->n, pKey, nKey, pRes);
+ vdbeSorterCompare(pCsr, nKeyCol, pVal->z, pVal->n, pKey, nKey, pRes);
return SQLITE_OK;
}
/************** End of vdbesort.c ********************************************/
/************** Begin file journal.c *****************************************/
@@ -76496,11 +77119,11 @@
}
break;
}
}
if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && HasRowid(pTab) ){
- /* IMP: R-24309-18625 */
+ /* IMP: R-51414-32910 */
/* IMP: R-44911-55124 */
iCol = -1;
}
if( iColnCol ){
cnt++;
@@ -76852,12 +77475,17 @@
}
}else{
/* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is equivalent to
** likelihood(X, 0.0625).
** EVIDENCE-OF: R-01283-11636 The unlikely(X) function is short-hand for
- ** likelihood(X,0.0625). */
- pExpr->iTable = 62; /* TUNING: Default 2nd arg to unlikely() is 0.0625 */
+ ** likelihood(X,0.0625).
+ ** EVIDENCE-OF: R-36850-34127 The likely(X) function is short-hand for
+ ** likelihood(X,0.9375).
+ ** EVIDENCE-OF: R-53436-40973 The likely(X) function is equivalent to
+ ** likelihood(X,0.9375). */
+ /* TUNING: unlikely() probability is 0.0625. likely() is 0.9375 */
+ pExpr->iTable = pDef->zName[0]=='u' ? 62 : 938;
}
}
}
#ifndef SQLITE_OMIT_AUTHORIZATION
if( pDef ){
@@ -77629,11 +78257,11 @@
** SELECT * FROM t1 WHERE (select a from t1);
*/
SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
int op;
pExpr = sqlite3ExprSkipCollate(pExpr);
- if( pExpr->flags & EP_Generic ) return SQLITE_AFF_NONE;
+ if( pExpr->flags & EP_Generic ) return 0;
op = pExpr->op;
if( op==TK_SELECT ){
assert( pExpr->flags&EP_xIsSelect );
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
}
@@ -78964,10 +79592,13 @@
case TK_INTEGER:
case TK_STRING:
case TK_FLOAT:
case TK_BLOB:
return 0;
+ case TK_COLUMN:
+ assert( p->pTab!=0 );
+ return p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0;
default:
return 1;
}
}
@@ -79071,83 +79702,124 @@
SQLITE_PRIVATE int sqlite3CodeOnce(Parse *pParse){
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++);
}
+/*
+** Generate code that checks the left-most column of index table iCur to see if
+** it contains any NULL entries. Cause the register at regHasNull to be set
+** to a non-NULL value if iCur contains no NULLs. Cause register regHasNull
+** to be set to NULL if iCur contains one or more NULL values.
+*/
+static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){
+ int j1;
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, regHasNull);
+ j1 = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v);
+ sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, regHasNull);
+ sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
+ VdbeComment((v, "first_entry_in(%d)", iCur));
+ sqlite3VdbeJumpHere(v, j1);
+}
+
+
+#ifndef SQLITE_OMIT_SUBQUERY
+/*
+** The argument is an IN operator with a list (not a subquery) on the
+** right-hand side. Return TRUE if that list is constant.
+*/
+static int sqlite3InRhsIsConstant(Expr *pIn){
+ Expr *pLHS;
+ int res;
+ assert( !ExprHasProperty(pIn, EP_xIsSelect) );
+ pLHS = pIn->pLeft;
+ pIn->pLeft = 0;
+ res = sqlite3ExprIsConstant(pIn);
+ pIn->pLeft = pLHS;
+ return res;
+}
+#endif
+
/*
** This function is used by the implementation of the IN (...) operator.
** The pX parameter is the expression on the RHS of the IN operator, which
** might be either a list of expressions or a subquery.
**
** The job of this routine is to find or create a b-tree object that can
** be used either to test for membership in the RHS set or to iterate through
** all members of the RHS set, skipping duplicates.
**
-** A cursor is opened on the b-tree object that the RHS of the IN operator
+** A cursor is opened on the b-tree object that is the RHS of the IN operator
** and pX->iTable is set to the index of that cursor.
**
** The returned value of this function indicates the b-tree type, as follows:
**
** IN_INDEX_ROWID - The cursor was opened on a database table.
** IN_INDEX_INDEX_ASC - The cursor was opened on an ascending index.
** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index.
** IN_INDEX_EPH - The cursor was opened on a specially created and
** populated epheremal table.
+** IN_INDEX_NOOP - No cursor was allocated. The IN operator must be
+** implemented as a sequence of comparisons.
**
** An existing b-tree might be used if the RHS expression pX is a simple
** subquery such as:
**
** SELECT FROM
**
** If the RHS of the IN operator is a list or a more complex subquery, then
** an ephemeral table might need to be generated from the RHS and then
** pX->iTable made to point to the ephermeral table instead of an
-** existing table.
+** existing table.
**
-** If the prNotFound parameter is 0, then the b-tree will be used to iterate
-** through the set members, skipping any duplicates. In this case an
-** epheremal table must be used unless the selected is guaranteed
+** The inFlags parameter must contain exactly one of the bits
+** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP. If inFlags contains
+** IN_INDEX_MEMBERSHIP, then the generated table will be used for a
+** fast membership test. When the IN_INDEX_LOOP bit is set, the
+** IN index will be used to loop over all values of the RHS of the
+** IN operator.
+**
+** When IN_INDEX_LOOP is used (and the b-tree will be used to iterate
+** through the set members) then the b-tree must not contain duplicates.
+** An epheremal table must be used unless the selected is guaranteed
** to be unique - either because it is an INTEGER PRIMARY KEY or it
** has a UNIQUE constraint or UNIQUE index.
**
-** If the prNotFound parameter is not 0, then the b-tree will be used
-** for fast set membership tests. In this case an epheremal table must
+** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used
+** for fast set membership tests) then an epheremal table must
** be used unless is an INTEGER PRIMARY KEY or an index can
** be found with as its left-most column.
+**
+** If the IN_INDEX_NOOP_OK and IN_INDEX_MEMBERSHIP are both set and
+** if the RHS of the IN operator is a list (not a subquery) then this
+** routine might decide that creating an ephemeral b-tree for membership
+** testing is too expensive and return IN_INDEX_NOOP. In that case, the
+** calling routine should implement the IN operator using a sequence
+** of Eq or Ne comparison operations.
**
** When the b-tree is being used for membership tests, the calling function
-** needs to know whether or not the structure contains an SQL NULL
-** value in order to correctly evaluate expressions like "X IN (Y, Z)".
-** If there is any chance that the (...) might contain a NULL value at
+** might need to know whether or not the RHS side of the IN operator
+** contains a NULL. If prRhsHasNull is not a NULL pointer and
+** if there is any chance that the (...) might contain a NULL value at
** runtime, then a register is allocated and the register number written
-** to *prNotFound. If there is no chance that the (...) contains a
-** NULL value, then *prNotFound is left unchanged.
-**
-** If a register is allocated and its location stored in *prNotFound, then
-** its initial value is NULL. If the (...) does not remain constant
-** for the duration of the query (i.e. the SELECT within the (...)
-** is a correlated subquery) then the value of the allocated register is
-** reset to NULL each time the subquery is rerun. This allows the
-** caller to use vdbe code equivalent to the following:
-**
-** if( register==NULL ){
-** has_null =
-** register = 1
-** }
-**
-** in order to avoid running the
-** test more often than is necessary.
+** to *prRhsHasNull. If there is no chance that the (...) contains a
+** NULL value, then *prRhsHasNull is left unchanged.
+**
+** If a register is allocated and its location stored in *prRhsHasNull, then
+** the value in that register will be NULL if the b-tree contains one or more
+** NULL values, and it will be some non-NULL value if the b-tree contains no
+** NULL values.
*/
#ifndef SQLITE_OMIT_SUBQUERY
-SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
+SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
Select *p; /* SELECT to the right of IN operator */
int eType = 0; /* Type of RHS table. IN_INDEX_* */
int iTab = pParse->nTab++; /* Cursor of the RHS table */
- int mustBeUnique = (prNotFound==0); /* True if RHS must be unique */
+ int mustBeUnique; /* True if RHS must be unique */
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
assert( pX->op==TK_IN );
+ mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0;
/* Check to see if an existing table or index can be used to
** satisfy the query. This is preferable to generating a new
** ephemeral table.
*/
@@ -79200,44 +79872,59 @@
int affinity_ok = sqlite3IndexAffinityOk(pX, pTab->aCol[iCol].affinity);
for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){
if( (pIdx->aiColumn[0]==iCol)
&& sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq
- && (!mustBeUnique || (pIdx->nKeyCol==1 && pIdx->onError!=OE_None))
+ && (!mustBeUnique || (pIdx->nKeyCol==1 && IsUniqueIndex(pIdx)))
){
int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
VdbeComment((v, "%s", pIdx->zName));
assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
- if( prNotFound && !pTab->aCol[iCol].notNull ){
- *prNotFound = ++pParse->nMem;
- sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
+ if( prRhsHasNull && !pTab->aCol[iCol].notNull ){
+ *prRhsHasNull = ++pParse->nMem;
+ sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull);
}
sqlite3VdbeJumpHere(v, iAddr);
}
}
}
}
+
+ /* If no preexisting index is available for the IN clause
+ ** and IN_INDEX_NOOP is an allowed reply
+ ** and the RHS of the IN operator is a list, not a subquery
+ ** and the RHS is not contant or has two or fewer terms,
+ ** then it is not worth creating an ephermeral table to evaluate
+ ** the IN operator so return IN_INDEX_NOOP.
+ */
+ if( eType==0
+ && (inFlags & IN_INDEX_NOOP_OK)
+ && !ExprHasProperty(pX, EP_xIsSelect)
+ && (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2)
+ ){
+ eType = IN_INDEX_NOOP;
+ }
+
if( eType==0 ){
- /* Could not found an existing table or index to use as the RHS b-tree.
+ /* Could not find an existing table or index to use as the RHS b-tree.
** We will have to generate an ephemeral table to do the job.
*/
u32 savedNQueryLoop = pParse->nQueryLoop;
int rMayHaveNull = 0;
eType = IN_INDEX_EPH;
- if( prNotFound ){
- *prNotFound = rMayHaveNull = ++pParse->nMem;
- sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
- }else{
+ if( inFlags & IN_INDEX_LOOP ){
pParse->nQueryLoop = 0;
if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){
eType = IN_INDEX_ROWID;
}
+ }else if( prRhsHasNull ){
+ *prRhsHasNull = rMayHaveNull = ++pParse->nMem;
}
sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID);
pParse->nQueryLoop = savedNQueryLoop;
}else{
pX->iTable = iTab;
@@ -79264,31 +79951,25 @@
** intkey B-Tree to store the set of IN(...) values instead of the usual
** (slower) variable length keys B-Tree.
**
** If rMayHaveNull is non-zero, that means that the operation is an IN
** (not a SELECT or EXISTS) and that the RHS might contains NULLs.
-** Furthermore, the IN is in a WHERE clause and that we really want
-** to iterate over the RHS of the IN operator in order to quickly locate
-** all corresponding LHS elements. All this routine does is initialize
-** the register given by rMayHaveNull to NULL. Calling routines will take
-** care of changing this register value to non-NULL if the RHS is NULL-free.
-**
-** If rMayHaveNull is zero, that means that the subquery is being used
-** for membership testing only. There is no need to initialize any
-** registers to indicate the presence or absence of NULLs on the RHS.
+** All this routine does is initialize the register given by rMayHaveNull
+** to NULL. Calling routines will take care of changing this register
+** value to non-NULL if the RHS is NULL-free.
**
** For a SELECT or EXISTS operator, return the register that holds the
** result. For IN operators or if an error occurs, the return value is 0.
*/
#ifndef SQLITE_OMIT_SUBQUERY
SQLITE_PRIVATE int sqlite3CodeSubselect(
Parse *pParse, /* Parsing context */
Expr *pExpr, /* The IN, SELECT, or EXISTS operator */
- int rMayHaveNull, /* Register that records whether NULLs exist in RHS */
+ int rHasNullFlag, /* Register that records whether NULLs exist in RHS */
int isRowid /* If true, LHS of IN operator is a rowid */
){
- int testAddr = -1; /* One-time test address */
+ int jmpIfDynamic = -1; /* One-time test address */
int rReg = 0; /* Register storing resulting */
Vdbe *v = sqlite3GetVdbe(pParse);
if( NEVER(v==0) ) return 0;
sqlite3ExprCachePush(pParse);
@@ -79301,17 +79982,17 @@
**
** If all of the above are false, then we can run this code just once
** save the results, and reuse the same result on subsequent invocations.
*/
if( !ExprHasProperty(pExpr, EP_VarSelect) ){
- testAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
+ jmpIfDynamic = sqlite3CodeOnce(pParse); VdbeCoverage(v);
}
#ifndef SQLITE_OMIT_EXPLAIN
if( pParse->explain==2 ){
char *zMsg = sqlite3MPrintf(
- pParse->db, "EXECUTE %s%s SUBQUERY %d", testAddr>=0?"":"CORRELATED ",
+ pParse->db, "EXECUTE %s%s SUBQUERY %d", jmpIfDynamic>=0?"":"CORRELATED ",
pExpr->op==TK_IN?"LIST":"SCALAR", pParse->iNextSelectId
);
sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
}
#endif
@@ -79321,14 +80002,10 @@
char affinity; /* Affinity of the LHS of the IN */
int addr; /* Address of OP_OpenEphemeral instruction */
Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
KeyInfo *pKeyInfo = 0; /* Key information */
- if( rMayHaveNull ){
- sqlite3VdbeAddOp2(v, OP_Null, 0, rMayHaveNull);
- }
-
affinity = sqlite3ExprAffinity(pLeft);
/* Whether this is an 'x IN(SELECT...)' or an 'x IN()'
** expression it is handled the same way. An ephemeral table is
** filled with single-field index keys representing the results
@@ -79350,24 +80027,27 @@
/* Case 1: expr IN (SELECT ...)
**
** Generate code to write the results of the select into the temporary
** table allocated and opened above.
*/
+ Select *pSelect = pExpr->x.pSelect;
SelectDest dest;
ExprList *pEList;
assert( !isRowid );
sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
dest.affSdst = (u8)affinity;
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
- pExpr->x.pSelect->iLimit = 0;
+ pSelect->iLimit = 0;
+ testcase( pSelect->selFlags & SF_Distinct );
+ pSelect->selFlags &= ~SF_Distinct;
testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
- if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
+ if( sqlite3Select(pParse, pSelect, &dest) ){
sqlite3KeyInfoUnref(pKeyInfo);
return 0;
}
- pEList = pExpr->x.pSelect->pEList;
+ pEList = pSelect->pEList;
assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
assert( pEList!=0 );
assert( pEList->nExpr>0 );
assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
pKeyInfo->aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
@@ -79394,23 +80074,23 @@
}
/* Loop through each expression in . */
r1 = sqlite3GetTempReg(pParse);
r2 = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp2(v, OP_Null, 0, r2);
+ if( isRowid ) sqlite3VdbeAddOp2(v, OP_Null, 0, r2);
for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){
Expr *pE2 = pItem->pExpr;
int iValToIns;
/* If the expression is not constant then we will need to
** disable the test that was generated above that makes sure
** this code only executes once. Because for a non-constant
** expression we need to rerun this code each time.
*/
- if( testAddr>=0 && !sqlite3ExprIsConstant(pE2) ){
- sqlite3VdbeChangeToNoop(v, testAddr);
- testAddr = -1;
+ if( jmpIfDynamic>=0 && !sqlite3ExprIsConstant(pE2) ){
+ sqlite3VdbeChangeToNoop(v, jmpIfDynamic);
+ jmpIfDynamic = -1;
}
/* Evaluate the expression and insert it into the temp table */
if( isRowid && sqlite3ExprIsInteger(pE2, &iValToIns) ){
sqlite3VdbeAddOp3(v, OP_InsertInt, pExpr->iTable, r2, iValToIns);
@@ -79476,12 +80156,16 @@
ExprSetVVAProperty(pExpr, EP_NoReduce);
break;
}
}
- if( testAddr>=0 ){
- sqlite3VdbeJumpHere(v, testAddr);
+ if( rHasNullFlag ){
+ sqlite3SetHasNullFlag(v, pExpr->iTable, rHasNullFlag);
+ }
+
+ if( jmpIfDynamic>=0 ){
+ sqlite3VdbeJumpHere(v, jmpIfDynamic);
}
sqlite3ExprCachePop(pParse);
return rReg;
}
@@ -79498,11 +80182,11 @@
** is an array of zero or more values. The expression is true if the LHS is
** contained within the RHS. The value of the expression is unknown (NULL)
** if the LHS is NULL or if the LHS is not contained within the RHS and the
** RHS contains one or more NULL values.
**
-** This routine generates code will jump to destIfFalse if the LHS is not
+** This routine generates code that jumps to destIfFalse if the LHS is not
** contained within the RHS. If due to NULLs we cannot determine if the LHS
** is contained in the RHS then jump to destIfNull. If the LHS is contained
** within the RHS then fall through.
*/
static void sqlite3ExprCodeIN(
@@ -79521,11 +80205,13 @@
** pExpr->iTable will contains the values that make up the RHS.
*/
v = pParse->pVdbe;
assert( v!=0 ); /* OOM detected prior to this routine */
VdbeNoopComment((v, "begin IN expr"));
- eType = sqlite3FindInIndex(pParse, pExpr, &rRhsHasNull);
+ eType = sqlite3FindInIndex(pParse, pExpr,
+ IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK,
+ destIfFalse==destIfNull ? 0 : &rRhsHasNull);
/* Figure out the affinity to use to create a key from the results
** of the expression. affinityStr stores a static string suitable for
** P4 of OP_MakeRecord.
*/
@@ -79535,86 +80221,118 @@
*/
sqlite3ExprCachePush(pParse);
r1 = sqlite3GetTempReg(pParse);
sqlite3ExprCode(pParse, pExpr->pLeft, r1);
- /* If the LHS is NULL, then the result is either false or NULL depending
- ** on whether the RHS is empty or not, respectively.
- */
- if( destIfNull==destIfFalse ){
- /* Shortcut for the common case where the false and NULL outcomes are
- ** the same. */
- sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v);
- }else{
- int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
- VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
- sqlite3VdbeJumpHere(v, addr1);
- }
-
- if( eType==IN_INDEX_ROWID ){
- /* In this case, the RHS is the ROWID of table b-tree
- */
- sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v);
- sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1);
- VdbeCoverage(v);
- }else{
- /* In this case, the RHS is an index b-tree.
- */
- sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1);
-
- /* If the set membership test fails, then the result of the
- ** "x IN (...)" expression must be either 0 or NULL. If the set
- ** contains no NULL values, then the result is 0. If the set
- ** contains one or more NULL values, then the result of the
- ** expression is also NULL.
- */
- if( rRhsHasNull==0 || destIfFalse==destIfNull ){
- /* This branch runs if it is known at compile time that the RHS
- ** cannot contain NULL values. This happens as the result
- ** of a "NOT NULL" constraint in the database schema.
- **
- ** Also run this branch if NULL is equivalent to FALSE
- ** for this particular IN operator.
- */
- sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, r1, 1);
- VdbeCoverage(v);
- }else{
- /* In this branch, the RHS of the IN might contain a NULL and
- ** the presence of a NULL on the RHS makes a difference in the
- ** outcome.
- */
- int j1, j2;
-
- /* First check to see if the LHS is contained in the RHS. If so,
- ** then the presence of NULLs in the RHS does not matter, so jump
- ** over all of the code that follows.
- */
- j1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1);
- VdbeCoverage(v);
-
- /* Here we begin generating code that runs if the LHS is not
- ** contained within the RHS. Generate additional code that
- ** tests the RHS for NULLs. If the RHS contains a NULL then
- ** jump to destIfNull. If there are no NULLs in the RHS then
- ** jump to destIfFalse.
- */
- sqlite3VdbeAddOp2(v, OP_If, rRhsHasNull, destIfNull); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_IfNot, rRhsHasNull, destIfFalse); VdbeCoverage(v);
- j2 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, rRhsHasNull, 1);
- VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_Integer, 0, rRhsHasNull);
+ /* If sqlite3FindInIndex() did not find or create an index that is
+ ** suitable for evaluating the IN operator, then evaluate using a
+ ** sequence of comparisons.
+ */
+ if( eType==IN_INDEX_NOOP ){
+ ExprList *pList = pExpr->x.pList;
+ CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
+ int labelOk = sqlite3VdbeMakeLabel(v);
+ int r2, regToFree;
+ int regCkNull = 0;
+ int ii;
+ assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
+ if( destIfNull!=destIfFalse ){
+ regCkNull = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp3(v, OP_BitAnd, r1, r1, regCkNull);
+ }
+ for(ii=0; iinExpr; ii++){
+ r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, ®ToFree);
+ if( regCkNull && sqlite3ExprCanBeNull(pList->a[ii].pExpr) ){
+ sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull);
+ }
+ if( iinExpr-1 || destIfNull!=destIfFalse ){
+ sqlite3VdbeAddOp4(v, OP_Eq, r1, labelOk, r2,
+ (void*)pColl, P4_COLLSEQ);
+ VdbeCoverageIf(v, iinExpr-1);
+ VdbeCoverageIf(v, ii==pList->nExpr-1);
+ sqlite3VdbeChangeP5(v, affinity);
+ }else{
+ assert( destIfNull==destIfFalse );
+ sqlite3VdbeAddOp4(v, OP_Ne, r1, destIfFalse, r2,
+ (void*)pColl, P4_COLLSEQ); VdbeCoverage(v);
+ sqlite3VdbeChangeP5(v, affinity | SQLITE_JUMPIFNULL);
+ }
+ sqlite3ReleaseTempReg(pParse, regToFree);
+ }
+ if( regCkNull ){
+ sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse);
- sqlite3VdbeJumpHere(v, j2);
- sqlite3VdbeAddOp2(v, OP_Integer, 1, rRhsHasNull);
- sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
-
- /* The OP_Found at the top of this branch jumps here when true,
- ** causing the overall IN expression evaluation to fall through.
+ }
+ sqlite3VdbeResolveLabel(v, labelOk);
+ sqlite3ReleaseTempReg(pParse, regCkNull);
+ }else{
+
+ /* If the LHS is NULL, then the result is either false or NULL depending
+ ** on whether the RHS is empty or not, respectively.
+ */
+ if( sqlite3ExprCanBeNull(pExpr->pLeft) ){
+ if( destIfNull==destIfFalse ){
+ /* Shortcut for the common case where the false and NULL outcomes are
+ ** the same. */
+ sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v);
+ }else{
+ int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
+ sqlite3VdbeJumpHere(v, addr1);
+ }
+ }
+
+ if( eType==IN_INDEX_ROWID ){
+ /* In this case, the RHS is the ROWID of table b-tree
*/
- sqlite3VdbeJumpHere(v, j1);
+ sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v);
+ sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1);
+ VdbeCoverage(v);
+ }else{
+ /* In this case, the RHS is an index b-tree.
+ */
+ sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1);
+
+ /* If the set membership test fails, then the result of the
+ ** "x IN (...)" expression must be either 0 or NULL. If the set
+ ** contains no NULL values, then the result is 0. If the set
+ ** contains one or more NULL values, then the result of the
+ ** expression is also NULL.
+ */
+ assert( destIfFalse!=destIfNull || rRhsHasNull==0 );
+ if( rRhsHasNull==0 ){
+ /* This branch runs if it is known at compile time that the RHS
+ ** cannot contain NULL values. This happens as the result
+ ** of a "NOT NULL" constraint in the database schema.
+ **
+ ** Also run this branch if NULL is equivalent to FALSE
+ ** for this particular IN operator.
+ */
+ sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, r1, 1);
+ VdbeCoverage(v);
+ }else{
+ /* In this branch, the RHS of the IN might contain a NULL and
+ ** the presence of a NULL on the RHS makes a difference in the
+ ** outcome.
+ */
+ int j1;
+
+ /* First check to see if the LHS is contained in the RHS. If so,
+ ** then the answer is TRUE the presence of NULLs in the RHS does
+ ** not matter. If the LHS is not contained in the RHS, then the
+ ** answer is NULL if the RHS contains NULLs and the answer is
+ ** FALSE if the RHS is NULL-free.
+ */
+ j1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_IsNull, rRhsHasNull, destIfNull);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse);
+ sqlite3VdbeJumpHere(v, j1);
+ }
}
}
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ExprCachePop(pParse);
VdbeComment((v, "end IN expr"));
@@ -79671,21 +80389,28 @@
}else{
int c;
i64 value;
const char *z = pExpr->u.zToken;
assert( z!=0 );
- c = sqlite3Atoi64(z, &value, sqlite3Strlen30(z), SQLITE_UTF8);
+ c = sqlite3DecOrHexToI64(z, &value);
if( c==0 || (c==2 && negFlag) ){
char *zV;
if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; }
zV = dup8bytes(v, (char*)&value);
sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);
}else{
#ifdef SQLITE_OMIT_FLOATING_POINT
sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
#else
- codeReal(v, z, negFlag, iMem);
+#ifndef SQLITE_OMIT_HEX_INTEGER
+ if( sqlite3_strnicmp(z,"0x",2)==0 ){
+ sqlite3ErrorMsg(pParse, "hex literal too big: %s", z);
+ }else
+#endif
+ {
+ codeReal(v, z, negFlag, iMem);
+ }
#endif
}
}
}
@@ -80227,11 +80952,11 @@
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
testcase( regFree1==0 );
addr = sqlite3VdbeAddOp1(v, op, r1);
VdbeCoverageIf(v, op==TK_ISNULL);
VdbeCoverageIf(v, op==TK_NOTNULL);
- sqlite3VdbeAddOp2(v, OP_AddImm, target, -1);
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, target);
sqlite3VdbeJumpHere(v, addr);
break;
}
case TK_AGG_FUNCTION: {
AggInfo *pInfo = pExpr->pAggInfo;
@@ -80263,11 +80988,11 @@
nFarg = pFarg ? pFarg->nExpr : 0;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
zId = pExpr->u.zToken;
nId = sqlite3Strlen30(zId);
pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0);
- if( pDef==0 ){
+ if( pDef==0 || pDef->xFunc==0 ){
sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId);
break;
}
/* Attempt a direct implementation of the built-in COALESCE() and
@@ -82929,10 +83654,11 @@
/* Open the sqlite_stat[134] tables for writing. */
for(i=0; aTable[i].zCols; i++){
assert( idb, p);
}
/*
-** Implementation of the stat_init(N,C) SQL function. The two parameters
-** are the number of rows in the table or index (C) and the number of columns
-** in the index (N). The second argument (C) is only used for STAT3 and STAT4.
+** Implementation of the stat_init(N,K,C) SQL function. The three parameters
+** are:
+** N: The number of columns in the index including the rowid/pk (note 1)
+** K: The number of columns in the index excluding the rowid/pk.
+** C: The number of rows in the index (note 2)
+**
+** Note 1: In the special case of the covering index that implements a
+** WITHOUT ROWID table, N is the number of PRIMARY KEY columns, not the
+** total number of columns in the table.
+**
+** Note 2: C is only used for STAT3 and STAT4.
+**
+** For indexes on ordinary rowid tables, N==K+1. But for indexes on
+** WITHOUT ROWID tables, N=K+P where P is the number of columns in the
+** PRIMARY KEY of the table. The covering index that implements the
+** original WITHOUT ROWID table as N==K as a special case.
**
** This routine allocates the Stat4Accum object in heap memory. The return
** value is a pointer to the the Stat4Accum object encoded as a blob (i.e.
** the size of the blob is sizeof(void*) bytes).
*/
@@ -83065,10 +83805,11 @@
int argc,
sqlite3_value **argv
){
Stat4Accum *p;
int nCol; /* Number of columns in index being sampled */
+ int nKeyCol; /* Number of key columns */
int nColUp; /* nCol rounded up for alignment */
int n; /* Bytes of space to allocate */
sqlite3 *db; /* Database connection */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
int mxSample = SQLITE_STAT4_SAMPLES;
@@ -83075,12 +83816,15 @@
#endif
/* Decode the three function arguments */
UNUSED_PARAMETER(argc);
nCol = sqlite3_value_int(argv[0]);
- assert( nCol>1 ); /* >1 because it includes the rowid column */
+ assert( nCol>0 );
nColUp = sizeof(tRowcnt)<8 ? (nCol+1)&~1 : nCol;
+ nKeyCol = sqlite3_value_int(argv[1]);
+ assert( nKeyCol<=nCol );
+ assert( nKeyCol>0 );
/* Allocate the space required for the Stat4Accum object */
n = sizeof(*p)
+ sizeof(tRowcnt)*nColUp /* Stat4Accum.anEq */
+ sizeof(tRowcnt)*nColUp /* Stat4Accum.anDLt */
@@ -83098,10 +83842,11 @@
}
p->db = db;
p->nRow = 0;
p->nCol = nCol;
+ p->nKeyCol = nKeyCol;
p->current.anDLt = (tRowcnt*)&p[1];
p->current.anEq = &p->current.anDLt[nColUp];
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
{
@@ -83108,13 +83853,13 @@
u8 *pSpace; /* Allocated space not yet assigned */
int i; /* Used to iterate through p->aSample[] */
p->iGet = -1;
p->mxSample = mxSample;
- p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[1])/(mxSample/3+1) + 1);
+ p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1);
p->current.anLt = &p->current.anEq[nColUp];
- p->iPrn = nCol*0x689e962d ^ sqlite3_value_int(argv[1])*0xd0944565;
+ p->iPrn = nCol*0x689e962d ^ sqlite3_value_int(argv[2])*0xd0944565;
/* Set up the Stat4Accum.a[] and aBest[] arrays */
p->a = (struct Stat4Sample*)&p->current.anLt[nColUp];
p->aBest = &p->a[mxSample];
pSpace = (u8*)(&p->a[mxSample+nCol]);
@@ -83133,11 +83878,11 @@
/* Return a pointer to the allocated object to the caller */
sqlite3_result_blob(context, p, sizeof(p), stat4Destructor);
}
static const FuncDef statInitFuncdef = {
- 1+IsStat34, /* nArg */
+ 2+IsStat34, /* nArg */
SQLITE_UTF8, /* funcFlags */
0, /* pUserData */
0, /* pNext */
statInit, /* xFunc */
0, /* xStep */
@@ -83357,11 +84102,14 @@
** P Pointer to the Stat4Accum object created by stat_init()
** C Index of left-most column to differ from previous row
** R Rowid for the current row. Might be a key record for
** WITHOUT ROWID tables.
**
-** The SQL function always returns NULL.
+** This SQL function always returns NULL. It's purpose it to accumulate
+** statistical data and/or samples in the Stat4Accum object about the
+** index being analyzed. The stat_get() SQL function will later be used to
+** extract relevant information for constructing the sqlite_statN tables.
**
** The R parameter is only used for STAT3 and STAT4
*/
static void statPush(
sqlite3_context *context,
@@ -83374,11 +84122,11 @@
Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]);
int iChng = sqlite3_value_int(argv[1]);
UNUSED_PARAMETER( argc );
UNUSED_PARAMETER( context );
- assert( p->nCol>1 ); /* Includes rowid field */
+ assert( p->nCol>0 );
assert( iChngnCol );
if( p->nRow==0 ){
/* This is the first call to this function. Do initialization. */
for(i=0; inCol; i++) p->current.anEq[i] = 1;
@@ -83451,11 +84199,14 @@
#define STAT_GET_NLT 3 /* "nlt" column of stat[34] entry */
#define STAT_GET_NDLT 4 /* "ndlt" column of stat[34] entry */
/*
** Implementation of the stat_get(P,J) SQL function. This routine is
-** used to query the results. Content is returned for parameter J
+** used to query statistical information that has been gathered into
+** the Stat4Accum object by prior calls to stat_push(). The P parameter
+** is a BLOB which is decoded into a pointer to the Stat4Accum objects.
+** The content to returned is determined by the parameter J
** which is one of the STAT_GET_xxxx values defined above.
**
** If neither STAT3 nor STAT4 are enabled, then J is always
** STAT_GET_STAT1 and is hence omitted and this routine becomes
** a one-parameter function, stat_get(P), that always returns the
@@ -83502,19 +84253,19 @@
** I = (K+D-1)/D
*/
char *z;
int i;
- char *zRet = sqlite3MallocZero(p->nCol * 25);
+ char *zRet = sqlite3MallocZero( (p->nKeyCol+1)*25 );
if( zRet==0 ){
sqlite3_result_error_nomem(context);
return;
}
sqlite3_snprintf(24, zRet, "%llu", (u64)p->nRow);
z = zRet + sqlite3Strlen30(zRet);
- for(i=0; i<(p->nCol-1); i++){
+ for(i=0; inKeyCol; i++){
u64 nDistinct = p->current.anDLt[i] + 1;
u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
sqlite3_snprintf(24, z, " %llu", iVal);
z += sqlite3Strlen30(z);
assert( p->current.anEq[i] );
@@ -83670,31 +84421,31 @@
pParse->nTab = MAX(pParse->nTab, iTab);
sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- int nCol; /* Number of columns indexed by pIdx */
- int *aGotoChng; /* Array of jump instruction addresses */
+ int nCol; /* Number of columns in pIdx. "N" */
int addrRewind; /* Address of "OP_Rewind iIdxCur" */
- int addrGotoChng0; /* Address of "Goto addr_chng_0" */
int addrNextRow; /* Address of "next_row:" */
const char *zIdxName; /* Name of the index */
+ int nColTest; /* Number of columns to test for changes */
if( pOnlyIdx && pOnlyIdx!=pIdx ) continue;
if( pIdx->pPartIdxWhere==0 ) needTableCnt = 0;
- VdbeNoopComment((v, "Begin analysis of %s", pIdx->zName));
- nCol = pIdx->nKeyCol;
- aGotoChng = sqlite3DbMallocRaw(db, sizeof(int)*(nCol+1));
- if( aGotoChng==0 ) continue;
+ if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIdx) ){
+ nCol = pIdx->nKeyCol;
+ zIdxName = pTab->zName;
+ nColTest = nCol - 1;
+ }else{
+ nCol = pIdx->nColumn;
+ zIdxName = pIdx->zName;
+ nColTest = pIdx->uniqNotNull ? pIdx->nKeyCol-1 : nCol-1;
+ }
/* Populate the register containing the index name. */
- if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
- zIdxName = pTab->zName;
- }else{
- zIdxName = pIdx->zName;
- }
sqlite3VdbeAddOp4(v, OP_String8, 0, regIdxname, 0, zIdxName, 0);
+ VdbeComment((v, "Analysis for %s.%s", pTab->zName, zIdxName));
/*
** Pseudo-code for loop that calls stat_push():
**
** Rewind csr
@@ -83715,11 +84466,11 @@
** regPrev(0) = idx(0)
** chng_addr_1:
** regPrev(1) = idx(1)
** ...
**
- ** chng_addr_N:
+ ** endDistinctTest:
** regRowid = idx(rowid)
** stat_push(P, regChng, regRowid)
** Next csr
** if !eof(csr) goto next_row;
**
@@ -83728,32 +84479,36 @@
/* Make sure there are enough memory cells allocated to accommodate
** the regPrev array and a trailing rowid (the rowid slot is required
** when building a record to insert into the sample column of
** the sqlite_stat4 table. */
- pParse->nMem = MAX(pParse->nMem, regPrev+nCol);
+ pParse->nMem = MAX(pParse->nMem, regPrev+nColTest);
/* Open a read-only cursor on the index being analyzed. */
assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) );
sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
VdbeComment((v, "%s", pIdx->zName));
/* Invoke the stat_init() function. The arguments are:
**
- ** (1) the number of columns in the index including the rowid,
- ** (2) the number of rows in the index,
+ ** (1) the number of columns in the index including the rowid
+ ** (or for a WITHOUT ROWID table, the number of PK columns),
+ ** (2) the number of columns in the key without the rowid/pk
+ ** (3) the number of rows in the index,
**
- ** The second argument is only used for STAT3 and STAT4
+ **
+ ** The third argument is only used for STAT3 and STAT4
*/
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
- sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+2);
+ sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3);
#endif
- sqlite3VdbeAddOp2(v, OP_Integer, nCol+1, regStat4+1);
+ sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
+ sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
sqlite3VdbeAddOp3(v, OP_Function, 0, regStat4+1, regStat4);
sqlite3VdbeChangeP4(v, -1, (char*)&statInitFuncdef, P4_FUNCDEF);
- sqlite3VdbeChangeP5(v, 1+IsStat34);
+ sqlite3VdbeChangeP5(v, 2+IsStat34);
/* Implementation of the following:
**
** Rewind csr
** if eof(csr) goto end_of_scan;
@@ -83762,56 +84517,73 @@
**
*/
addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng);
- addrGotoChng0 = sqlite3VdbeAddOp0(v, OP_Goto);
-
- /*
- ** next_row:
- ** regChng = 0
- ** if( idx(0) != regPrev(0) ) goto chng_addr_0
- ** regChng = 1
- ** if( idx(1) != regPrev(1) ) goto chng_addr_1
- ** ...
- ** regChng = N
- ** goto chng_addr_N
- */
addrNextRow = sqlite3VdbeCurrentAddr(v);
- for(i=0; iazColl[i]);
- sqlite3VdbeAddOp2(v, OP_Integer, i, regChng);
- sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp);
- aGotoChng[i] =
- sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ);
- sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
- VdbeCoverage(v);
- }
- sqlite3VdbeAddOp2(v, OP_Integer, nCol, regChng);
- aGotoChng[nCol] = sqlite3VdbeAddOp0(v, OP_Goto);
-
- /*
- ** chng_addr_0:
- ** regPrev(0) = idx(0)
- ** chng_addr_1:
- ** regPrev(1) = idx(1)
- ** ...
- */
- sqlite3VdbeJumpHere(v, addrGotoChng0);
- for(i=0; i0 ){
+ int endDistinctTest = sqlite3VdbeMakeLabel(v);
+ int *aGotoChng; /* Array of jump instruction addresses */
+ aGotoChng = sqlite3DbMallocRaw(db, sizeof(int)*nColTest);
+ if( aGotoChng==0 ) continue;
+
+ /*
+ ** next_row:
+ ** regChng = 0
+ ** if( idx(0) != regPrev(0) ) goto chng_addr_0
+ ** regChng = 1
+ ** if( idx(1) != regPrev(1) ) goto chng_addr_1
+ ** ...
+ ** regChng = N
+ ** goto endDistinctTest
+ */
+ sqlite3VdbeAddOp0(v, OP_Goto);
+ addrNextRow = sqlite3VdbeCurrentAddr(v);
+ if( nColTest==1 && pIdx->nKeyCol==1 && IsUniqueIndex(pIdx) ){
+ /* For a single-column UNIQUE index, once we have found a non-NULL
+ ** row, we know that all the rest will be distinct, so skip
+ ** subsequent distinctness tests. */
+ sqlite3VdbeAddOp2(v, OP_NotNull, regPrev, endDistinctTest);
+ VdbeCoverage(v);
+ }
+ for(i=0; iazColl[i]);
+ sqlite3VdbeAddOp2(v, OP_Integer, i, regChng);
+ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp);
+ aGotoChng[i] =
+ sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ);
+ sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
+ VdbeCoverage(v);
+ }
+ sqlite3VdbeAddOp2(v, OP_Integer, nColTest, regChng);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, endDistinctTest);
+
+
+ /*
+ ** chng_addr_0:
+ ** regPrev(0) = idx(0)
+ ** chng_addr_1:
+ ** regPrev(1) = idx(1)
+ ** ...
+ */
+ sqlite3VdbeJumpHere(v, addrNextRow-1);
+ for(i=0; inMem = MAX(pParse->nMem, regCol+nCol+1);
+ pParse->nMem = MAX(pParse->nMem, regCol+nCol);
addrNext = sqlite3VdbeCurrentAddr(v);
callStatGet(v, regStat4, STAT_GET_ROWID, regSampleRowid);
addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regSampleRowid);
VdbeCoverage(v);
@@ -83873,11 +84645,11 @@
#else
for(i=0; iaiColumn[i];
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regCol+i);
}
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol+1, regSample);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol, regSample);
#endif
sqlite3VdbeAddOp3(v, OP_MakeRecord, regTabname, 6, regTemp);
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur+1, regNewRowid);
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur+1, regTemp, regNewRowid);
sqlite3VdbeAddOp2(v, OP_Goto, 1, addrNext); /* P1==1 for end-of-loop */
@@ -83885,11 +84657,10 @@
}
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
/* End of analysis */
sqlite3VdbeJumpHere(v, addrRewind);
- sqlite3DbFree(db, aGotoChng);
}
/* Create a single sqlite_stat1 entry containing NULL as the index
** name and the row count as the content.
@@ -83986,10 +84757,11 @@
int i;
char *z, *zDb;
Table *pTab;
Index *pIdx;
Token *pTableName;
+ Vdbe *v;
/* Read the database schema. If an error occurs, leave an error message
** and code in pParse and return NULL. */
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
@@ -84033,10 +84805,12 @@
}
sqlite3DbFree(db, z);
}
}
}
+ v = sqlite3GetVdbe(pParse);
+ if( v ) sqlite3VdbeAddOp0(v, OP_Expire);
}
/*
** Used to pass information from the analyzer reader through to the
** callback routine.
@@ -84091,18 +84865,23 @@
#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
assert( pIndex!=0 );
#else
if( pIndex )
#endif
- {
- if( strcmp(z, "unordered")==0 ){
+ while( z[0] ){
+ if( sqlite3_strglob("unordered*", z)==0 ){
pIndex->bUnordered = 1;
}else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
- int v32 = 0;
- sqlite3GetInt32(z+3, &v32);
- pIndex->szIdxRow = sqlite3LogEst(v32);
+ pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3));
}
+#ifdef SQLITE_ENABLE_COSTMULT
+ else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){
+ pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9));
+ }
+#endif
+ while( z[0]!=0 && z[0]!=' ' ) z++;
+ while( z[0]==' ' ) z++;
}
}
/*
** This callback is invoked once for each index when reading the
@@ -84139,15 +84918,19 @@
pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase);
}
z = argv[2];
if( pIndex ){
+ pIndex->bUnordered = 0;
decodeIntArray((char*)z, pIndex->nKeyCol+1, 0, pIndex->aiRowLogEst, pIndex);
if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0];
}else{
Index fakeIdx;
fakeIdx.szIdxRow = pTable->szTabRow;
+#ifdef SQLITE_ENABLE_COSTMULT
+ fakeIdx.pTable = pTable;
+#endif
decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx);
pTable->szTabRow = fakeIdx.szIdxRow;
}
return 0;
@@ -84185,11 +84968,20 @@
static void initAvgEq(Index *pIdx){
if( pIdx ){
IndexSample *aSample = pIdx->aSample;
IndexSample *pFinal = &aSample[pIdx->nSample-1];
int iCol;
- for(iCol=0; iColnKeyCol; iCol++){
+ int nCol = 1;
+ if( pIdx->nSampleCol>1 ){
+ /* If this is stat4 data, then calculate aAvgEq[] values for all
+ ** sample columns except the last. The last is always set to 1, as
+ ** once the trailing PK fields are considered all index keys are
+ ** unique. */
+ nCol = pIdx->nSampleCol-1;
+ pIdx->aAvgEq[nCol] = 1;
+ }
+ for(iCol=0; iColanDLt[iCol];
@@ -84208,11 +85000,10 @@
if( nDLt>nSum ){
avgEq = (pFinal->anLt[iCol] - sumEq)/(nDLt - nSum);
}
if( avgEq==0 ) avgEq = 1;
pIdx->aAvgEq[iCol] = avgEq;
- if( pIdx->nSampleCol==1 ) break;
}
}
}
/*
@@ -84267,11 +85058,10 @@
sqlite3DbFree(db, zSql);
if( rc ) return rc;
while( sqlite3_step(pStmt)==SQLITE_ROW ){
int nIdxCol = 1; /* Number of columns in stat4 records */
- int nAvgCol = 1; /* Number of entries in Index.aAvgEq */
char *zIndex; /* Index name */
Index *pIdx; /* Pointer to the index object */
int nSample; /* Number of samples */
int nByte; /* Bytes of space required */
@@ -84285,25 +85075,29 @@
assert( pIdx==0 || bStat3 || pIdx->nSample==0 );
/* Index.nSample is non-zero at this point if data has already been
** loaded from the stat4 table. In this case ignore stat3 data. */
if( pIdx==0 || pIdx->nSample ) continue;
if( bStat3==0 ){
- nIdxCol = pIdx->nKeyCol+1;
- nAvgCol = pIdx->nKeyCol;
+ assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 );
+ if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
+ nIdxCol = pIdx->nKeyCol;
+ }else{
+ nIdxCol = pIdx->nColumn;
+ }
}
pIdx->nSampleCol = nIdxCol;
nByte = sizeof(IndexSample) * nSample;
nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample;
- nByte += nAvgCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */
+ nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */
pIdx->aSample = sqlite3DbMallocZero(db, nByte);
if( pIdx->aSample==0 ){
sqlite3_finalize(pStmt);
return SQLITE_NOMEM;
}
pSpace = (tRowcnt*)&pIdx->aSample[nSample];
- pIdx->aAvgEq = pSpace; pSpace += nAvgCol;
+ pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
for(i=0; iaSample[i].anEq = pSpace; pSpace += nIdxCol;
pIdx->aSample[i].anLt = pSpace; pSpace += nIdxCol;
pIdx->aSample[i].anDLt = pSpace; pSpace += nIdxCol;
}
@@ -85408,10 +86202,23 @@
}
#else
#define codeTableLocks(x)
#endif
+/*
+** Return TRUE if the given yDbMask object is empty - if it contains no
+** 1 bits. This routine is used by the DbMaskAllZero() and DbMaskNotZero()
+** macros when SQLITE_MAX_ATTACHED is greater than 30.
+*/
+#if SQLITE_MAX_ATTACHED>30
+SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask m){
+ int i;
+ for(i=0; imallocFailed==0 && (pParse->cookieMask || pParse->pConstExpr) ){
- yDbMask mask;
+ if( db->mallocFailed==0
+ && (DbMaskNonZero(pParse->cookieMask) || pParse->pConstExpr)
+ ){
int iDb, i;
assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
sqlite3VdbeJumpHere(v, 0);
- for(iDb=0, mask=1; iDbnDb; mask<<=1, iDb++){
- if( (mask & pParse->cookieMask)==0 ) continue;
+ for(iDb=0; iDbnDb; iDb++){
+ if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
sqlite3VdbeUsesBtree(v, iDb);
sqlite3VdbeAddOp4Int(v,
OP_Transaction, /* Opcode */
iDb, /* P1 */
- (mask & pParse->writeMask)!=0, /* P2 */
+ DbMaskTest(pParse->writeMask,iDb), /* P2 */
pParse->cookieValue[iDb], /* P3 */
db->aDb[iDb].pSchema->iGeneration /* P4 */
);
if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
}
@@ -85511,11 +86319,11 @@
}
pParse->nTab = 0;
pParse->nMem = 0;
pParse->nSet = 0;
pParse->nVar = 0;
- pParse->cookieMask = 0;
+ DbMaskZero(pParse->cookieMask);
}
/*
** Run the parser and code generator recursively in order to generate
** code for the SQL statement given onto the end of the pParse context
@@ -87411,11 +88219,11 @@
pTable->aCol = pSelTab->aCol;
pSelTab->nCol = 0;
pSelTab->aCol = 0;
sqlite3DeleteTable(db, pSelTab);
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
- pTable->pSchema->flags |= DB_UnresetViews;
+ pTable->pSchema->schemaFlags |= DB_UnresetViews;
}else{
pTable->nCol = 0;
nErr++;
}
sqlite3SelectDelete(db, pSel);
@@ -87988,16 +88796,16 @@
(char *)pKey, P4_KEYINFO);
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v);
assert( pKey!=0 || db->mallocFailed || pParse->nErr );
- if( pIndex->onError!=OE_None && pKey!=0 ){
+ if( IsUniqueIndex(pIndex) && pKey!=0 ){
int j2 = sqlite3VdbeCurrentAddr(v) + 3;
sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
addr2 = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord,
- pKey->nField - pIndex->nKeyCol); VdbeCoverage(v);
+ pIndex->nKeyCol); VdbeCoverage(v);
sqlite3UniqueConstraint(pParse, OE_Abort, pIndex);
}else{
addr2 = sqlite3VdbeCurrentAddr(v);
}
sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord);
@@ -88385,13 +89193,13 @@
** considered distinct and both result in separate indices.
*/
Index *pIdx;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int k;
- assert( pIdx->onError!=OE_None );
+ assert( IsUniqueIndex(pIdx) );
assert( pIdx->idxType!=SQLITE_IDXTYPE_APPDEF );
- assert( pIndex->onError!=OE_None );
+ assert( IsUniqueIndex(pIndex) );
if( pIdx->nKeyCol!=pIndex->nKeyCol ) continue;
for(k=0; knKeyCol; k++){
const char *z1;
const char *z2;
@@ -88578,11 +89386,11 @@
for(i=nCopy+1; i<=pIdx->nKeyCol; i++){
a[i] = 23; assert( 23==sqlite3LogEst(5) );
}
assert( 0==sqlite3LogEst(1) );
- if( pIdx->onError!=OE_None ) a[pIdx->nKeyCol] = 0;
+ if( IsUniqueIndex(pIdx) ) a[pIdx->nKeyCol] = 0;
}
/*
** This routine will drop an existing named index. This routine
** implements the DROP INDEX statement.
@@ -89138,19 +89946,17 @@
** later, by sqlite3FinishCoding().
*/
SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
sqlite3 *db = pToplevel->db;
- yDbMask mask;
assert( iDb>=0 && iDbnDb );
assert( db->aDb[iDb].pBt!=0 || iDb==1 );
assert( iDbcookieMask & mask)==0 ){
- pToplevel->cookieMask |= mask;
+ if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){
+ DbMaskSet(pToplevel->cookieMask, iDb);
pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
if( !OMIT_TEMPDB && iDb==1 ){
sqlite3OpenTempDatabase(pToplevel);
}
}
@@ -89185,11 +89991,11 @@
** necessary to undo a write and the checkpoint should not be set.
*/
SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
sqlite3CodeVerifySchema(pParse, iDb);
- pToplevel->writeMask |= ((yDbMask)1)<writeMask, iDb);
pToplevel->isMultiWrite |= setStatement;
}
/*
** Indicate that the statement currently under construction might write
@@ -89992,13 +90798,13 @@
sqlite3DeleteTable(0, pTab);
}
sqlite3HashClear(&temp1);
sqlite3HashClear(&pSchema->fkeyHash);
pSchema->pSeqTab = 0;
- if( pSchema->flags & DB_SchemaLoaded ){
+ if( pSchema->schemaFlags & DB_SchemaLoaded ){
pSchema->iGeneration++;
- pSchema->flags &= ~DB_SchemaLoaded;
+ pSchema->schemaFlags &= ~DB_SchemaLoaded;
}
}
/*
** Find and return the schema associated with a BTree. Create
@@ -90873,16 +91679,13 @@
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
-** This file contains the C functions that implement various SQL
-** functions of SQLite.
-**
-** There is only one exported symbol in this file - the function
-** sqliteRegisterBuildinFunctions() found at the bottom of the file.
-** All other code has file scope.
+** This file contains the C-language implementions for many of the SQL
+** functions of SQLite. (Some function, and in particular the date and
+** time functions, are implemented separately.)
*/
/* #include */
/* #include */
/*
@@ -92553,10 +93356,11 @@
FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
FUNCTION(hex, 1, 0, 0, hexFunc ),
FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
+ FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
FUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
@@ -92839,11 +93643,11 @@
if( !aiCol ) return 1;
*paiCol = aiCol;
}
for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->nKeyCol==nCol && pIdx->onError!=OE_None ){
+ if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) ){
/* pIdx is a UNIQUE index (or a PRIMARY KEY) and has the right number
** of columns. If each indexed column corresponds to a foreign key
** column of pFKey, then this index is a winner. */
if( zKey==0 ){
@@ -95865,11 +96669,11 @@
){
return 0; /* Default values must be the same for all columns */
}
}
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
- if( pDestIdx->onError!=OE_None ){
+ if( IsUniqueIndex(pDestIdx) ){
destHasUniqueIdx = 1;
}
for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){
if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
}
@@ -96095,10 +96899,13 @@
goto exec_out;
}
}
}
if( xCallback(pArg, nCol, azVals, azCols) ){
+ /* EVIDENCE-OF: R-38229-40159 If the callback function to
+ ** sqlite3_exec() returns non-zero, then sqlite3_exec() will
+ ** return SQLITE_ABORT. */
rc = SQLITE_ABORT;
sqlite3VdbeFinalize((Vdbe *)pStmt);
pStmt = 0;
sqlite3Error(db, SQLITE_ABORT, 0);
goto exec_out;
@@ -97872,11 +98679,11 @@
** Note that the values returned are one less that the values that
** should be passed into sqlite3BtreeSetSafetyLevel(). The is done
** to support legacy SQL code. The safety level used to be boolean
** and older scripts may have used numbers 0 for OFF and 1 for ON.
*/
-static u8 getSafetyLevel(const char *z, int omitFull, int dflt){
+static u8 getSafetyLevel(const char *z, int omitFull, u8 dflt){
/* 123456789 123456789 */
static const char zText[] = "onoffalseyestruefull";
static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16};
static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 4};
static const u8 iValue[] = {1, 0, 0, 0, 1, 1, 2};
@@ -97894,11 +98701,11 @@
}
/*
** Interpret the given string as a boolean value.
*/
-SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z, int dflt){
+SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z, u8 dflt){
return getSafetyLevel(z,1,dflt)!=0;
}
/* The sqlite3GetBoolean() function is used by other modules but the
** remainder of this file is specific to PRAGMA processing. So omit
@@ -98440,11 +99247,11 @@
*/
case PragTyp_JOURNAL_SIZE_LIMIT: {
Pager *pPager = sqlite3BtreePager(pDb->pBt);
i64 iLimit = -2;
if( zRight ){
- sqlite3Atoi64(zRight, &iLimit, sqlite3Strlen30(zRight), SQLITE_UTF8);
+ sqlite3DecOrHexToI64(zRight, &iLimit);
if( iLimit<-1 ) iLimit = -1;
}
iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
returnSingleInt(pParse, "journal_size_limit", iLimit);
break;
@@ -98568,11 +99375,11 @@
sqlite3_int64 sz;
#if SQLITE_MAX_MMAP_SIZE>0
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( zRight ){
int ii;
- sqlite3Atoi64(zRight, &sz, sqlite3Strlen30(zRight), SQLITE_UTF8);
+ sqlite3DecOrHexToI64(zRight, &sz);
if( sz<0 ) sz = sqlite3GlobalConfig.szMmap;
if( pId2->n==0 ) db->szMmap = sz;
for(ii=db->nDb-1; ii>=0; ii--){
if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){
sqlite3BtreeSetMmapLimit(db->aDb[ii].pBt, sz);
@@ -98936,11 +99743,11 @@
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC);
for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
- sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 3);
+ sqlite3VdbeAddOp2(v, OP_Integer, IsUniqueIndex(pIdx), 3);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
}
}
}
break;
@@ -99186,13 +99993,12 @@
** messages have been generated, output OK. Otherwise output the
** error message
*/
static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList endCode[] = {
- { OP_AddImm, 1, 0, 0}, /* 0 */
- { OP_IfNeg, 1, 0, 0}, /* 1 */
- { OP_String8, 0, 3, 0}, /* 2 */
+ { OP_IfNeg, 1, 0, 0}, /* 0 */
+ { OP_String8, 0, 3, 0}, /* 1 */
{ OP_ResultRow, 3, 1, 0},
};
int isQuick = (sqlite3Tolower(zLeft[0])=='q');
@@ -99300,32 +100106,80 @@
sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
}
pParse->nMem = MAX(pParse->nMem, 8+j);
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
+ /* Verify that all NOT NULL columns really are NOT NULL */
+ for(j=0; jnCol; j++){
+ char *zErr;
+ int jmp2, jmp3;
+ if( j==pTab->iPKey ) continue;
+ if( pTab->aCol[j].notNull==0 ) continue;
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
+ sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
+ jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
+ zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
+ pTab->aCol[j].zName);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
+ jmp3 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
+ sqlite3VdbeAddOp0(v, OP_Halt);
+ sqlite3VdbeJumpHere(v, jmp2);
+ sqlite3VdbeJumpHere(v, jmp3);
+ }
+ /* Validate index entries for the current row */
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
- int jmp2, jmp3, jmp4;
+ int jmp2, jmp3, jmp4, jmp5;
+ int ckUniq = sqlite3VdbeMakeLabel(v);
if( pPk==pIdx ) continue;
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3,
pPrior, r1);
pPrior = pIdx;
sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */
- jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, 0, r1,
+ /* Verify that an index entry exists for the current table row */
+ jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
pIdx->nColumn); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, "row ", P4_STATIC);
sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
- sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, " missing from index ",
- P4_STATIC);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0,
+ " missing from index ", P4_STATIC);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
- sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, pIdx->zName, P4_TRANSIENT);
+ jmp5 = sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0,
+ pIdx->zName, P4_TRANSIENT);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
sqlite3VdbeAddOp0(v, OP_Halt);
- sqlite3VdbeJumpHere(v, jmp4);
sqlite3VdbeJumpHere(v, jmp2);
+ /* For UNIQUE indexes, verify that only one entry exists with the
+ ** current key. The entry is unique if (1) any column is NULL
+ ** or (2) the next entry has a different key */
+ if( IsUniqueIndex(pIdx) ){
+ int uniqOk = sqlite3VdbeMakeLabel(v);
+ int jmp6;
+ int kk;
+ for(kk=0; kknKeyCol; kk++){
+ int iCol = pIdx->aiColumn[kk];
+ assert( iCol>=0 && iColnCol );
+ if( pTab->aCol[iCol].notNull ) continue;
+ sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
+ VdbeCoverage(v);
+ }
+ jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, uniqOk);
+ sqlite3VdbeJumpHere(v, jmp6);
+ sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1,
+ pIdx->nKeyCol); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
+ "non-unique entry in index ", P4_STATIC);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, jmp5);
+ sqlite3VdbeResolveLabel(v, uniqOk);
+ }
+ sqlite3VdbeJumpHere(v, jmp4);
sqlite3ResolvePartIdxLabel(pParse, jmp3);
}
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, loopTop-1);
#ifndef SQLITE_OMIT_BTREECOUNT
@@ -99346,13 +100200,13 @@
}
#endif /* SQLITE_OMIT_BTREECOUNT */
}
}
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
- sqlite3VdbeChangeP2(v, addr, -mxErr);
- sqlite3VdbeJumpHere(v, addr+1);
- sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC);
+ sqlite3VdbeChangeP3(v, addr, -mxErr);
+ sqlite3VdbeJumpHere(v, addr);
+ sqlite3VdbeChangeP4(v, addr+1, "ok", P4_STATIC);
}
break;
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
#ifndef SQLITE_OMIT_UTF16
@@ -99611,11 +100465,11 @@
** Call sqlite3_soft_heap_limit64(N). Return the result. If N is omitted,
** use -1.
*/
case PragTyp_SOFT_HEAP_LIMIT: {
sqlite3_int64 N;
- if( zRight && sqlite3Atoi64(zRight, &N, 1000000, SQLITE_UTF8)==SQLITE_OK ){
+ if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){
sqlite3_soft_heap_limit64(N);
}
returnSingleInt(pParse, "soft_heap_limit", sqlite3_soft_heap_limit64(-1));
break;
}
@@ -101134,12 +101988,11 @@
int iOffset, /* Register holding the offset counter */
int iContinue /* Jump here to skip the current record */
){
if( iOffset>0 ){
int addr;
- sqlite3VdbeAddOp2(v, OP_AddImm, iOffset, -1);
- addr = sqlite3VdbeAddOp1(v, OP_IfNeg, iOffset); VdbeCoverage(v);
+ addr = sqlite3VdbeAddOp3(v, OP_IfNeg, iOffset, 0, -1); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue);
VdbeComment((v, "skip OFFSET records"));
sqlite3VdbeJumpHere(v, addr);
}
}
@@ -101300,11 +102153,11 @@
VdbeCoverage(v);
}
sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ);
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
}
- assert( sqlite3VdbeCurrentAddr(v)==iJump );
+ assert( sqlite3VdbeCurrentAddr(v)==iJump || pParse->db->mallocFailed );
sqlite3VdbeAddOp3(v, OP_Copy, regResult, regPrev, nResultCol-1);
break;
}
case WHERE_DISTINCT_UNIQUE: {
@@ -107767,11 +108620,12 @@
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey);
VdbeCoverageNeverTaken(v);
}
labelContinue = labelBreak;
sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak);
- VdbeCoverage(v);
+ VdbeCoverageIf(v, pPk==0);
+ VdbeCoverageIf(v, pPk!=0);
}else if( pPk ){
labelContinue = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);
addrTop = sqlite3VdbeAddOp2(v, OP_RowKey, iEph, regKey);
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0);
@@ -109777,10 +110631,11 @@
struct WherePath {
Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */
Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
LogEst nRow; /* Estimated number of rows generated by this path */
LogEst rCost; /* Total cost of this path */
+ LogEst rUnsorted; /* Total cost of this path ignoring sorting costs */
i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */
WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
};
/*
@@ -110581,11 +111436,11 @@
pScan->pOrigWC = pWC;
pScan->pWC = pWC;
if( pIdx && iColumn>=0 ){
pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity;
for(j=0; pIdx->aiColumn[j]!=iColumn; j++){
- if( NEVER(j>=pIdx->nKeyCol) ) return 0;
+ if( NEVER(j>pIdx->nColumn) ) return 0;
}
pScan->zCollName = pIdx->azColl[j];
}else{
pScan->idxaff = 0;
pScan->zCollName = 0;
@@ -111507,11 +112362,11 @@
**
** 3. All of those index columns for which the WHERE clause does not
** contain a "col=X" term are subject to a NOT NULL constraint.
*/
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->onError==OE_None ) continue;
+ if( !IsUniqueIndex(pIdx) ) continue;
for(i=0; inKeyCol; i++){
i16 iCol = pIdx->aiColumn[i];
if( 0==findTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx) ){
int iIdxCol = findIndexCol(pParse, pDistinct, iBase, pIdx, i);
if( iIdxCol<0 || pTab->aCol[iCol].notNull==0 ){
@@ -111531,12 +112386,11 @@
/*
** Estimate the logarithm of the input value to base 2.
*/
static LogEst estLog(LogEst N){
- LogEst x = sqlite3LogEst(N);
- return x>33 ? x - 33 : 0;
+ return N<=10 ? 0 : sqlite3LogEst(N) - 33;
}
/*
** Two routines for printing the content of an sqlite3_index_info
** structure. Used for testing and debugging only. If neither
@@ -111997,11 +112851,11 @@
}else{
i64 nRow0 = sqlite3LogEstToInt(pIdx->aiRowLogEst[0]);
iUpper = i>=pIdx->nSample ? nRow0 : aSample[i].anLt[iCol];
iLower = aSample[i-1].anEq[iCol] + aSample[i-1].anLt[iCol];
}
- aStat[1] = (pIdx->nKeyCol>iCol ? pIdx->aAvgEq[iCol] : 1);
+ aStat[1] = pIdx->aAvgEq[iCol];
if( iLower>=iUpper ){
iGap = 0;
}else{
iGap = iUpper - iLower;
}
@@ -112036,10 +112890,119 @@
}
}
return nRet;
}
+#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+/*
+** This function is called to estimate the number of rows visited by a
+** range-scan on a skip-scan index. For example:
+**
+** CREATE INDEX i1 ON t1(a, b, c);
+** SELECT * FROM t1 WHERE a=? AND c BETWEEN ? AND ?;
+**
+** Value pLoop->nOut is currently set to the estimated number of rows
+** visited for scanning (a=? AND b=?). This function reduces that estimate
+** by some factor to account for the (c BETWEEN ? AND ?) expression based
+** on the stat4 data for the index. this scan will be peformed multiple
+** times (once for each (a,b) combination that matches a=?) is dealt with
+** by the caller.
+**
+** It does this by scanning through all stat4 samples, comparing values
+** extracted from pLower and pUpper with the corresponding column in each
+** sample. If L and U are the number of samples found to be less than or
+** equal to the values extracted from pLower and pUpper respectively, and
+** N is the total number of samples, the pLoop->nOut value is adjusted
+** as follows:
+**
+** nOut = nOut * ( min(U - L, 1) / N )
+**
+** If pLower is NULL, or a value cannot be extracted from the term, L is
+** set to zero. If pUpper is NULL, or a value cannot be extracted from it,
+** U is set to N.
+**
+** Normally, this function sets *pbDone to 1 before returning. However,
+** if no value can be extracted from either pLower or pUpper (and so the
+** estimate of the number of rows delivered remains unchanged), *pbDone
+** is left as is.
+**
+** If an error occurs, an SQLite error code is returned. Otherwise,
+** SQLITE_OK.
+*/
+static int whereRangeSkipScanEst(
+ Parse *pParse, /* Parsing & code generating context */
+ WhereTerm *pLower, /* Lower bound on the range. ex: "x>123" Might be NULL */
+ WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */
+ WhereLoop *pLoop, /* Update the .nOut value of this loop */
+ int *pbDone /* Set to true if at least one expr. value extracted */
+){
+ Index *p = pLoop->u.btree.pIndex;
+ int nEq = pLoop->u.btree.nEq;
+ sqlite3 *db = pParse->db;
+ int nLower = -1;
+ int nUpper = p->nSample+1;
+ int rc = SQLITE_OK;
+ int iCol = p->aiColumn[nEq];
+ u8 aff = iCol>=0 ? p->pTable->aCol[iCol].affinity : SQLITE_AFF_INTEGER;
+ CollSeq *pColl;
+
+ sqlite3_value *p1 = 0; /* Value extracted from pLower */
+ sqlite3_value *p2 = 0; /* Value extracted from pUpper */
+ sqlite3_value *pVal = 0; /* Value extracted from record */
+
+ pColl = sqlite3LocateCollSeq(pParse, p->azColl[nEq]);
+ if( pLower ){
+ rc = sqlite3Stat4ValueFromExpr(pParse, pLower->pExpr->pRight, aff, &p1);
+ nLower = 0;
+ }
+ if( pUpper && rc==SQLITE_OK ){
+ rc = sqlite3Stat4ValueFromExpr(pParse, pUpper->pExpr->pRight, aff, &p2);
+ nUpper = p2 ? 0 : p->nSample;
+ }
+
+ if( p1 || p2 ){
+ int i;
+ int nDiff;
+ for(i=0; rc==SQLITE_OK && inSample; i++){
+ rc = sqlite3Stat4Column(db, p->aSample[i].p, p->aSample[i].n, nEq, &pVal);
+ if( rc==SQLITE_OK && p1 ){
+ int res = sqlite3MemCompare(p1, pVal, pColl);
+ if( res>=0 ) nLower++;
+ }
+ if( rc==SQLITE_OK && p2 ){
+ int res = sqlite3MemCompare(p2, pVal, pColl);
+ if( res>=0 ) nUpper++;
+ }
+ }
+ nDiff = (nUpper - nLower);
+ if( nDiff<=0 ) nDiff = 1;
+
+ /* If there is both an upper and lower bound specified, and the
+ ** comparisons indicate that they are close together, use the fallback
+ ** method (assume that the scan visits 1/64 of the rows) for estimating
+ ** the number of rows visited. Otherwise, estimate the number of rows
+ ** using the method described in the header comment for this function. */
+ if( nDiff!=1 || pUpper==0 || pLower==0 ){
+ int nAdjust = (sqlite3LogEst(p->nSample) - sqlite3LogEst(nDiff));
+ pLoop->nOut -= nAdjust;
+ *pbDone = 1;
+ WHERETRACE(0x10, ("range skip-scan regions: %u..%u adjust=%d est=%d\n",
+ nLower, nUpper, nAdjust*-1, pLoop->nOut));
+ }
+
+ }else{
+ assert( *pbDone==0 );
+ }
+
+ sqlite3ValueFree(p1);
+ sqlite3ValueFree(p2);
+ sqlite3ValueFree(pVal);
+
+ return rc;
+}
+#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
+
/*
** This function is used to estimate the number of rows that will be visited
** by scanning an index for a range of values. The range may have an upper
** bound, a lower bound, or both. The WHERE clause terms that set the upper
** and lower bounds are represented by pLower and pUpper respectively. For
@@ -112072,13 +113035,13 @@
** considering the range constraints. If nEq is 0, this is the number of
** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced)
** to account for the range contraints pLower and pUpper.
**
** In the absence of sqlite_stat4 ANALYZE data, or if such data cannot be
-** used, each range inequality reduces the search space by a factor of 4.
-** Hence a pair of constraints (x>? AND x) reduces the expected number of
-** rows visited by a factor of 16.
+** used, a single range inequality reduces the search space by a factor of 4.
+** and a pair of constraints (x>? AND x) reduces the expected number of
+** rows visited by a factor of 64.
*/
static int whereRangeScanEst(
Parse *pParse, /* Parsing & code generating context */
WhereLoopBuilder *pBuilder,
WhereTerm *pLower, /* Lower bound on the range. ex: "x>123" Might be NULL */
@@ -112092,99 +113055,104 @@
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
Index *p = pLoop->u.btree.pIndex;
int nEq = pLoop->u.btree.nEq;
if( p->nSample>0
- && nEq==pBuilder->nRecValid
&& nEqnSampleCol
&& OptimizationEnabled(pParse->db, SQLITE_Stat3)
){
- UnpackedRecord *pRec = pBuilder->pRec;
- tRowcnt a[2];
- u8 aff;
-
- /* Variable iLower will be set to the estimate of the number of rows in
- ** the index that are less than the lower bound of the range query. The
- ** lower bound being the concatenation of $P and $L, where $P is the
- ** key-prefix formed by the nEq values matched against the nEq left-most
- ** columns of the index, and $L is the value in pLower.
- **
- ** Or, if pLower is NULL or $L cannot be extracted from it (because it
- ** is not a simple variable or literal value), the lower bound of the
- ** range is $P. Due to a quirk in the way whereKeyStats() works, even
- ** if $L is available, whereKeyStats() is called for both ($P) and
- ** ($P:$L) and the larger of the two returned values used.
- **
- ** Similarly, iUpper is to be set to the estimate of the number of rows
- ** less than the upper bound of the range query. Where the upper bound
- ** is either ($P) or ($P:$U). Again, even if $U is available, both values
- ** of iUpper are requested of whereKeyStats() and the smaller used.
- */
- tRowcnt iLower;
- tRowcnt iUpper;
-
- if( nEq==p->nKeyCol ){
- aff = SQLITE_AFF_INTEGER;
- }else{
- aff = p->pTable->aCol[p->aiColumn[nEq]].affinity;
- }
- /* Determine iLower and iUpper using ($P) only. */
- if( nEq==0 ){
- iLower = 0;
- iUpper = sqlite3LogEstToInt(p->aiRowLogEst[0]);
- }else{
- /* Note: this call could be optimized away - since the same values must
- ** have been requested when testing key $P in whereEqualScanEst(). */
- whereKeyStats(pParse, p, pRec, 0, a);
- iLower = a[0];
- iUpper = a[0] + a[1];
- }
-
- /* If possible, improve on the iLower estimate using ($P:$L). */
- if( pLower ){
- int bOk; /* True if value is extracted from pExpr */
- Expr *pExpr = pLower->pExpr->pRight;
- assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 );
- rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
- if( rc==SQLITE_OK && bOk ){
- tRowcnt iNew;
- whereKeyStats(pParse, p, pRec, 0, a);
- iNew = a[0] + ((pLower->eOperator & WO_GT) ? a[1] : 0);
- if( iNew>iLower ) iLower = iNew;
- nOut--;
- }
- }
-
- /* If possible, improve on the iUpper estimate using ($P:$U). */
- if( pUpper ){
- int bOk; /* True if value is extracted from pExpr */
- Expr *pExpr = pUpper->pExpr->pRight;
- assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 );
- rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
- if( rc==SQLITE_OK && bOk ){
- tRowcnt iNew;
- whereKeyStats(pParse, p, pRec, 1, a);
- iNew = a[0] + ((pUpper->eOperator & WO_LE) ? a[1] : 0);
- if( iNewpRec = pRec;
- if( rc==SQLITE_OK ){
- if( iUpper>iLower ){
- nNew = sqlite3LogEst(iUpper - iLower);
- }else{
- nNew = 10; assert( 10==sqlite3LogEst(2) );
- }
- if( nNewnOut = (LogEst)nOut;
- WHERETRACE(0x10, ("range scan regions: %u..%u est=%d\n",
- (u32)iLower, (u32)iUpper, nOut));
- return SQLITE_OK;
+ if( nEq==pBuilder->nRecValid ){
+ UnpackedRecord *pRec = pBuilder->pRec;
+ tRowcnt a[2];
+ u8 aff;
+
+ /* Variable iLower will be set to the estimate of the number of rows in
+ ** the index that are less than the lower bound of the range query. The
+ ** lower bound being the concatenation of $P and $L, where $P is the
+ ** key-prefix formed by the nEq values matched against the nEq left-most
+ ** columns of the index, and $L is the value in pLower.
+ **
+ ** Or, if pLower is NULL or $L cannot be extracted from it (because it
+ ** is not a simple variable or literal value), the lower bound of the
+ ** range is $P. Due to a quirk in the way whereKeyStats() works, even
+ ** if $L is available, whereKeyStats() is called for both ($P) and
+ ** ($P:$L) and the larger of the two returned values used.
+ **
+ ** Similarly, iUpper is to be set to the estimate of the number of rows
+ ** less than the upper bound of the range query. Where the upper bound
+ ** is either ($P) or ($P:$U). Again, even if $U is available, both values
+ ** of iUpper are requested of whereKeyStats() and the smaller used.
+ */
+ tRowcnt iLower;
+ tRowcnt iUpper;
+
+ if( nEq==p->nKeyCol ){
+ aff = SQLITE_AFF_INTEGER;
+ }else{
+ aff = p->pTable->aCol[p->aiColumn[nEq]].affinity;
+ }
+ /* Determine iLower and iUpper using ($P) only. */
+ if( nEq==0 ){
+ iLower = 0;
+ iUpper = sqlite3LogEstToInt(p->aiRowLogEst[0]);
+ }else{
+ /* Note: this call could be optimized away - since the same values must
+ ** have been requested when testing key $P in whereEqualScanEst(). */
+ whereKeyStats(pParse, p, pRec, 0, a);
+ iLower = a[0];
+ iUpper = a[0] + a[1];
+ }
+
+ /* If possible, improve on the iLower estimate using ($P:$L). */
+ if( pLower ){
+ int bOk; /* True if value is extracted from pExpr */
+ Expr *pExpr = pLower->pExpr->pRight;
+ assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 );
+ rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
+ if( rc==SQLITE_OK && bOk ){
+ tRowcnt iNew;
+ whereKeyStats(pParse, p, pRec, 0, a);
+ iNew = a[0] + ((pLower->eOperator & WO_GT) ? a[1] : 0);
+ if( iNew>iLower ) iLower = iNew;
+ nOut--;
+ }
+ }
+
+ /* If possible, improve on the iUpper estimate using ($P:$U). */
+ if( pUpper ){
+ int bOk; /* True if value is extracted from pExpr */
+ Expr *pExpr = pUpper->pExpr->pRight;
+ assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 );
+ rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
+ if( rc==SQLITE_OK && bOk ){
+ tRowcnt iNew;
+ whereKeyStats(pParse, p, pRec, 1, a);
+ iNew = a[0] + ((pUpper->eOperator & WO_LE) ? a[1] : 0);
+ if( iNewpRec = pRec;
+ if( rc==SQLITE_OK ){
+ if( iUpper>iLower ){
+ nNew = sqlite3LogEst(iUpper - iLower);
+ }else{
+ nNew = 10; assert( 10==sqlite3LogEst(2) );
+ }
+ if( nNewnOut = (LogEst)nOut;
+ WHERETRACE(0x10, ("range scan regions: %u..%u est=%d\n",
+ (u32)iLower, (u32)iUpper, nOut));
+ return SQLITE_OK;
+ }
+ }else{
+ int bDone = 0;
+ rc = whereRangeSkipScanEst(pParse, pLower, pUpper, pLoop, &bDone);
+ if( bDone ) return rc;
}
}
#else
UNUSED_PARAMETER(pParse);
UNUSED_PARAMETER(pBuilder);
@@ -112239,11 +113207,11 @@
int rc; /* Subfunction return code */
tRowcnt a[2]; /* Statistics */
int bOk;
assert( nEq>=1 );
- assert( nEq<=(p->nKeyCol+1) );
+ assert( nEq<=p->nColumn );
assert( p->aSample!=0 );
assert( p->nSample>0 );
assert( pBuilder->nRecValidp->nKeyCol ){
+ if( nEq>=p->nColumn ){
*pnRow = 1;
return SQLITE_OK;
}
aff = p->pTable->aCol[p->aiColumn[nEq-1]].affinity;
@@ -112446,11 +113414,11 @@
testcase( bRev );
bRev = !bRev;
}
assert( pX->op==TK_IN );
iReg = iTarget;
- eType = sqlite3FindInIndex(pParse, pX, 0);
+ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0);
if( eType==IN_INDEX_INDEX_DESC ){
testcase( bRev );
bRev = !bRev;
}
iTab = pX->iTable;
@@ -112683,11 +113651,11 @@
}
sqlite3StrAccumInit(&txt, 0, 0, SQLITE_MAX_LENGTH);
txt.db = db;
sqlite3StrAccumAppend(&txt, " (", 2);
for(i=0; inKeyCol ) ? "rowid" : aCol[aiColumn[i]].zName;
+ char *z = aiColumn[i] < 0 ? "rowid" : aCol[aiColumn[i]].zName;
if( i>=nSkip ){
explainAppendTerm(&txt, i, z, "=");
}else{
if( i ) sqlite3StrAccumAppend(&txt, " AND ", 5);
sqlite3StrAccumAppend(&txt, "ANY(", 4);
@@ -112696,15 +113664,15 @@
}
}
j = i;
if( pLoop->wsFlags&WHERE_BTM_LIMIT ){
- char *z = (j==pIndex->nKeyCol ) ? "rowid" : aCol[aiColumn[j]].zName;
+ char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName;
explainAppendTerm(&txt, i++, z, ">");
}
if( pLoop->wsFlags&WHERE_TOP_LIMIT ){
- char *z = (j==pIndex->nKeyCol ) ? "rowid" : aCol[aiColumn[j]].zName;
+ char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName;
explainAppendTerm(&txt, i, z, "<");
}
sqlite3StrAccumAppend(&txt, ")", 1);
return sqlite3StrAccumFinish(&txt);
}
@@ -113347,10 +114315,11 @@
int regRowid = 0; /* Register holding rowid */
int iLoopBody = sqlite3VdbeMakeLabel(v); /* Start of loop body */
int iRetInit; /* Address of regReturn init */
int untestedTerms = 0; /* Some terms not completely tested */
int ii; /* Loop counter */
+ u16 wctrlFlags; /* Flags for sub-WHERE clause */
Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
Table *pTab = pTabItem->pTab;
pTerm = pLoop->aLTerm[0];
assert( pTerm!=0 );
@@ -113442,10 +114411,12 @@
/* Run a separate WHERE clause for each term of the OR clause. After
** eliminating duplicates from other WHERE clauses, the action for each
** sub-WHERE clause is to to invoke the main loop body as a subroutine.
*/
+ wctrlFlags = WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY |
+ WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY;
for(ii=0; iinTerm; ii++){
WhereTerm *pOrTerm = &pOrWc->a[ii];
if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
WhereInfo *pSubWInfo; /* Info for single OR-term scan */
Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */
@@ -113454,12 +114425,11 @@
pAndExpr->pLeft = pOrExpr;
pOrExpr = pAndExpr;
}
/* Loop through table entries that match term pOrTerm. */
pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0,
- WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY |
- WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY, iCovCur);
+ wctrlFlags, iCovCur);
assert( pSubWInfo || pParse->nErr || db->mallocFailed );
if( pSubWInfo ){
WhereLoop *pSubLoop;
explainOneScan(
pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
@@ -113546,10 +114516,11 @@
&& (ii==0 || pSubLoop->u.btree.pIndex==pCov)
&& (HasRowid(pTab) || !IsPrimaryKeyIndex(pSubLoop->u.btree.pIndex))
){
assert( pSubWInfo->a[0].iIdxCur==iCovCur );
pCov = pSubLoop->u.btree.pIndex;
+ wctrlFlags |= WHERE_REOPEN_IDX;
}else{
pCov = 0;
}
/* Finish the loop through table entries that match term pOrTerm. */
@@ -113724,11 +114695,11 @@
z = sqlite3_mprintf("(%d,%x)", p->u.vtab.idxNum, p->u.vtab.omitMask);
}
sqlite3DebugPrintf(" %-19s", z);
sqlite3_free(z);
}
- sqlite3DebugPrintf(" f %04x N %d", p->wsFlags, p->nLTerm);
+ sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm);
sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut);
#ifdef SQLITE_ENABLE_TREE_EXPLAIN
/* If the 0x100 bit of wheretracing is set, then show all of the constraint
** expressions in the WhereLoop.aLTerm[] array.
*/
@@ -113960,10 +114931,21 @@
/* whereLoopAddBtree() always generates and inserts the automatic index
** case first. Hence compatible candidate WhereLoops never have a larger
** rSetup. Call this SETUP-INVARIANT */
assert( p->rSetup>=pTemplate->rSetup );
+
+ /* Any loop using an appliation-defined index (or PRIMARY KEY or
+ ** UNIQUE constraint) with one or more == constraints is better
+ ** than an automatic index. */
+ if( (p->wsFlags & WHERE_AUTO_INDEX)!=0
+ && (pTemplate->wsFlags & WHERE_INDEXED)!=0
+ && (pTemplate->wsFlags & WHERE_COLUMN_EQ)!=0
+ && (p->prereq & pTemplate->prereq)==pTemplate->prereq
+ ){
+ break;
+ }
/* If existing WhereLoop p is better than pTemplate, pTemplate can be
** discarded. WhereLoop p is better if:
** (1) p has no more dependencies than pTemplate, and
** (2) p has an equal or lower cost than pTemplate
@@ -114085,17 +115067,17 @@
** p[] that are also supplated by pTemplate */
WhereLoop **ppTail = &p->pNextLoop;
WhereLoop *pToDel;
while( *ppTail ){
ppTail = whereLoopFindLesser(ppTail, pTemplate);
- if( NEVER(ppTail==0) ) break;
+ if( ppTail==0 ) break;
pToDel = *ppTail;
if( pToDel==0 ) break;
*ppTail = pToDel->pNextLoop;
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
- sqlite3DebugPrintf("ins-del: ");
+ sqlite3DebugPrintf("ins-del: ");
whereLoopPrint(pToDel, pBuilder->pWC);
}
#endif
whereLoopDelete(db, pToDel);
}
@@ -114141,10 +115123,20 @@
pLoop->nOut += (pTerm->truthProb<=0 ? pTerm->truthProb : -1);
}
}
}
+/*
+** Adjust the cost C by the costMult facter T. This only occurs if
+** compiled with -DSQLITE_ENABLE_COSTMULT
+*/
+#ifdef SQLITE_ENABLE_COSTMULT
+# define ApplyCostMultiplier(C,T) C += T
+#else
+# define ApplyCostMultiplier(C,T)
+#endif
+
/*
** We have so far matched pBuilder->pNew->u.btree.nEq terms of the
** index pIndex. Try to match one more.
**
** When this function is called, pBuilder->pNew->nOut contains the
@@ -114191,16 +115183,13 @@
}else{
opMask = WO_EQ|WO_IN|WO_ISNULL|WO_GT|WO_GE|WO_LT|WO_LE;
}
if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
- assert( pNew->u.btree.nEq<=pProbe->nKeyCol );
- if( pNew->u.btree.nEq < pProbe->nKeyCol ){
- iCol = pProbe->aiColumn[pNew->u.btree.nEq];
- }else{
- iCol = -1;
- }
+ assert( pNew->u.btree.nEqnColumn );
+ iCol = pProbe->aiColumn[pNew->u.btree.nEq];
+
pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol,
opMask, pProbe);
saved_nEq = pNew->u.btree.nEq;
saved_nSkip = pNew->u.btree.nSkip;
saved_nLTerm = pNew->nLTerm;
@@ -114279,11 +115268,11 @@
** changes "x IN (?)" into "x=?". */
}else if( eOp & (WO_EQ) ){
pNew->wsFlags |= WHERE_COLUMN_EQ;
if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1) ){
- if( iCol>=0 && pProbe->onError==OE_None ){
+ if( iCol>=0 && !IsUniqueIndex(pProbe) ){
pNew->wsFlags |= WHERE_UNQ_WANTED;
}else{
pNew->wsFlags |= WHERE_ONEROW;
}
}
@@ -114340,11 +115329,10 @@
testcase( eOp & WO_ISNULL );
rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut);
}else{
rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut);
}
- assert( rc!=SQLITE_OK || nOut>0 );
if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
if( rc!=SQLITE_OK ) break; /* Jump out of the pTerm loop */
if( nOut ){
pNew->nOut = sqlite3LogEst(nOut);
if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut;
@@ -114372,10 +115360,11 @@
rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx);
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16);
}
+ ApplyCostMultiplier(pNew->rRun, pProbe->pTable->costMult);
nOutUnadjusted = pNew->nOut;
pNew->rRun += nInMul + nIn;
pNew->nOut += nInMul + nIn;
whereLoopOutputAdjust(pBuilder->pWC, pNew);
@@ -114386,11 +115375,11 @@
}else{
pNew->nOut = nOutUnadjusted;
}
if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0
- && pNew->u.btree.nEq<(pProbe->nKeyCol + (pProbe->zName!=0))
+ && pNew->u.btree.nEqnColumn
){
whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn);
}
pNew->nOut = saved_nOut;
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
@@ -114491,10 +115480,18 @@
** cost = nSeek * (log(nRow) + (K+3.0) * nVisit) // non-covering index
**
** Normally, nSeek is 1. nSeek values greater than 1 come about if the
** WHERE clause includes "x IN (....)" terms used in place of "x=?". Or when
** implicit "x IN (SELECT x FROM tbl)" terms are added for skip-scans.
+**
+** The estimated values (nRow, nVisit, nSeek) often contain a large amount
+** of uncertainty. For this reason, scoring is designed to pick plans that
+** "do the least harm" if the estimates are inaccurate. For example, a
+** log(nRow) factor is omitted from a non-covering index scan in order to
+** bias the scoring in favor of using an index, since the worst-case
+** performance of using an index is far better than the worst-case performance
+** of a full table scan.
*/
static int whereLoopAddBtree(
WhereLoopBuilder *pBuilder, /* WHERE clause information */
Bitmask mExtra /* Extra prerequesites for using this table */
){
@@ -114533,10 +115530,11 @@
** fake index the first in a chain of Index objects with all of the real
** indices to follow */
Index *pFirst; /* First of real indices on the table */
memset(&sPk, 0, sizeof(Index));
sPk.nKeyCol = 1;
+ sPk.nColumn = 1;
sPk.aiColumn = &aiColumnPk;
sPk.aiRowLogEst = aiRowEstPk;
sPk.onError = OE_Replace;
sPk.pTable = pTab;
sPk.szIdxRow = pTab->szTabRow;
@@ -114577,10 +115575,11 @@
pNew->aLTerm[0] = pTerm;
/* TUNING: One-time cost for computing the automatic index is
** approximately 7*N*log2(N) where N is the number of rows in
** the table being indexed. */
pNew->rSetup = rLogSize + rSize + 28; assert( 28==sqlite3LogEst(7) );
+ ApplyCostMultiplier(pNew->rSetup, pTab->costMult);
/* TUNING: Each index lookup yields 20 rows in the table. This
** is more than the usual guess of 10 rows, since we have no way
** of knowning how selective the index will ultimately be. It would
** not be unreasonable to make this value much larger. */
pNew->nOut = 43; assert( 43==sqlite3LogEst(20) );
@@ -114618,10 +115617,11 @@
/* Full table scan */
pNew->iSortIdx = b ? iSortIdx : 0;
/* TUNING: Cost of full table scan is (N*3.0). */
pNew->rRun = rSize + 16;
+ ApplyCostMultiplier(pNew->rRun, pTab->costMult);
whereLoopOutputAdjust(pWC, pNew);
rc = whereLoopInsert(pBuilder, pNew);
pNew->nOut = rSize;
if( rc ) break;
}else{
@@ -114653,11 +115653,11 @@
** also add the cost of visiting table rows (N*3.0). */
pNew->rRun = rSize + 1 + (15*pProbe->szIdxRow)/pTab->szTabRow;
if( m!=0 ){
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, rSize+16);
}
-
+ ApplyCostMultiplier(pNew->rRun, pTab->costMult);
whereLoopOutputAdjust(pWC, pNew);
rc = whereLoopInsert(pBuilder, pNew);
pNew->nOut = rSize;
if( rc ) break;
}
@@ -115123,11 +116123,11 @@
}else{
nKeyCol = pIndex->nKeyCol;
nColumn = pIndex->nColumn;
assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) );
assert( pIndex->aiColumn[nColumn-1]==(-1) || !HasRowid(pIndex->pTable));
- isOrderDistinct = pIndex->onError!=OE_None;
+ isOrderDistinct = IsUniqueIndex(pIndex);
}
/* Loop through all columns of the index and deal with the ones
** that are not constrained by == or IN.
*/
@@ -115291,10 +116291,49 @@
if( pLast ) zName[i++] = pLast->cId;
zName[i] = 0;
return zName;
}
#endif
+
+/*
+** Return the cost of sorting nRow rows, assuming that the keys have
+** nOrderby columns and that the first nSorted columns are already in
+** order.
+*/
+static LogEst whereSortingCost(
+ WhereInfo *pWInfo,
+ LogEst nRow,
+ int nOrderBy,
+ int nSorted
+){
+ /* TUNING: Estimated cost of a full external sort, where N is
+ ** the number of rows to sort is:
+ **
+ ** cost = (3.0 * N * log(N)).
+ **
+ ** Or, if the order-by clause has X terms but only the last Y
+ ** terms are out of order, then block-sorting will reduce the
+ ** sorting cost to:
+ **
+ ** cost = (3.0 * N * log(N)) * (Y/X)
+ **
+ ** The (Y/X) term is implemented using stack variable rScale
+ ** below. */
+ LogEst rScale, rSortCost;
+ assert( nOrderBy>0 && 66==sqlite3LogEst(100) );
+ rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66;
+ rSortCost = nRow + estLog(nRow) + rScale + 16;
+
+ /* TUNING: The cost of implementing DISTINCT using a B-TREE is
+ ** similar but with a larger constant of proportionality.
+ ** Multiply by an additional factor of 3.0. */
+ if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
+ rSortCost += 16;
+ }
+
+ return rSortCost;
+}
/*
** Given the list of WhereLoop objects at pWInfo->pLoops, this routine
** attempts to find the lowest cost path that visits each WhereLoop
** once. This path is then loaded into the pWInfo->a[].pWLoop fields.
@@ -115313,142 +116352,170 @@
sqlite3 *db; /* The database connection */
int iLoop; /* Loop counter over the terms of the join */
int ii, jj; /* Loop counters */
int mxI = 0; /* Index of next entry to replace */
int nOrderBy; /* Number of ORDER BY clause terms */
- LogEst rCost; /* Cost of a path */
- LogEst nOut; /* Number of outputs */
LogEst mxCost = 0; /* Maximum cost of a set of paths */
- LogEst mxOut = 0; /* Maximum nOut value on the set of paths */
+ LogEst mxUnsorted = 0; /* Maximum unsorted cost of a set of path */
int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */
WherePath *aFrom; /* All nFrom paths at the previous level */
WherePath *aTo; /* The nTo best paths at the current level */
WherePath *pFrom; /* An element of aFrom[] that we are working on */
WherePath *pTo; /* An element of aTo[] that we are working on */
WhereLoop *pWLoop; /* One of the WhereLoop objects */
WhereLoop **pX; /* Used to divy up the pSpace memory */
+ LogEst *aSortCost = 0; /* Sorting and partial sorting costs */
char *pSpace; /* Temporary memory used by this routine */
+ int nSpace; /* Bytes of space allocated at pSpace */
pParse = pWInfo->pParse;
db = pParse->db;
nLoop = pWInfo->nLevel;
/* TUNING: For simple queries, only the best path is tracked.
** For 2-way joins, the 5 best paths are followed.
** For joins of 3 or more tables, track the 10 best paths */
mxChoice = (nLoop<=1) ? 1 : (nLoop==2 ? 5 : 10);
assert( nLoop<=pWInfo->pTabList->nSrc );
- WHERETRACE(0x002, ("---- begin solver\n"));
+ WHERETRACE(0x002, ("---- begin solver. (nRowEst=%d)\n", nRowEst));
- /* Allocate and initialize space for aTo and aFrom */
- ii = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2;
- pSpace = sqlite3DbMallocRaw(db, ii);
+ /* If nRowEst is zero and there is an ORDER BY clause, ignore it. In this
+ ** case the purpose of this call is to estimate the number of rows returned
+ ** by the overall query. Once this estimate has been obtained, the caller
+ ** will invoke this function a second time, passing the estimate as the
+ ** nRowEst parameter. */
+ if( pWInfo->pOrderBy==0 || nRowEst==0 ){
+ nOrderBy = 0;
+ }else{
+ nOrderBy = pWInfo->pOrderBy->nExpr;
+ }
+
+ /* Allocate and initialize space for aTo, aFrom and aSortCost[] */
+ nSpace = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2;
+ nSpace += sizeof(LogEst) * nOrderBy;
+ pSpace = sqlite3DbMallocRaw(db, nSpace);
if( pSpace==0 ) return SQLITE_NOMEM;
aTo = (WherePath*)pSpace;
aFrom = aTo+mxChoice;
memset(aFrom, 0, sizeof(aFrom[0]));
pX = (WhereLoop**)(aFrom+mxChoice);
for(ii=mxChoice*2, pFrom=aTo; ii>0; ii--, pFrom++, pX += nLoop){
pFrom->aLoop = pX;
}
+ if( nOrderBy ){
+ /* If there is an ORDER BY clause and it is not being ignored, set up
+ ** space for the aSortCost[] array. Each element of the aSortCost array
+ ** is either zero - meaning it has not yet been initialized - or the
+ ** cost of sorting nRowEst rows of data where the first X terms of
+ ** the ORDER BY clause are already in order, where X is the array
+ ** index. */
+ aSortCost = (LogEst*)pX;
+ memset(aSortCost, 0, sizeof(LogEst) * nOrderBy);
+ }
+ assert( aSortCost==0 || &pSpace[nSpace]==(char*)&aSortCost[nOrderBy] );
+ assert( aSortCost!=0 || &pSpace[nSpace]==(char*)pX );
/* Seed the search with a single WherePath containing zero WhereLoops.
**
** TUNING: Do not let the number of iterations go above 25. If the cost
** of computing an automatic index is not paid back within the first 25
** rows, then do not use the automatic index. */
aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==sqlite3LogEst(25) );
nFrom = 1;
-
- /* Precompute the cost of sorting the final result set, if the caller
- ** to sqlite3WhereBegin() was concerned about sorting */
- if( pWInfo->pOrderBy==0 || nRowEst==0 ){
- aFrom[0].isOrdered = 0;
- nOrderBy = 0;
- }else{
- aFrom[0].isOrdered = nLoop>0 ? -1 : 1;
- nOrderBy = pWInfo->pOrderBy->nExpr;
+ assert( aFrom[0].isOrdered==0 );
+ if( nOrderBy ){
+ /* If nLoop is zero, then there are no FROM terms in the query. Since
+ ** in this case the query may return a maximum of one row, the results
+ ** are already in the requested order. Set isOrdered to nOrderBy to
+ ** indicate this. Or, if nLoop is greater than zero, set isOrdered to
+ ** -1, indicating that the result set may or may not be ordered,
+ ** depending on the loops added to the current plan. */
+ aFrom[0].isOrdered = nLoop>0 ? -1 : nOrderBy;
}
/* Compute successively longer WherePaths using the previous generation
** of WherePaths as the basis for the next. Keep track of the mxChoice
** best paths at each generation */
for(iLoop=0; iLooppLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
- Bitmask maskNew;
- Bitmask revMask = 0;
- i8 isOrdered = pFrom->isOrdered;
+ LogEst nOut; /* Rows visited by (pFrom+pWLoop) */
+ LogEst rCost; /* Cost of path (pFrom+pWLoop) */
+ LogEst rUnsorted; /* Unsorted cost of (pFrom+pWLoop) */
+ i8 isOrdered = pFrom->isOrdered; /* isOrdered for (pFrom+pWLoop) */
+ Bitmask maskNew; /* Mask of src visited by (..) */
+ Bitmask revMask = 0; /* Mask of rev-order loops for (..) */
+
if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
/* At this point, pWLoop is a candidate to be the next loop.
** Compute its cost */
- rCost = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
- rCost = sqlite3LogEstAdd(rCost, pFrom->rCost);
+ rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
+ rUnsorted = sqlite3LogEstAdd(rUnsorted, pFrom->rUnsorted);
nOut = pFrom->nRow + pWLoop->nOut;
maskNew = pFrom->maskLoop | pWLoop->maskSelf;
if( isOrdered<0 ){
isOrdered = wherePathSatisfiesOrderBy(pWInfo,
pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
iLoop, pWLoop, &revMask);
- if( isOrdered>=0 && isOrdered0 && 66==sqlite3LogEst(100) );
- rScale = sqlite3LogEst((nOrderBy-isOrdered)*100/nOrderBy) - 66;
- rSortCost = nRowEst + estLog(nRowEst) + rScale + 16;
-
- /* TUNING: The cost of implementing DISTINCT using a B-TREE is
- ** similar but with a larger constant of proportionality.
- ** Multiply by an additional factor of 3.0. */
- if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
- rSortCost += 16;
- }
- WHERETRACE(0x002,
- ("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n",
- rSortCost, (nOrderBy-isOrdered), nOrderBy, rCost,
- sqlite3LogEstAdd(rCost,rSortCost)));
- rCost = sqlite3LogEstAdd(rCost, rSortCost);
- }
}else{
revMask = pFrom->revLoop;
}
- /* Check to see if pWLoop should be added to the mxChoice best so far */
+ if( isOrdered>=0 && isOrderedisOrdered^isOrdered)&0x80)==0" is equivalent
+ ** to (pTo->isOrdered==(-1))==(isOrdered==(-1))" for the range
+ ** of legal values for isOrdered, -1..64.
+ */
for(jj=0, pTo=aTo; jjmaskLoop==maskNew
- && ((pTo->isOrdered^isOrdered)&80)==0
- && ((pTo->rCost<=rCost && pTo->nRow<=nOut) ||
- (pTo->rCost>=rCost && pTo->nRow>=nOut))
+ && ((pTo->isOrdered^isOrdered)&0x80)==0
){
testcase( jj==nTo-1 );
break;
}
}
if( jj>=nTo ){
- if( nTo>=mxChoice && rCost>=mxCost ){
+ /* None of the existing best-so-far paths match the candidate. */
+ if( nTo>=mxChoice
+ && (rCost>mxCost || (rCost==mxCost && rUnsorted>=mxUnsorted))
+ ){
+ /* The current candidate is no better than any of the mxChoice
+ ** paths currently in the best-so-far buffer. So discard
+ ** this candidate as not viable. */
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n",
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
isOrdered>=0 ? isOrdered+'0' : '?');
}
#endif
continue;
}
- /* Add a new Path to the aTo[] set */
+ /* If we reach this points it means that the new candidate path
+ ** needs to be added to the set of best-so-far paths. */
if( nTo=0 ? isOrdered+'0' : '?');
}
#endif
}else{
- if( pTo->rCost<=rCost && pTo->nRow<=nOut ){
+ /* Control reaches here if best-so-far path pTo=aTo[jj] covers the
+ ** same set of loops and has the sam isOrdered setting as the
+ ** candidate path. Check to see if the candidate should replace
+ ** pTo or if the candidate should be skipped */
+ if( pTo->rCostrCost==rCost && pTo->nRow<=nOut) ){
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf(
"Skip %s cost=%-3d,%3d order=%c",
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
@@ -115473,15 +116544,17 @@
sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
}
#endif
+ /* Discard the candidate path from further consideration */
testcase( pTo->rCost==rCost );
continue;
}
testcase( pTo->rCost==rCost+1 );
- /* A new and better score for a previously created equivalent path */
+ /* Control reaches here if the candidate path is better than the
+ ** pTo path. Replace pTo with the candidate. */
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf(
"Update %s cost=%-3d,%3d order=%c",
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
@@ -115495,21 +116568,24 @@
/* pWLoop is a winner. Add it to the set of best so far */
pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf;
pTo->revLoop = revMask;
pTo->nRow = nOut;
pTo->rCost = rCost;
+ pTo->rUnsorted = rUnsorted;
pTo->isOrdered = isOrdered;
memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop);
pTo->aLoop[iLoop] = pWLoop;
if( nTo>=mxChoice ){
mxI = 0;
mxCost = aTo[0].rCost;
- mxOut = aTo[0].nRow;
+ mxUnsorted = aTo[0].nRow;
for(jj=1, pTo=&aTo[1]; jjrCost>mxCost || (pTo->rCost==mxCost && pTo->nRow>mxOut) ){
+ if( pTo->rCost>mxCost
+ || (pTo->rCost==mxCost && pTo->rUnsorted>mxUnsorted)
+ ){
mxCost = pTo->rCost;
- mxOut = pTo->nRow;
+ mxUnsorted = pTo->rUnsorted;
mxI = jj;
}
}
}
}
@@ -115643,11 +116719,11 @@
pLoop->rRun = 33; /* 33==sqlite3LogEst(10) */
}else{
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pLoop->aLTermSpace==pLoop->aLTerm );
assert( ArraySize(pLoop->aLTermSpace)==4 );
- if( pIdx->onError==OE_None
+ if( !IsUniqueIndex(pIdx)
|| pIdx->pPartIdxWhere!=0
|| pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)
) continue;
for(j=0; jnKeyCol; j++){
pTerm = findTerm(pWC, iCur, pIdx->aiColumn[j], 0, WO_EQ, pIdx);
@@ -116133,10 +117209,11 @@
}
op = OP_OpenWrite;
pWInfo->aiCurOnePass[1] = iIndexCur;
}else if( iIdxCur && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ){
iIndexCur = iIdxCur;
+ if( wctrlFlags & WHERE_REOPEN_IDX ) op = OP_ReopenIdx;
}else{
iIndexCur = pParse->nTab++;
}
pLevel->iIdxCur = iIndexCur;
assert( pIx->pSchema==pTab->pSchema );
@@ -120457,10 +121534,16 @@
testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' );
testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' );
testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' );
testcase( z[0]=='9' );
*tokenType = TK_INTEGER;
+#ifndef SQLITE_OMIT_HEX_INTEGER
+ if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){
+ for(i=3; sqlite3Isxdigit(z[i]); i++){}
+ return i;
+ }
+#endif
for(i=0; sqlite3Isdigit(z[i]); i++){}
#ifndef SQLITE_OMIT_FLOATING_POINT
if( z[i]=='.' ){
i++;
while( sqlite3Isdigit(z[i]) ){ i++; }
@@ -121904,10 +122987,12 @@
/*
** Close an existing SQLite database
*/
static int sqlite3Close(sqlite3 *db, int forceZombie){
if( !db ){
+ /* EVIDENCE-OF: R-63257-11740 Calling sqlite3_close() or
+ ** sqlite3_close_v2() with a NULL pointer argument is a harmless no-op. */
return SQLITE_OK;
}
if( !sqlite3SafetyCheckSickOrOk(db) ){
return SQLITE_MISUSE_BKPT;
}
@@ -122133,11 +123218,11 @@
/*
** Return a static string containing the name corresponding to the error code
** specified in the argument.
*/
-#if defined(SQLITE_TEST)
+#if (defined(SQLITE_DEBUG) && SQLITE_OS_WIN) || defined(SQLITE_TEST)
SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
const char *zName = 0;
int i, origRc = rc;
for(i=0; i<2 && zName==0; i++, rc &= 0xff){
switch( rc ){
@@ -122168,11 +123253,10 @@
case SQLITE_IOERR_TRUNCATE: zName = "SQLITE_IOERR_TRUNCATE"; break;
case SQLITE_IOERR_FSTAT: zName = "SQLITE_IOERR_FSTAT"; break;
case SQLITE_IOERR_UNLOCK: zName = "SQLITE_IOERR_UNLOCK"; break;
case SQLITE_IOERR_RDLOCK: zName = "SQLITE_IOERR_RDLOCK"; break;
case SQLITE_IOERR_DELETE: zName = "SQLITE_IOERR_DELETE"; break;
- case SQLITE_IOERR_BLOCKED: zName = "SQLITE_IOERR_BLOCKED"; break;
case SQLITE_IOERR_NOMEM: zName = "SQLITE_IOERR_NOMEM"; break;
case SQLITE_IOERR_ACCESS: zName = "SQLITE_IOERR_ACCESS"; break;
case SQLITE_IOERR_CHECKRESERVEDLOCK:
zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break;
case SQLITE_IOERR_LOCK: zName = "SQLITE_IOERR_LOCK"; break;
@@ -123153,11 +124237,11 @@
SQLITE_MAX_COMPOUND_SELECT,
SQLITE_MAX_VDBE_OP,
SQLITE_MAX_FUNCTION_ARG,
SQLITE_MAX_ATTACHED,
SQLITE_MAX_LIKE_PATTERN_LENGTH,
- SQLITE_MAX_VARIABLE_NUMBER,
+ SQLITE_MAX_VARIABLE_NUMBER, /* IMP: R-38091-32352 */
SQLITE_MAX_TRIGGER_DEPTH,
};
/*
** Make sure the hard limits are set to reasonable values
@@ -123178,12 +124262,12 @@
# error SQLITE_MAX_VDBE_OP must be at least 40
#endif
#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>1000
# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 1000
#endif
-#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>62
-# error SQLITE_MAX_ATTACHED must be between 0 and 62
+#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125
+# error SQLITE_MAX_ATTACHED must be between 0 and 125
#endif
#if SQLITE_MAX_LIKE_PATTERN_LENGTH<1
# error SQLITE_MAX_LIKE_PATTERN_LENGTH must be at least 1
#endif
#if SQLITE_MAX_COLUMN>32767
@@ -124205,14 +125289,14 @@
** sqlite3_test_control().
*/
case SQLITE_TESTCTRL_FAULT_INSTALL: {
/* MSVC is picky about pulling func ptrs from va lists.
** http://support.microsoft.com/kb/47961
- ** sqlite3Config.xTestCallback = va_arg(ap, int(*)(int));
+ ** sqlite3GlobalConfig.xTestCallback = va_arg(ap, int(*)(int));
*/
typedef int(*TESTCALLBACKFUNC_t)(int);
- sqlite3Config.xTestCallback = va_arg(ap, TESTCALLBACKFUNC_t);
+ sqlite3GlobalConfig.xTestCallback = va_arg(ap, TESTCALLBACKFUNC_t);
rc = sqlite3FaultSim(0);
break;
}
/*
@@ -124438,10 +125522,20 @@
sqlite3GlobalConfig.pVdbeBranchArg = va_arg(ap,void*);
#endif
break;
}
+ /* sqlite3_test_control(SQLITE_TESTCTRL_ISINIT);
+ **
+ ** Return SQLITE_OK if SQLite has been initialized and SQLITE_ERROR if
+ ** not.
+ */
+ case SQLITE_TESTCTRL_ISINIT: {
+ if( sqlite3GlobalConfig.isInit==0 ) rc = SQLITE_ERROR;
+ break;
+ }
+
}
va_end(ap);
#endif /* SQLITE_OMIT_BUILTIN_TEST */
return rc;
}
@@ -124486,11 +125580,11 @@
const char *zParam, /* URI parameter sought */
sqlite3_int64 bDflt /* return if parameter is missing */
){
const char *z = sqlite3_uri_parameter(zFilename, zParam);
sqlite3_int64 v;
- if( z && sqlite3Atoi64(z, &v, sqlite3Strlen30(z), SQLITE_UTF8)==SQLITE_OK ){
+ if( z && sqlite3DecOrHexToI64(z, &v)==SQLITE_OK ){
bDflt = v;
}
return bDflt;
}
@@ -126017,11 +127111,11 @@
/* fts3_tokenize_vtab.c */
SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *);
/* fts3_unicode2.c (functions generated by parsing unicode text files) */
-#ifdef SQLITE_ENABLE_FTS4_UNICODE61
+#ifndef SQLITE_DISABLE_FTS3_UNICODE
SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int, int);
SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int);
SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int);
#endif
@@ -129487,11 +130581,11 @@
** to by the argument to point to the "simple" tokenizer implementation.
** And so on.
*/
SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule);
SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(sqlite3_tokenizer_module const**ppModule);
-#ifdef SQLITE_ENABLE_FTS4_UNICODE61
+#ifndef SQLITE_DISABLE_FTS3_UNICODE
SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const**ppModule);
#endif
#ifdef SQLITE_ENABLE_ICU
SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule);
#endif
@@ -129505,20 +130599,20 @@
SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
int rc = SQLITE_OK;
Fts3Hash *pHash = 0;
const sqlite3_tokenizer_module *pSimple = 0;
const sqlite3_tokenizer_module *pPorter = 0;
-#ifdef SQLITE_ENABLE_FTS4_UNICODE61
+#ifndef SQLITE_DISABLE_FTS3_UNICODE
const sqlite3_tokenizer_module *pUnicode = 0;
#endif
#ifdef SQLITE_ENABLE_ICU
const sqlite3_tokenizer_module *pIcu = 0;
sqlite3Fts3IcuTokenizerModule(&pIcu);
#endif
-#ifdef SQLITE_ENABLE_FTS4_UNICODE61
+#ifndef SQLITE_DISABLE_FTS3_UNICODE
sqlite3Fts3UnicodeTokenizer(&pUnicode);
#endif
#ifdef SQLITE_TEST
rc = sqlite3Fts3InitTerm(db);
@@ -129542,11 +130636,11 @@
/* Load the built-in tokenizers into the hash table */
if( rc==SQLITE_OK ){
if( sqlite3Fts3HashInsert(pHash, "simple", 7, (void *)pSimple)
|| sqlite3Fts3HashInsert(pHash, "porter", 7, (void *)pPorter)
-#ifdef SQLITE_ENABLE_FTS4_UNICODE61
+#ifndef SQLITE_DISABLE_FTS3_UNICODE
|| sqlite3Fts3HashInsert(pHash, "unicode61", 10, (void *)pUnicode)
#endif
#ifdef SQLITE_ENABLE_ICU
|| (pIcu && sqlite3Fts3HashInsert(pHash, "icu", 4, (void *)pIcu))
#endif
@@ -140777,38 +141871,40 @@
i64 iDocid = sqlite3_column_int64(pStmt, 0);
int iLang = langidFromSelect(p, pStmt);
int iCol;
for(iCol=0; rc==SQLITE_OK && iColnColumn; iCol++){
- const char *zText = (const char *)sqlite3_column_text(pStmt, iCol+1);
- int nText = sqlite3_column_bytes(pStmt, iCol+1);
- sqlite3_tokenizer_cursor *pT = 0;
-
- rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, nText, &pT);
- while( rc==SQLITE_OK ){
- char const *zToken; /* Buffer containing token */
- int nToken = 0; /* Number of bytes in token */
- int iDum1 = 0, iDum2 = 0; /* Dummy variables */
- int iPos = 0; /* Position of token in zText */
-
- rc = pModule->xNext(pT, &zToken, &nToken, &iDum1, &iDum2, &iPos);
- if( rc==SQLITE_OK ){
- int i;
- cksum2 = cksum2 ^ fts3ChecksumEntry(
- zToken, nToken, iLang, 0, iDocid, iCol, iPos
- );
- for(i=1; inIndex; i++){
- if( p->aIndex[i].nPrefix<=nToken ){
- cksum2 = cksum2 ^ fts3ChecksumEntry(
- zToken, p->aIndex[i].nPrefix, iLang, i, iDocid, iCol, iPos
- );
- }
- }
- }
- }
- if( pT ) pModule->xClose(pT);
- if( rc==SQLITE_DONE ) rc = SQLITE_OK;
+ if( p->abNotindexed[iCol]==0 ){
+ const char *zText = (const char *)sqlite3_column_text(pStmt, iCol+1);
+ int nText = sqlite3_column_bytes(pStmt, iCol+1);
+ sqlite3_tokenizer_cursor *pT = 0;
+
+ rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, nText,&pT);
+ while( rc==SQLITE_OK ){
+ char const *zToken; /* Buffer containing token */
+ int nToken = 0; /* Number of bytes in token */
+ int iDum1 = 0, iDum2 = 0; /* Dummy variables */
+ int iPos = 0; /* Position of token in zText */
+
+ rc = pModule->xNext(pT, &zToken, &nToken, &iDum1, &iDum2, &iPos);
+ if( rc==SQLITE_OK ){
+ int i;
+ cksum2 = cksum2 ^ fts3ChecksumEntry(
+ zToken, nToken, iLang, 0, iDocid, iCol, iPos
+ );
+ for(i=1; inIndex; i++){
+ if( p->aIndex[i].nPrefix<=nToken ){
+ cksum2 = cksum2 ^ fts3ChecksumEntry(
+ zToken, p->aIndex[i].nPrefix, iLang, i, iDocid, iCol, iPos
+ );
+ }
+ }
+ }
+ }
+ if( pT ) pModule->xClose(pT);
+ if( rc==SQLITE_DONE ) rc = SQLITE_OK;
+ }
}
}
sqlite3_finalize(pStmt);
}
@@ -142800,11 +143896,11 @@
******************************************************************************
**
** Implementation of the "unicode" full-text-search tokenizer.
*/
-#ifdef SQLITE_ENABLE_FTS4_UNICODE61
+#ifndef SQLITE_DISABLE_FTS3_UNICODE
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
/* #include */
/* #include */
@@ -143016,11 +144112,11 @@
memset(pNew, 0, sizeof(unicode_tokenizer));
pNew->bRemoveDiacritic = 1;
for(i=0; rc==SQLITE_OK && ibRemoveDiacritic = 1;
}
else if( n==19 && memcmp("remove_diacritics=0", z, 19)==0 ){
@@ -143103,11 +144199,11 @@
int *piEnd, /* OUT: Ending offset of token */
int *piPos /* OUT: Position integer of token */
){
unicode_cursor *pCsr = (unicode_cursor *)pC;
unicode_tokenizer *p = ((unicode_tokenizer *)pCsr->base.pTokenizer);
- int iCode;
+ int iCode = 0;
char *zOut;
const unsigned char *z = &pCsr->aInput[pCsr->iOff];
const unsigned char *zStart = z;
const unsigned char *zEnd;
const unsigned char *zTerm = &pCsr->aInput[pCsr->nInput];
@@ -143148,15 +144244,15 @@
}while( unicodeIsAlnum(p, iCode)
|| sqlite3FtsUnicodeIsdiacritic(iCode)
);
/* Set the output variables and return. */
- pCsr->iOff = (z - pCsr->aInput);
+ pCsr->iOff = (int)(z - pCsr->aInput);
*paToken = pCsr->zToken;
- *pnToken = zOut - pCsr->zToken;
- *piStart = (zStart - pCsr->aInput);
- *piEnd = (zEnd - pCsr->aInput);
+ *pnToken = (int)(zOut - pCsr->zToken);
+ *piStart = (int)(zStart - pCsr->aInput);
+ *piEnd = (int)(zEnd - pCsr->aInput);
*piPos = pCsr->iToken++;
return SQLITE_OK;
}
/*
@@ -143175,11 +144271,11 @@
};
*ppModule = &module;
}
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */
-#endif /* ifndef SQLITE_ENABLE_FTS4_UNICODE61 */
+#endif /* ifndef SQLITE_DISABLE_FTS3_UNICODE */
/************** End of fts3_unicode.c ****************************************/
/************** Begin file fts3_unicode2.c ***********************************/
/*
** 2012 May 25
@@ -143196,11 +144292,11 @@
/*
** DO NOT EDIT THIS MACHINE GENERATED FILE.
*/
-#if defined(SQLITE_ENABLE_FTS4_UNICODE61)
+#ifndef SQLITE_DISABLE_FTS3_UNICODE
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
/* #include */
/*
@@ -143220,11 +144316,11 @@
** the size of the range (always at least 1). In other words, the value
** ((C<<22) + N) represents a range of N codepoints starting with codepoint
** C. It is not possible to represent a range larger than 1023 codepoints
** using this format.
*/
- const static unsigned int aEntry[] = {
+ static const unsigned int aEntry[] = {
0x00000030, 0x0000E807, 0x00016C06, 0x0001EC2F, 0x0002AC07,
0x0002D001, 0x0002D803, 0x0002EC01, 0x0002FC01, 0x00035C01,
0x0003DC01, 0x000B0804, 0x000B480E, 0x000B9407, 0x000BB401,
0x000BBC81, 0x000DD401, 0x000DF801, 0x000E1002, 0x000E1C01,
0x000FD801, 0x00120808, 0x00156806, 0x00162402, 0x00163C01,
@@ -143312,11 +144408,11 @@
if( c<128 ){
return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
}else if( c<(1<<22) ){
unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
- int iRes;
+ int iRes = 0;
int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
int iLo = 0;
while( iHi>=iLo ){
int iTest = (iHi + iLo) / 2;
if( key >= aEntry[iTest] ){
@@ -143383,11 +144479,11 @@
iHi = iTest-1;
}
}
assert( key>=aDia[iRes] );
return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]);
-};
+}
/*
** Return true if the argument interpreted as a unicode codepoint
** is a diacritical modifier character.
@@ -143543,11 +144639,11 @@
}
return ret;
}
#endif /* defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) */
-#endif /* !defined(SQLITE_ENABLE_FTS4_UNICODE61) */
+#endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */
/************** End of fts3_unicode2.c ***************************************/
/************** Begin file rtree.c *******************************************/
/*
** 2001 September 15
@@ -145080,13 +146176,17 @@
int rc = SQLITE_OK;
int iCell = 0;
rtreeReference(pRtree);
+ /* Reset the cursor to the same state as rtreeOpen() leaves it in. */
freeCursorConstraints(pCsr);
+ sqlite3_free(pCsr->aPoint);
+ memset(pCsr, 0, sizeof(RtreeCursor));
+ pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
+
pCsr->iStrategy = idxNum;
-
if( idxNum==1 ){
/* Special case - lookup by rowid. */
RtreeNode *pLeaf; /* Leaf on which the required cell resides */
RtreeSearchPoint *p; /* Search point for the the leaf */
i64 iRowid = sqlite3_value_int64(argv[0]);
Index: SQLite.Interop/src/core/sqlite3.h
==================================================================
--- SQLite.Interop/src/core/sqlite3.h
+++ SQLite.Interop/src/core/sqlite3.h
@@ -105,13 +105,13 @@
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.8.5"
-#define SQLITE_VERSION_NUMBER 3008005
-#define SQLITE_SOURCE_ID "2014-06-04 14:06:34 b1ed4f2a34ba66c29b130f8d13e9092758019212"
+#define SQLITE_VERSION "3.8.6"
+#define SQLITE_VERSION_NUMBER 3008006
+#define SQLITE_SOURCE_ID "2014-08-15 11:46:33 9491ba7d738528f168657adb43a198238abde19e"
/*
** CAPI3REF: Run-Time Library Version Numbers
** KEYWORDS: sqlite3_version, sqlite3_sourceid
**
@@ -267,19 +267,19 @@
/*
** CAPI3REF: Closing A Database Connection
**
** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors
** for the [sqlite3] object.
-** ^Calls to sqlite3_close() and sqlite3_close_v2() return SQLITE_OK if
+** ^Calls to sqlite3_close() and sqlite3_close_v2() return [SQLITE_OK] if
** the [sqlite3] object is successfully destroyed and all associated
** resources are deallocated.
**
** ^If the database connection is associated with unfinalized prepared
** statements or unfinished sqlite3_backup objects then sqlite3_close()
** will leave the database connection open and return [SQLITE_BUSY].
** ^If sqlite3_close_v2() is called with unfinalized prepared statements
-** and unfinished sqlite3_backups, then the database connection becomes
+** and/or unfinished sqlite3_backups, then the database connection becomes
** an unusable "zombie" which will automatically be deallocated when the
** last prepared statement is finalized or the last sqlite3_backup is
** finished. The sqlite3_close_v2() interface is intended for use with
** host languages that are garbage collected, and where the order in which
** destructors are called is arbitrary.
@@ -288,11 +288,11 @@
** [sqlite3_blob_close | close] all [BLOB handles], and
** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
** with the [sqlite3] object prior to attempting to close the object. ^If
** sqlite3_close_v2() is called on a [database connection] that still has
** outstanding [prepared statements], [BLOB handles], and/or
-** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation
+** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation
** of resources is deferred until all [prepared statements], [BLOB handles],
** and [sqlite3_backup] objects are also destroyed.
**
** ^If an [sqlite3] object is destroyed while a transaction is open,
** the transaction is automatically rolled back.
@@ -384,20 +384,18 @@
char **errmsg /* Error msg written here */
);
/*
** CAPI3REF: Result Codes
-** KEYWORDS: SQLITE_OK {error code} {error codes}
-** KEYWORDS: {result code} {result codes}
+** KEYWORDS: {result code definitions}
**
** Many SQLite functions return an integer result code from the set shown
** here in order to indicate success or failure.
**
** New error codes may be added in future versions of SQLite.
**
-** See also: [SQLITE_IOERR_READ | extended result codes],
-** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes].
+** See also: [extended result code definitions]
*/
#define SQLITE_OK 0 /* Successful result */
/* beginning-of-error-codes */
#define SQLITE_ERROR 1 /* SQL error or missing database */
#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */
@@ -431,30 +429,23 @@
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
/* end-of-error-codes */
/*
** CAPI3REF: Extended Result Codes
-** KEYWORDS: {extended error code} {extended error codes}
-** KEYWORDS: {extended result code} {extended result codes}
+** KEYWORDS: {extended result code definitions}
**
-** In its default configuration, SQLite API routines return one of 26 integer
-** [SQLITE_OK | result codes]. However, experience has shown that many of
+** In its default configuration, SQLite API routines return one of 30 integer
+** [result codes]. However, experience has shown that many of
** these result codes are too coarse-grained. They do not provide as
** much information about problems as programmers might like. In an effort to
** address this, newer versions of SQLite (version 3.3.8 and later) include
** support for additional result codes that provide more detailed information
-** about errors. The extended result codes are enabled or disabled
+** about errors. These [extended result codes] are enabled or disabled
** on a per database connection basis using the
-** [sqlite3_extended_result_codes()] API.
-**
-** Some of the available extended result codes are listed here.
-** One may expect the number of extended result codes will increase
-** over time. Software that uses extended result codes should expect
-** to see new result codes in future releases of SQLite.
-**
-** The SQLITE_OK result code will never be extended. It will always
-** be exactly zero.
+** [sqlite3_extended_result_codes()] API. Or, the extended code for
+** the most recent error can be obtained using
+** [sqlite3_extended_errcode()].
*/
#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))
#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))
#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8))
#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8))
@@ -683,11 +674,11 @@
** write return values. Potential uses for xFileControl() might be
** functions to enable blocking locks with timeouts, to change the
** locking strategy (for example to use dot-file locks), to inquire
** about the status of a lock, or to break stale locks. The SQLite
** core reserves all opcodes less than 100 for its own use.
-** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available.
+** A [file control opcodes | list of opcodes] less than 100 is available.
** Applications that define a custom xFileControl method should use opcodes
** greater than 100 to avoid conflicts. VFS implementations should
** return [SQLITE_NOTFOUND] for file control opcodes that they do not
** recognize.
**
@@ -756,10 +747,11 @@
/* Additional methods may be added in future releases */
};
/*
** CAPI3REF: Standard File Control Opcodes
+** KEYWORDS: {file control opcodes} {file control opcode}
**
** These integer constants are opcodes for the xFileControl method
** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()]
** interface.
**
@@ -2035,31 +2027,37 @@
SQLITE_API int sqlite3_complete16(const void *sql);
/*
** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
**
-** ^This routine sets a callback function that might be invoked whenever
-** an attempt is made to open a database table that another thread
-** or process has locked.
+** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X
+** that might be invoked with argument P whenever
+** an attempt is made to access a database table associated with
+** [database connection] D when another thread
+** or process has the table locked.
+** The sqlite3_busy_handler() interface is used to implement
+** [sqlite3_busy_timeout()] and [PRAGMA busy_timeout].
**
-** ^If the busy callback is NULL, then [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED]
+** ^If the busy callback is NULL, then [SQLITE_BUSY]
** is returned immediately upon encountering the lock. ^If the busy callback
** is not NULL, then the callback might be invoked with two arguments.
**
** ^The first argument to the busy handler is a copy of the void* pointer which
** is the third argument to sqlite3_busy_handler(). ^The second argument to
** the busy handler callback is the number of times that the busy handler has
-** been invoked for this locking event. ^If the
+** been invoked for the same locking event. ^If the
** busy callback returns 0, then no additional attempts are made to
-** access the database and [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] is returned.
+** access the database and [SQLITE_BUSY] is returned
+** to the application.
** ^If the callback returns non-zero, then another attempt
-** is made to open the database for reading and the cycle repeats.
+** is made to access the database and the cycle repeats.
**
** The presence of a busy handler does not guarantee that it will be invoked
** when there is lock contention. ^If SQLite determines that invoking the busy
** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY]
-** or [SQLITE_IOERR_BLOCKED] instead of invoking the busy handler.
+** to the application instead of invoking the
+** busy handler.
** Consider a scenario where one process is holding a read lock that
** it is trying to promote to a reserved lock and
** a second process is holding a reserved lock that it is trying
** to promote to an exclusive lock. The first process cannot proceed
** because it is blocked by the second and the second process cannot
@@ -2069,32 +2067,19 @@
** will induce the first process to release its read lock and allow
** the second process to proceed.
**
** ^The default busy callback is NULL.
**
-** ^The [SQLITE_BUSY] error is converted to [SQLITE_IOERR_BLOCKED]
-** when SQLite is in the middle of a large transaction where all the
-** changes will not fit into the in-memory cache. SQLite will
-** already hold a RESERVED lock on the database file, but it needs
-** to promote this lock to EXCLUSIVE so that it can spill cache
-** pages into the database file without harm to concurrent
-** readers. ^If it is unable to promote the lock, then the in-memory
-** cache will be left in an inconsistent state and so the error
-** code is promoted from the relatively benign [SQLITE_BUSY] to
-** the more severe [SQLITE_IOERR_BLOCKED]. ^This error code promotion
-** forces an automatic rollback of the changes. See the
-**
-** CorruptionFollowingBusyError wiki page for a discussion of why
-** this is important.
-**
** ^(There can only be a single busy handler defined for each
** [database connection]. Setting a new busy handler clears any
** previously set handler.)^ ^Note that calling [sqlite3_busy_timeout()]
-** will also set or clear the busy handler.
+** or evaluating [PRAGMA busy_timeout=N] will change the
+** busy handler and thus clear any previously set busy handler.
**
** The busy callback should not take any actions which modify the
-** database connection that invoked the busy handler. Any such actions
+** database connection that invoked the busy handler. In other words,
+** the busy handler is not reentrant. Any such actions
** result in undefined behavior.
**
** A busy handler must not close the database connection
** or [prepared statement] that invoked the busy handler.
*/
@@ -2106,19 +2091,21 @@
** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps
** for a specified amount of time when a table is locked. ^The handler
** will sleep multiple times until at least "ms" milliseconds of sleeping
** have accumulated. ^After at least "ms" milliseconds of sleeping,
** the handler returns 0 which causes [sqlite3_step()] to return
-** [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED].
+** [SQLITE_BUSY].
**
** ^Calling this routine with an argument less than or equal to zero
** turns off all busy handlers.
**
** ^(There can only be a single busy handler for a particular
** [database connection] any any given moment. If another busy handler
** was defined (using [sqlite3_busy_handler()]) prior to calling
** this routine, that other busy handler is cleared.)^
+**
+** See also: [PRAGMA busy_timeout]
*/
SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
/*
** CAPI3REF: Convenience Routines For Running Queries
@@ -2516,12 +2503,12 @@
** return either [SQLITE_OK] or one of these two constants in order
** to signal SQLite whether or not the action is permitted. See the
** [sqlite3_set_authorizer | authorizer documentation] for additional
** information.
**
-** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code]
-** from the [sqlite3_vtab_on_conflict()] interface.
+** Note that SQLITE_IGNORE is also used as a [conflict resolution mode]
+** returned from the [sqlite3_vtab_on_conflict()] interface.
*/
#define SQLITE_DENY 1 /* Abort the SQL statement with an error */
#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
/*
@@ -4703,10 +4690,17 @@
** the name of a folder (a.k.a. directory), then all temporary files
** created by SQLite when using a built-in [sqlite3_vfs | VFS]
** will be placed in that directory.)^ ^If this variable
** is a NULL pointer, then SQLite performs a search for an appropriate
** temporary file directory.
+**
+** Applications are strongly discouraged from using this global variable.
+** It is required to set a temporary folder on Windows Runtime (WinRT).
+** But for all other platforms, it is highly recommended that applications
+** neither read nor write this variable. This global variable is a relic
+** that exists for backwards compatibility of legacy applications and should
+** be avoided in new projects.
**
** It is not safe to read or modify this variable in more than one
** thread at a time. It is not safe to read or modify this variable
** if a [database connection] is being used at the same time in a separate
** thread.
@@ -4722,10 +4716,15 @@
** [sqlite3_malloc] and the pragma may attempt to free that memory
** using [sqlite3_free].
** Hence, if this variable is modified directly, either it should be
** made NULL or made to point to memory obtained from [sqlite3_malloc]
** or else the use of the [temp_store_directory pragma] should be avoided.
+** Except when requested by the [temp_store_directory pragma], SQLite
+** does not free the memory that sqlite3_temp_directory points to. If
+** the application wants that memory to be freed, it must do
+** so itself, taking care to only do so after all [database connection]
+** objects have been destroyed.
**
** Note to Windows Runtime users: The temporary directory must be set
** prior to calling [sqlite3_open] or [sqlite3_open_v2]. Otherwise, various
** features that require the use of temporary files may fail. Here is an
** example of how to do this using C++ with the Windows Runtime:
@@ -5856,14 +5855,16 @@
**
** - SQLITE_MUTEX_FAST
**
- SQLITE_MUTEX_RECURSIVE
**
- SQLITE_MUTEX_STATIC_MASTER
**
- SQLITE_MUTEX_STATIC_MEM
-**
- SQLITE_MUTEX_STATIC_MEM2
+**
- SQLITE_MUTEX_STATIC_OPEN
**
- SQLITE_MUTEX_STATIC_PRNG
**
- SQLITE_MUTEX_STATIC_LRU
-**
- SQLITE_MUTEX_STATIC_LRU2
+**
- SQLITE_MUTEX_STATIC_PMEM
+**
- SQLITE_MUTEX_STATIC_APP1
+**
- SQLITE_MUTEX_STATIC_APP2
**
)^
**
** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
** cause sqlite3_mutex_alloc() to create
** a new mutex. ^The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
@@ -6063,10 +6064,13 @@
#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */
#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */
#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
+#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */
+#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */
+#define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */
/*
** CAPI3REF: Retrieve the mutex for a database connection
**
** ^This interface returns a pointer the [sqlite3_mutex] object that
@@ -6158,11 +6162,12 @@
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
#define SQLITE_TESTCTRL_BYTEORDER 22
-#define SQLITE_TESTCTRL_LAST 22
+#define SQLITE_TESTCTRL_ISINIT 23
+#define SQLITE_TESTCTRL_LAST 23
/*
** CAPI3REF: SQLite Runtime Status
**
** ^This interface is used to retrieve runtime status information
@@ -7141,10 +7146,13 @@
** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism
** configured by this function.
**
** ^The [wal_autocheckpoint pragma] can be used to invoke this interface
** from SQL.
+**
+** ^Checkpoints initiated by this mechanism are
+** [sqlite3_wal_checkpoint_v2|PASSIVE].
**
** ^Every new [database connection] defaults to having the auto-checkpoint
** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT]
** pages. The use of this interface
** is only necessary if the default setting is found to be suboptimal
@@ -7158,10 +7166,14 @@
** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X
** on [database connection] D to be [checkpointed]. ^If X is NULL or an
** empty string, then a checkpoint is run on all databases of
** connection D. ^If the database connection D is not in
** [WAL | write-ahead log mode] then this interface is a harmless no-op.
+** ^The [sqlite3_wal_checkpoint(D,X)] interface initiates a
+** [sqlite3_wal_checkpoint_v2|PASSIVE] checkpoint.
+** Use the [sqlite3_wal_checkpoint_v2()] interface to get a FULL
+** or RESET checkpoint.
**
** ^The [wal_checkpoint pragma] can be used to invoke this interface
** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the
** [wal_autocheckpoint pragma] can be used to cause this interface to be
** run whenever the WAL reaches a certain size threshold.
@@ -7180,22 +7192,25 @@
**
** - SQLITE_CHECKPOINT_PASSIVE
-
** Checkpoint as many frames as possible without waiting for any database
** readers or writers to finish. Sync the db file if all frames in the log
** are checkpointed. This mode is the same as calling
-** sqlite3_wal_checkpoint(). The busy-handler callback is never invoked.
+** sqlite3_wal_checkpoint(). The [sqlite3_busy_handler|busy-handler callback]
+** is never invoked.
**
**
- SQLITE_CHECKPOINT_FULL
-
-** This mode blocks (calls the busy-handler callback) until there is no
+** This mode blocks (it invokes the
+** [sqlite3_busy_handler|busy-handler callback]) until there is no
** database writer and all readers are reading from the most recent database
** snapshot. It then checkpoints all frames in the log file and syncs the
** database file. This call blocks database writers while it is running,
** but not database readers.
**
**
- SQLITE_CHECKPOINT_RESTART
-
** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after
-** checkpointing the log file it blocks (calls the busy-handler callback)
+** checkpointing the log file it blocks (calls the
+** [sqlite3_busy_handler|busy-handler callback])
** until all readers are reading from the database file only. This ensures
** that the next client to write to the database file restarts the log file
** from the beginning. This call blocks database writers while it is running,
** but not database readers.
**
@@ -7329,10 +7344,11 @@
*/
SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
/*
** CAPI3REF: Conflict resolution modes
+** KEYWORDS: {conflict resolution mode}
**
** These constants are returned by [sqlite3_vtab_on_conflict()] to
** inform a [virtual table] implementation what the [ON CONFLICT] mode
** is for the SQL statement being evaluated.
**
Index: SQLite.NET.2005.MSBuild.sln
==================================================================
--- SQLite.NET.2005.MSBuild.sln
+++ SQLite.NET.2005.MSBuild.sln
@@ -4,17 +4,14 @@
ProjectSection(SolutionItems) = preProject
data\exclude_bin.txt = data\exclude_bin.txt
data\exclude_src.txt = data\exclude_src.txt
Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk
Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk
- NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform
- NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform
- NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform
- NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1
- NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1
- NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1
- NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1
+ NuGet\shared\Core\build\System.Data.SQLite.Core.targets = NuGet\shared\Core\build\System.Data.SQLite.Core.targets
+ NuGet\shared\Core\content\config.transform = NuGet\shared\Core\content\config.transform
+ NuGet\net40\EF6\content\config.transform = NuGet\net40\EF6\content\config.transform
+ NuGet\net40\EF6\tools\provider.ps1 = NuGet\net40\EF6\tools\provider.ps1
NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec
NuGet\SQLite.Core.Beta.nuspec = NuGet\SQLite.Core.Beta.nuspec
NuGet\SQLite.Core.Test.nuspec = NuGet\SQLite.Core.Test.nuspec
NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec
NuGet\SQLite.Core.MSIL.Beta.nuspec = NuGet\SQLite.Core.MSIL.Beta.nuspec
Index: SQLite.NET.2005.sln
==================================================================
--- SQLite.NET.2005.sln
+++ SQLite.NET.2005.sln
@@ -4,17 +4,14 @@
ProjectSection(SolutionItems) = preProject
data\exclude_bin.txt = data\exclude_bin.txt
data\exclude_src.txt = data\exclude_src.txt
Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk
Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk
- NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform
- NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform
- NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform
- NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1
- NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1
- NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1
- NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1
+ NuGet\shared\Core\build\System.Data.SQLite.Core.targets = NuGet\shared\Core\build\System.Data.SQLite.Core.targets
+ NuGet\shared\Core\content\config.transform = NuGet\shared\Core\content\config.transform
+ NuGet\net40\EF6\content\config.transform = NuGet\net40\EF6\content\config.transform
+ NuGet\net40\EF6\tools\provider.ps1 = NuGet\net40\EF6\tools\provider.ps1
NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec
NuGet\SQLite.Core.Beta.nuspec = NuGet\SQLite.Core.Beta.nuspec
NuGet\SQLite.Core.Test.nuspec = NuGet\SQLite.Core.Test.nuspec
NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec
NuGet\SQLite.Core.MSIL.Beta.nuspec = NuGet\SQLite.Core.MSIL.Beta.nuspec
Index: SQLite.NET.2008.MSBuild.sln
==================================================================
--- SQLite.NET.2008.MSBuild.sln
+++ SQLite.NET.2008.MSBuild.sln
@@ -4,17 +4,14 @@
ProjectSection(SolutionItems) = preProject
data\exclude_bin.txt = data\exclude_bin.txt
data\exclude_src.txt = data\exclude_src.txt
Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk
Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk
- NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform
- NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform
- NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform
- NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1
- NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1
- NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1
- NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1
+ NuGet\shared\Core\build\System.Data.SQLite.Core.targets = NuGet\shared\Core\build\System.Data.SQLite.Core.targets
+ NuGet\shared\Core\content\config.transform = NuGet\shared\Core\content\config.transform
+ NuGet\net40\EF6\content\config.transform = NuGet\net40\EF6\content\config.transform
+ NuGet\net40\EF6\tools\provider.ps1 = NuGet\net40\EF6\tools\provider.ps1
NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec
NuGet\SQLite.Core.Beta.nuspec = NuGet\SQLite.Core.Beta.nuspec
NuGet\SQLite.Core.Test.nuspec = NuGet\SQLite.Core.Test.nuspec
NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec
NuGet\SQLite.Core.MSIL.Beta.nuspec = NuGet\SQLite.Core.MSIL.Beta.nuspec
Index: SQLite.NET.2008.sln
==================================================================
--- SQLite.NET.2008.sln
+++ SQLite.NET.2008.sln
@@ -4,17 +4,14 @@
ProjectSection(SolutionItems) = preProject
data\exclude_bin.txt = data\exclude_bin.txt
data\exclude_src.txt = data\exclude_src.txt
Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk
Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk
- NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform
- NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform
- NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform
- NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1
- NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1
- NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1
- NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1
+ NuGet\shared\Core\build\System.Data.SQLite.Core.targets = NuGet\shared\Core\build\System.Data.SQLite.Core.targets
+ NuGet\shared\Core\content\config.transform = NuGet\shared\Core\content\config.transform
+ NuGet\net40\EF6\content\config.transform = NuGet\net40\EF6\content\config.transform
+ NuGet\net40\EF6\tools\provider.ps1 = NuGet\net40\EF6\tools\provider.ps1
NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec
NuGet\SQLite.Core.Beta.nuspec = NuGet\SQLite.Core.Beta.nuspec
NuGet\SQLite.Core.Test.nuspec = NuGet\SQLite.Core.Test.nuspec
NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec
NuGet\SQLite.Core.MSIL.Beta.nuspec = NuGet\SQLite.Core.MSIL.Beta.nuspec
Index: SQLite.NET.2010.MSBuild.sln
==================================================================
--- SQLite.NET.2010.MSBuild.sln
+++ SQLite.NET.2010.MSBuild.sln
@@ -4,17 +4,14 @@
ProjectSection(SolutionItems) = preProject
data\exclude_bin.txt = data\exclude_bin.txt
data\exclude_src.txt = data\exclude_src.txt
Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk
Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk
- NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform
- NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform
- NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform
- NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1
- NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1
- NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1
- NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1
+ NuGet\shared\Core\build\System.Data.SQLite.Core.targets = NuGet\shared\Core\build\System.Data.SQLite.Core.targets
+ NuGet\shared\Core\content\config.transform = NuGet\shared\Core\content\config.transform
+ NuGet\net40\EF6\content\config.transform = NuGet\net40\EF6\content\config.transform
+ NuGet\net40\EF6\tools\provider.ps1 = NuGet\net40\EF6\tools\provider.ps1
NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec
NuGet\SQLite.Core.Beta.nuspec = NuGet\SQLite.Core.Beta.nuspec
NuGet\SQLite.Core.Test.nuspec = NuGet\SQLite.Core.Test.nuspec
NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec
NuGet\SQLite.Core.MSIL.Beta.nuspec = NuGet\SQLite.Core.MSIL.Beta.nuspec
Index: SQLite.NET.2010.sln
==================================================================
--- SQLite.NET.2010.sln
+++ SQLite.NET.2010.sln
@@ -4,17 +4,14 @@
ProjectSection(SolutionItems) = preProject
data\exclude_bin.txt = data\exclude_bin.txt
data\exclude_src.txt = data\exclude_src.txt
Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk
Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk
- NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform
- NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform
- NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform
- NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1
- NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1
- NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1
- NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1
+ NuGet\shared\Core\build\System.Data.SQLite.Core.targets = NuGet\shared\Core\build\System.Data.SQLite.Core.targets
+ NuGet\shared\Core\content\config.transform = NuGet\shared\Core\content\config.transform
+ NuGet\net40\EF6\content\config.transform = NuGet\net40\EF6\content\config.transform
+ NuGet\net40\EF6\tools\provider.ps1 = NuGet\net40\EF6\tools\provider.ps1
NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec
NuGet\SQLite.Core.Beta.nuspec = NuGet\SQLite.Core.Beta.nuspec
NuGet\SQLite.Core.Test.nuspec = NuGet\SQLite.Core.Test.nuspec
NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec
NuGet\SQLite.Core.MSIL.Beta.nuspec = NuGet\SQLite.Core.MSIL.Beta.nuspec
Index: SQLite.NET.2012.MSBuild.sln
==================================================================
--- SQLite.NET.2012.MSBuild.sln
+++ SQLite.NET.2012.MSBuild.sln
@@ -4,17 +4,14 @@
ProjectSection(SolutionItems) = preProject
data\exclude_bin.txt = data\exclude_bin.txt
data\exclude_src.txt = data\exclude_src.txt
Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk
Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk
- NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform
- NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform
- NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform
- NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1
- NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1
- NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1
- NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1
+ NuGet\shared\Core\build\System.Data.SQLite.Core.targets = NuGet\shared\Core\build\System.Data.SQLite.Core.targets
+ NuGet\shared\Core\content\config.transform = NuGet\shared\Core\content\config.transform
+ NuGet\net40\EF6\content\config.transform = NuGet\net40\EF6\content\config.transform
+ NuGet\net40\EF6\tools\provider.ps1 = NuGet\net40\EF6\tools\provider.ps1
NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec
NuGet\SQLite.Core.Beta.nuspec = NuGet\SQLite.Core.Beta.nuspec
NuGet\SQLite.Core.Test.nuspec = NuGet\SQLite.Core.Test.nuspec
NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec
NuGet\SQLite.Core.MSIL.Beta.nuspec = NuGet\SQLite.Core.MSIL.Beta.nuspec
Index: SQLite.NET.2012.sln
==================================================================
--- SQLite.NET.2012.sln
+++ SQLite.NET.2012.sln
@@ -4,17 +4,14 @@
ProjectSection(SolutionItems) = preProject
data\exclude_bin.txt = data\exclude_bin.txt
data\exclude_src.txt = data\exclude_src.txt
Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk
Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk
- NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform
- NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform
- NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform
- NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1
- NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1
- NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1
- NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1
+ NuGet\shared\Core\build\System.Data.SQLite.Core.targets = NuGet\shared\Core\build\System.Data.SQLite.Core.targets
+ NuGet\shared\Core\content\config.transform = NuGet\shared\Core\content\config.transform
+ NuGet\net40\EF6\content\config.transform = NuGet\net40\EF6\content\config.transform
+ NuGet\net40\EF6\tools\provider.ps1 = NuGet\net40\EF6\tools\provider.ps1
NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec
NuGet\SQLite.Core.Beta.nuspec = NuGet\SQLite.Core.Beta.nuspec
NuGet\SQLite.Core.Test.nuspec = NuGet\SQLite.Core.Test.nuspec
NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec
NuGet\SQLite.Core.MSIL.Beta.nuspec = NuGet\SQLite.Core.MSIL.Beta.nuspec
Index: SQLite.NET.2013.MSBuild.sln
==================================================================
--- SQLite.NET.2013.MSBuild.sln
+++ SQLite.NET.2013.MSBuild.sln
@@ -4,17 +4,14 @@
ProjectSection(SolutionItems) = preProject
data\exclude_bin.txt = data\exclude_bin.txt
data\exclude_src.txt = data\exclude_src.txt
Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk
Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk
- NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform
- NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform
- NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform
- NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1
- NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1
- NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1
- NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1
+ NuGet\shared\Core\build\System.Data.SQLite.Core.targets = NuGet\shared\Core\build\System.Data.SQLite.Core.targets
+ NuGet\shared\Core\content\config.transform = NuGet\shared\Core\content\config.transform
+ NuGet\net40\EF6\content\config.transform = NuGet\net40\EF6\content\config.transform
+ NuGet\net40\EF6\tools\provider.ps1 = NuGet\net40\EF6\tools\provider.ps1
NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec
NuGet\SQLite.Core.Beta.nuspec = NuGet\SQLite.Core.Beta.nuspec
NuGet\SQLite.Core.Test.nuspec = NuGet\SQLite.Core.Test.nuspec
NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec
NuGet\SQLite.Core.MSIL.Beta.nuspec = NuGet\SQLite.Core.MSIL.Beta.nuspec
Index: SQLite.NET.2013.sln
==================================================================
--- SQLite.NET.2013.sln
+++ SQLite.NET.2013.sln
@@ -4,17 +4,14 @@
ProjectSection(SolutionItems) = preProject
data\exclude_bin.txt = data\exclude_bin.txt
data\exclude_src.txt = data\exclude_src.txt
Keys\System.Data.SQLite.CF.snk = Keys\System.Data.SQLite.CF.snk
Keys\System.Data.SQLite.snk = Keys\System.Data.SQLite.snk
- NuGet\net20\Core\config.transform = NuGet\net20\Core\config.transform
- NuGet\net40\Core\config.transform = NuGet\net40\Core\config.transform
- NuGet\net40\EF6\config.transform = NuGet\net40\EF6\config.transform
- NuGet\net20\Core\install.ps1 = NuGet\net20\Core\install.ps1
- NuGet\net40\Core\install.ps1 = NuGet\net40\Core\install.ps1
- NuGet\net40\EF6\install.ps1 = NuGet\net40\EF6\install.ps1
- NuGet\net40\EF6\provider.ps1 = NuGet\net40\EF6\provider.ps1
+ NuGet\shared\Core\build\System.Data.SQLite.Core.targets = NuGet\shared\Core\build\System.Data.SQLite.Core.targets
+ NuGet\shared\Core\content\config.transform = NuGet\shared\Core\content\config.transform
+ NuGet\net40\EF6\content\config.transform = NuGet\net40\EF6\content\config.transform
+ NuGet\net40\EF6\tools\provider.ps1 = NuGet\net40\EF6\tools\provider.ps1
NuGet\SQLite.Core.nuspec = NuGet\SQLite.Core.nuspec
NuGet\SQLite.Core.Beta.nuspec = NuGet\SQLite.Core.Beta.nuspec
NuGet\SQLite.Core.Test.nuspec = NuGet\SQLite.Core.Test.nuspec
NuGet\SQLite.Core.MSIL.nuspec = NuGet\SQLite.Core.MSIL.nuspec
NuGet\SQLite.Core.MSIL.Beta.nuspec = NuGet\SQLite.Core.MSIL.Beta.nuspec
Index: Setup/build_all.bat
==================================================================
--- Setup/build_all.bat
+++ Setup/build_all.bat
@@ -45,11 +45,11 @@
ECHO Could not set common variables.
GOTO errors
)
IF NOT DEFINED BUILD_CONFIGURATIONS (
- SET BUILD_CONFIGURATIONS=Release
+ SET BUILD_CONFIGURATIONS=Debug Release
)
%_VECHO% BuildConfigurations = '%BUILD_CONFIGURATIONS%'
IF NOT DEFINED PLATFORMS (
Index: Setup/data/SQLite.iss
==================================================================
--- Setup/data/SQLite.iss
+++ Setup/data/SQLite.iss
@@ -210,10 +210,14 @@
#if Year == "2010"
Components: Application\EF6; Source: ..\..\Externals\EntityFramework\lib\net40\EntityFramework.dll; DestDir: {app}\bin; Flags: restartreplace uninsrestartdelete
#elif Year == "2012" || Year == "2013"
Components: Application\EF6; Source: ..\..\Externals\EntityFramework\lib\net45\EntityFramework.dll; DestDir: {app}\bin; Flags: restartreplace uninsrestartdelete
#endif
+
+#if Pos("NativeOnly", AppConfiguration) == 0
+Components: Application\EF6; Tasks: gac; Source: ..\..\bin\{#Year}\{#BaseConfiguration}\bin\System.Data.SQLite.EF6.dll; DestDir: {app}\GAC; StrongAssemblyName: "System.Data.SQLite.EF6, Version={#AppVersion}, Culture=neutral, PublicKeyToken={#AppPublicKey}, ProcessorArchitecture=MSIL"; Flags: restartreplace uninsrestartdelete uninsnosharedfileprompt sharedfile gacinstall
+#endif
Components: Application\EF6; Source: ..\..\bin\{#Year}\{#BaseConfiguration}\bin\System.Data.SQLite.EF6.dll; DestDir: {app}\bin; Flags: restartreplace uninsrestartdelete
Components: Application\EF6 and Application\Symbols; Source: ..\..\bin\{#Year}\{#BaseConfiguration}\bin\System.Data.SQLite.EF6.pdb; DestDir: {app}\bin; Flags: restartreplace uninsrestartdelete
#endif
Index: Setup/data/verify.lst
==================================================================
--- Setup/data/verify.lst
+++ Setup/data/verify.lst
@@ -154,22 +154,22 @@
Externals/Eagle/lib/Test1.0/
Keys/
Keys/System.Data.SQLite.CF.snk
Keys/System.Data.SQLite.snk
NuGet/
- NuGet/net20/
- NuGet/net20/Core/
- NuGet/net20/Core/config.transform
- NuGet/net20/Core/install.ps1
+ NuGet/shared/
+ NuGet/shared/Core/
+ NuGet/shared/Core/build/
+ NuGet/shared/Core/build/System.Data.SQLite.Core.targets
+ NuGet/shared/Core/content/
+ NuGet/shared/Core/content/config.transform
NuGet/net40/
- NuGet/net40/Core/
- NuGet/net40/Core/config.transform
- NuGet/net40/Core/install.ps1
NuGet/net40/EF6/
- NuGet/net40/EF6/config.transform
- NuGet/net40/EF6/install.ps1
- NuGet/net40/EF6/provider.ps1
+ NuGet/net40/EF6/content/
+ NuGet/net40/EF6/content/config.transform
+ NuGet/net40/EF6/tools/
+ NuGet/net40/EF6/tools/provider.ps1
NuGet/SQLite.Beta.nuspec
NuGet/SQLite.Core.nuspec
NuGet/SQLite.Core.Beta.nuspec
NuGet/SQLite.Core.MSIL.nuspec
NuGet/SQLite.Core.MSIL.Beta.nuspec
Index: Setup/deployAndTestCe200x.eagle
==================================================================
--- Setup/deployAndTestCe200x.eagle
+++ Setup/deployAndTestCe200x.eagle
@@ -348,10 +348,17 @@
# (i.e. no user interaction is required) and capture the exit code.
# The exit code will be zero upon success (i.e. all tests passed) or
# non-zero otherwise.
#
set testFileName [file nativename [file join $device_directory testce.exe]]
+
+ #
+ # NOTE: The first (and only) argument passed to "testce.exe" on the device
+ # is the auto-close flag. When non-zero, it will close automatically
+ # upon completion. Setting this to zero is sometimes useful in order
+ # to more carefully examine the detailed results.
+ #
set exitCode [startRemoteProcess $device $testFileName true]
#
# NOTE: Is the target device actually an emulator running on this system?
#
Index: Setup/test.bat
==================================================================
--- Setup/test.bat
+++ Setup/test.bat
@@ -51,20 +51,20 @@
)
)
%_VECHO% PreArgs = '%PREARGS%'
-IF NOT DEFINED TESTFILE (
+IF NOT DEFINED TEST_FILE (
%_AECHO% No test file specified, using default...
- SET TESTFILE=Tests\empty.eagle
+ SET TEST_FILE=Tests\empty.eagle
)
-%_VECHO% TestFile = '%TESTFILE%'
+%_VECHO% TestFile = '%TEST_FILE%'
IF NOT DEFINED POSTARGS (
%_AECHO% No post-arguments specified, using default...
- SET POSTARGS=-file "%TESTFILE%"
+ SET POSTARGS=-file "%TEST_FILE%"
)
%_VECHO% PostArgs = '%POSTARGS%'
IF NOT DEFINED 32BITONLY (
Index: Setup/test_all.bat
==================================================================
--- Setup/test_all.bat
+++ Setup/test_all.bat
@@ -93,16 +93,18 @@
IF NOT DEFINED YEARS (
SET YEARS=2008
)
%_VECHO% Years = '%YEARS%'
+%_VECHO% PreArgs = '%PREARGS%'
IF NOT DEFINED TEST_FILE (
SET TEST_FILE=Tests\all.eagle
)
%_VECHO% TestFile = '%TEST_FILE%'
+%_VECHO% PostArgs = '%POSTARGS%'
IF NOT DEFINED 32BITONLY (
SET EAGLESHELL=EagleShell.exe
) ELSE (
SET EAGLESHELL=EagleShell32.exe
@@ -139,11 +141,11 @@
GOTO errors
)
)
IF NOT DEFINED NOMANAGEDONLY (
- %__ECHO% "Externals\Eagle\bin\%EAGLESHELL%" -anyInitialize "set test_year {%%Y}; set test_configuration {%%C}" -file "%TEST_FILE%"
+ %__ECHO% "Externals\Eagle\bin\%EAGLESHELL%" %PREARGS% -anyInitialize "set test_year {%%Y}; set test_configuration {%%C}" -file "%TEST_FILE%" %POSTARGS%
IF ERRORLEVEL 1 (
ECHO Testing of "%%Y/%%C" managed-only assembly failed.
GOTO errors
)
@@ -220,11 +222,11 @@
ECHO Failed to copy "bin\%%Y\%%C\bin\Installer.*" to "bin\%%Y\%PLATFORM%\%%C".
GOTO errors
)
)
- %__ECHO% "Externals\Eagle\bin\%EAGLESHELL%" -preInitialize "set test_year {%%Y}; set test_configuration {%%C}" -initialize -runtimeOption native -file "%TEST_FILE%"
+ %__ECHO% "Externals\Eagle\bin\%EAGLESHELL%" %PREARGS% -preInitialize "set test_year {%%Y}; set test_configuration {%%C}" -initialize -runtimeOption native -file "%TEST_FILE%" %POSTARGS%
IF ERRORLEVEL 1 (
ECHO Testing of "%%Y/%%C" mixed-mode assembly failed.
GOTO errors
)
Index: System.Data.SQLite/SQLiteBase.cs
==================================================================
--- System.Data.SQLite/SQLiteBase.cs
+++ System.Data.SQLite/SQLiteBase.cs
@@ -1083,10 +1083,23 @@
/// ,
/// or types.
///
DetectStringType = 0x4000000,
+ ///
+ /// Skip querying runtime configuration settings for use by the
+ /// class, including the default
+ /// value and default database type name.
+ /// NOTE: If the
+ /// and/or
+ /// properties are not set explicitly nor set via their connection
+ /// string properties and repeated calls to determine these runtime
+ /// configuration settings are seen to be a problem, this flag
+ /// should be set.
+ ///
+ NoConvertSettings = 0x8000000,
+
///
/// When binding parameter values or 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
@@ -325,10 +325,17 @@
///
///
public sealed partial class SQLiteConnection : DbConnection, ICloneable
{
#region Private Constants
+ ///
+ /// The "invalid value" for the enumeration used
+ /// by the property. This constant is shared
+ /// by this class and the SQLiteConnectionStringBuilder class.
+ ///
+ internal const DbType BadDbType = (DbType)(-1);
+
///
/// The default "stub" (i.e. placeholder) base schema name to use when
/// returning column schema information. Used as the initial value of
/// the BaseSchemaName property. This should start with "sqlite_*"
/// because those names are reserved for use by SQLite (i.e. they cannot
@@ -477,10 +484,17 @@
/// enumeration for a list of
/// possible values.
///
private SQLiteConnectionFlags _flags;
+ ///
+ /// The cached values for all settings that have been fetched on behalf
+ /// of this connection. This cache may be cleared by calling the
+ /// method.
+ ///
+ private Dictionary _cachedSettings;
+
///
/// The default databse type for this connection. This value will only
/// be used if the
/// flag is set.
///
@@ -628,10 +642,13 @@
{
UnsafeNativeMethods.sqlite3_log(
SQLiteErrorCode.Ok, SQLiteConvert.ToUTF8("logging initialized."));
}
#endif
+
+ _cachedSettings = new Dictionary(
+ new TypeNameStringComparer());
_typeNames = new SQLiteDbTypeMap();
_parseViaFramework = parseViaFramework;
_flags = SQLiteConnectionFlags.Default;
_defaultDbType = null;
@@ -911,10 +928,93 @@
if (backup != null)
sqliteBase.FinishBackup(backup); /* throw */
}
}
#endregion
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ #region Per-Connection Settings
+ ///
+ /// Clears the per-connection cached settings.
+ ///
+ ///
+ /// The total number of per-connection settings cleared.
+ ///
+ public int ClearCachedSettings()
+ {
+ CheckDisposed();
+
+ int result = -1; /* NO SETTINGS */
+
+ if (_cachedSettings != null)
+ {
+ result = _cachedSettings.Count;
+ _cachedSettings.Clear();
+ }
+
+ return result;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Queries and returns the value of the specified setting, using the
+ /// cached setting names and values for this connection, when available.
+ ///
+ ///
+ /// The name of the setting.
+ ///
+ ///
+ /// The value to be returned if the setting has not been set explicitly
+ /// or cannot be determined.
+ ///
+ ///
+ /// The value of the cached setting is stored here if found; otherwise,
+ /// the value of is stored here.
+ ///
+ ///
+ /// Non-zero if the cached setting was found; otherwise, zero.
+ ///
+ internal bool TryGetCachedSetting(
+ string name, /* in */
+ string @default, /* in */
+ out object value /* out */
+ )
+ {
+ if ((name == null) || (_cachedSettings == null))
+ {
+ value = @default;
+ return false;
+ }
+
+ return _cachedSettings.TryGetValue(name, out value);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Adds or sets the cached setting specified by
+ /// to the value specified by .
+ ///
+ ///
+ /// The name of the cached setting to add or replace.
+ ///
+ ///
+ /// The new value of the cached setting.
+ ///
+ internal void SetCachedSetting(
+ string name, /* in */
+ object value /* in */
+ )
+ {
+ if ((name == null) || (_cachedSettings == null))
+ return;
+
+ _cachedSettings[name] = value;
+ }
+ #endregion
///////////////////////////////////////////////////////////////////////////////////////////////
#region Per-Connection Type Mappings
///
@@ -2284,10 +2384,21 @@
bool noSharedFlags = SQLiteConvert.ToBoolean(FindKey(opts, "NoSharedFlags", DefaultNoSharedFlags.ToString()));
if (!noSharedFlags) { lock (_syncRoot) { _flags |= _sharedFlags; } }
enumValue = TryParseEnum(typeof(DbType), FindKey(opts, "DefaultDbType", null), true);
_defaultDbType = (enumValue is DbType) ? (DbType)enumValue : (DbType?)null;
+
+ //
+ // NOTE: Nullable values types are not supported by the .NET Framework
+ // ADO.NET support components that work with the connection string
+ // builder; therefore, translate the "invalid value" used by the
+ // SQLiteConnectionStringBuilder.DefaultDbType property to null
+ // here.
+ //
+ if ((_defaultDbType != null) && ((DbType)_defaultDbType == BadDbType))
+ _defaultDbType = null;
+
_defaultTypeName = FindKey(opts, "DefaultTypeName", null);
#if !NET_COMPACT_20 && TRACE_WARNING
bool uri = false;
#endif
Index: System.Data.SQLite/SQLiteConnectionStringBuilder.cs
==================================================================
--- System.Data.SQLite/SQLiteConnectionStringBuilder.cs
+++ System.Data.SQLite/SQLiteConnectionStringBuilder.cs
@@ -608,12 +608,12 @@
///
/// Gets/sets the default database type for the connection.
///
[DisplayName("Default Database Type")]
[Browsable(true)]
- [DefaultValue(null)]
- public DbType? DefaultDbType
+ [DefaultValue(SQLiteConnection.BadDbType)]
+ public DbType DefaultDbType
{
get
{
object value;
@@ -624,11 +624,11 @@
typeof(DbType)).ConvertFrom(value);
else if (value != null)
return (DbType)value;
}
- return null;
+ return SQLiteConnection.BadDbType;
}
set
{
this["defaultdbtype"] = value;
}
Index: System.Data.SQLite/SQLiteConvert.cs
==================================================================
--- System.Data.SQLite/SQLiteConvert.cs
+++ System.Data.SQLite/SQLiteConvert.cs
@@ -1093,22 +1093,51 @@
///
/// Determines the default database type name to be used when a
/// per-connection value is not available.
///
+ ///
+ /// The connection context for type mappings, if any.
+ ///
///
/// The default database type name to use.
///
- private static string GetDefaultTypeName()
+ private static string GetDefaultTypeName(
+ SQLiteConnection connection
+ )
{
- string value = UnsafeNativeMethods.GetSettingValue(
- "Use_SQLiteConvert_DefaultTypeName", null);
+ SQLiteConnectionFlags flags = (connection != null) ?
+ connection.Flags : SQLiteConnectionFlags.None;
- if (value == null)
+ if ((flags & SQLiteConnectionFlags.NoConvertSettings)
+ == SQLiteConnectionFlags.NoConvertSettings)
+ {
return FallbackDefaultTypeName;
+ }
- return value;
+ string name = "Use_SQLiteConvert_DefaultTypeName";
+ object value = null;
+ string @default = null;
+
+ if ((connection == null) ||
+ !connection.TryGetCachedSetting(name, @default, out value))
+ {
+ try
+ {
+ value = UnsafeNativeMethods.GetSettingValue(name, @default);
+
+ if (value == null)
+ value = FallbackDefaultTypeName;
+ }
+ finally
+ {
+ if (connection != null)
+ connection.SetCachedSetting(name, value);
+ }
+ }
+
+ return SettingValueToString(value);
}
#if !NET_COMPACT_20 && TRACE_WARNING
///
/// If applicable, issues a trace log message warning about falling back to
@@ -1209,11 +1238,11 @@
if ((flags & SQLiteConnectionFlags.NoGlobalTypes) == SQLiteConnectionFlags.NoGlobalTypes)
{
if (defaultTypeName != null)
return defaultTypeName;
- defaultTypeName = GetDefaultTypeName();
+ defaultTypeName = GetDefaultTypeName(connection);
#if !NET_COMPACT_20 && TRACE_WARNING
DefaultTypeNameWarning(dbType, flags, defaultTypeName);
#endif
@@ -1232,11 +1261,11 @@
}
if (defaultTypeName != null)
return defaultTypeName;
- defaultTypeName = GetDefaultTypeName();
+ defaultTypeName = GetDefaultTypeName(connection);
#if !NET_COMPACT_20 && TRACE_WARNING
DefaultTypeNameWarning(dbType, flags, defaultTypeName);
#endif
@@ -1431,33 +1460,94 @@
return true;
default:
return false;
}
}
+
+ ///
+ /// Determines and returns the runtime configuration setting string that
+ /// should be used in place of the specified object value.
+ ///
+ ///
+ /// The object value to convert to a string.
+ ///
+ ///
+ /// Either the string to use in place of the object value -OR- null if it
+ /// cannot be determined.
+ ///
+ private static string SettingValueToString(
+ object value
+ )
+ {
+ if (value is string)
+ return (string)value;
+
+ if (value != null)
+ return value.ToString();
+
+ return null;
+ }
///
/// Determines the default value to be used when a
/// per-connection value is not available.
///
+ ///
+ /// The connection context for type mappings, if any.
+ ///
///
/// The default value to use.
///
- private static DbType GetDefaultDbType()
- {
- string value = UnsafeNativeMethods.GetSettingValue(
- "Use_SQLiteConvert_DefaultDbType", null);
-
- if (value == null)
- return FallbackDefaultDbType;
-
- object enumValue = SQLiteConnection.TryParseEnum(
- typeof(DbType), value, true);
-
- if (!(enumValue is DbType))
- return FallbackDefaultDbType;
-
- return (DbType)enumValue;
+ private static DbType GetDefaultDbType(
+ SQLiteConnection connection
+ )
+ {
+ SQLiteConnectionFlags flags = (connection != null) ?
+ connection.Flags : SQLiteConnectionFlags.None;
+
+ if ((flags & SQLiteConnectionFlags.NoConvertSettings)
+ == SQLiteConnectionFlags.NoConvertSettings)
+ {
+ return FallbackDefaultDbType;
+ }
+
+ bool found = false;
+ string name = "Use_SQLiteConvert_DefaultDbType";
+ object value = null;
+ string @default = null;
+
+ if ((connection == null) ||
+ !connection.TryGetCachedSetting(name, @default, out value))
+ {
+ value = UnsafeNativeMethods.GetSettingValue(name, @default);
+
+ if (value == null)
+ value = FallbackDefaultDbType;
+ }
+ else
+ {
+ found = true;
+ }
+
+ try
+ {
+ if (!(value is DbType))
+ {
+ value = SQLiteConnection.TryParseEnum(
+ typeof(DbType), SettingValueToString(value), true);
+
+ if (!(value is DbType))
+ value = FallbackDefaultDbType;
+ }
+
+ return (DbType)value;
+ }
+ finally
+ {
+ if (!found && (connection != null))
+ connection.SetCachedSetting(name, value);
+ }
}
///
/// Determines if the specified textual value appears to be a
/// value.
@@ -1657,11 +1747,11 @@
if ((flags & SQLiteConnectionFlags.NoGlobalTypes) == SQLiteConnectionFlags.NoGlobalTypes)
{
if (defaultDbType != null)
return (DbType)defaultDbType;
- defaultDbType = GetDefaultDbType();
+ defaultDbType = GetDefaultDbType(connection);
#if !NET_COMPACT_20 && TRACE_WARNING
DefaultDbTypeWarning(typeName, flags, defaultDbType);
#endif
@@ -1695,11 +1785,11 @@
}
if (defaultDbType != null)
return (DbType)defaultDbType;
- defaultDbType = GetDefaultDbType();
+ defaultDbType = GetDefaultDbType(connection);
#if !NET_COMPACT_20 && TRACE_WARNING
DefaultDbTypeWarning(typeName, flags, defaultDbType);
#endif
Index: System.Data.SQLite/UnsafeNativeMethods.cs
==================================================================
--- System.Data.SQLite/UnsafeNativeMethods.cs
+++ System.Data.SQLite/UnsafeNativeMethods.cs
@@ -12,15 +12,13 @@
#if !NET_COMPACT_20 && (TRACE_DETECTION || TRACE_SHARED || TRACE_PRELOAD || TRACE_HANDLE)
using System.Diagnostics;
#endif
-#if PRELOAD_NATIVE_LIBRARY
using System.Collections.Generic;
using System.IO;
using System.Reflection;
-#endif
#if !PLATFORM_COMPACTFRAMEWORK && !DEBUG
using System.Security;
#endif
@@ -90,18 +88,17 @@
/// This lock is used to protect the static _SQLiteNativeModuleFileName,
/// _SQLiteNativeModuleHandle, and processorArchitecturePlatforms fields.
///
private static readonly object staticSyncRoot = new object();
-
+#if DEBUG
/////////////////////////////////////////////////////////////////////////
///
/// This dictionary stores the read counts for the runtime configuration
/// settings. This information is only recorded when compiled in the
/// "Debug" build configuration.
///
-#if DEBUG
private static Dictionary settingReadCounts;
#endif
/////////////////////////////////////////////////////////////////////////
///
@@ -273,21 +270,24 @@
/////////////////////////////////////////////////////////////////////
#region Debug Build Only
#if DEBUG
- //
- // NOTE: Update statistics for this setting value.
- //
- if (settingReadCounts != null)
- {
- int count;
-
- if (settingReadCounts.TryGetValue(name, out count))
- settingReadCounts[name] = count + 1;
- else
- settingReadCounts.Add(name, 1);
+ lock (staticSyncRoot)
+ {
+ //
+ // NOTE: Update statistics for this setting value.
+ //
+ if (settingReadCounts != null)
+ {
+ int count;
+
+ if (settingReadCounts.TryGetValue(name, out count))
+ settingReadCounts[name] = count + 1;
+ else
+ settingReadCounts.Add(name, 1);
+ }
}
#endif
#endregion
/////////////////////////////////////////////////////////////////////
Index: Tests/common.eagle
==================================================================
--- Tests/common.eagle
+++ Tests/common.eagle
@@ -1649,11 +1649,11 @@
# skipped.
#
set error null; # IGNORED
set value [object invoke Utility TryParseFlagsEnum "" \
System.Data.SQLite.SQLiteConnectionFlags "" $flags null true \
- error]
+ true error]
#
# NOTE: If the combined flags string could not actually be converted
# to the enumerated type it is the default value, then just use
# it verbatim; otherwise, just return an empty string. In that
Index: Tests/data/Installer_Test_Vs2005.log
==================================================================
--- Tests/data/Installer_Test_Vs2005.log
+++ Tests/data/Installer_Test_Vs2005.log
@@ -60,8 +60,8 @@
Installer.exe: #60: RegistryHelper.CreateSubKey: rootKey = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\8.0\DataProviders\{0ebaab6e-ca80-4b4a-8ddf-cbe6bf058c70}", subKeyName = "SupportedObjects\DataObjectSupport"
Installer.exe: #61: RegistryHelper.CreateSubKey: rootKey = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\8.0\DataProviders\{0ebaab6e-ca80-4b4a-8ddf-cbe6bf058c70}", subKeyName = "SupportedObjects\DataViewSupport"
Installer.exe: #62: RegistryHelper.OpenSubKey: rootKey = "HKEY_LOCAL_MACHINE", subKeyName = "Software${wow64}\Microsoft\VisualStudio\8.0", writable = False
Installer.exe: #63: RegistryHelper.GetValue: key = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\8.0", name = "InstallDir", defaultValue =
Installer.exe: #64: Installer.AddVsDevEnvSetup: fileName = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 8} Common7 IDE devenv.exe]]", arguments = "/setup", workingDirectory = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 8} Common7 IDE]]\", useShellExecute = False, redirectStandardOutput = True, redirectStandardError = True
-Installer.exe: #65: Installer.Main: subKeysCreated = 12, subKeysDeleted = 1, keyValuesSet = 23, keyValuesDeleted = 0
+Installer.exe: #65: Installer.Main: subKeysCreated = 12, subKeysDeleted = 1, keyValuesRead = 5, keyValuesWritten = 23, keyValuesDeleted = 0
Installer.exe: #66: Installer.Main: filesCreated = 1, filesModified = 2, filesDeleted = 0
Installer.exe: #67: Installer.Main: Success.
Index: Tests/data/Installer_Test_Vs2008.log
==================================================================
--- Tests/data/Installer_Test_Vs2008.log
+++ Tests/data/Installer_Test_Vs2008.log
@@ -70,8 +70,8 @@
Installer.exe: #70: RegistryHelper.CreateSubKey: rootKey = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\9.0\DataProviders\{0ebaab6e-ca80-4b4a-8ddf-cbe6bf058c70}", subKeyName = "SupportedObjects\DataObjectSupport"
Installer.exe: #71: RegistryHelper.CreateSubKey: rootKey = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\9.0\DataProviders\{0ebaab6e-ca80-4b4a-8ddf-cbe6bf058c70}", subKeyName = "SupportedObjects\DataViewSupport"
Installer.exe: #72: RegistryHelper.OpenSubKey: rootKey = "HKEY_LOCAL_MACHINE", subKeyName = "Software${wow64}\Microsoft\VisualStudio\9.0", writable = False
Installer.exe: #73: RegistryHelper.GetValue: key = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\9.0", name = "InstallDir", defaultValue =
Installer.exe: #74: Installer.AddVsDevEnvSetup: fileName = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 9.0} Common7 IDE devenv.exe]]", arguments = "/setup", workingDirectory = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 9.0} Common7 IDE]]\", useShellExecute = False, redirectStandardOutput = True, redirectStandardError = True
-Installer.exe: #75: Installer.Main: subKeysCreated = 13, subKeysDeleted = 2, keyValuesSet = 24, keyValuesDeleted = 0
+Installer.exe: #75: Installer.Main: subKeysCreated = 13, subKeysDeleted = 2, keyValuesRead = 6, keyValuesWritten = 24, keyValuesDeleted = 0
Installer.exe: #76: Installer.Main: filesCreated = 1, filesModified = 2, filesDeleted = 0
Installer.exe: #77: Installer.Main: Success.
Index: Tests/data/Installer_Test_Vs2010.log
==================================================================
--- Tests/data/Installer_Test_Vs2010.log
+++ Tests/data/Installer_Test_Vs2010.log
@@ -63,8 +63,8 @@
Installer.exe: #63: RegistryHelper.CreateSubKey: rootKey = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\10.0\DataProviders\{0ebaab6e-ca80-4b4a-8ddf-cbe6bf058c70}", subKeyName = "SupportedObjects\DataObjectSupport"
Installer.exe: #64: RegistryHelper.CreateSubKey: rootKey = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\10.0\DataProviders\{0ebaab6e-ca80-4b4a-8ddf-cbe6bf058c70}", subKeyName = "SupportedObjects\DataViewSupport"
Installer.exe: #65: RegistryHelper.OpenSubKey: rootKey = "HKEY_LOCAL_MACHINE", subKeyName = "Software${wow64}\Microsoft\VisualStudio\10.0", writable = False
Installer.exe: #66: RegistryHelper.GetValue: key = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\10.0", name = "InstallDir", defaultValue =
Installer.exe: #67: Installer.AddVsDevEnvSetup: fileName = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 10.0} Common7 IDE devenv.exe]]", arguments = "/setup", workingDirectory = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 10.0} Common7 IDE]]\", useShellExecute = False, redirectStandardOutput = True, redirectStandardError = True
-Installer.exe: #68: Installer.Main: subKeysCreated = 12, subKeysDeleted = 1, keyValuesSet = 23, keyValuesDeleted = 0
+Installer.exe: #68: Installer.Main: subKeysCreated = 12, subKeysDeleted = 1, keyValuesRead = 5, keyValuesWritten = 23, keyValuesDeleted = 0
Installer.exe: #69: Installer.Main: filesCreated = 1, filesModified = 2, filesDeleted = 0
Installer.exe: #70: Installer.Main: Success.
Index: Tests/data/Installer_Test_Vs2012.log
==================================================================
--- Tests/data/Installer_Test_Vs2012.log
+++ Tests/data/Installer_Test_Vs2012.log
@@ -63,8 +63,8 @@
Installer.exe: #63: RegistryHelper.CreateSubKey: rootKey = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\11.0\DataProviders\{0ebaab6e-ca80-4b4a-8ddf-cbe6bf058c70}", subKeyName = "SupportedObjects\DataObjectSupport"
Installer.exe: #64: RegistryHelper.CreateSubKey: rootKey = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\11.0\DataProviders\{0ebaab6e-ca80-4b4a-8ddf-cbe6bf058c70}", subKeyName = "SupportedObjects\DataViewSupport"
Installer.exe: #65: RegistryHelper.OpenSubKey: rootKey = "HKEY_LOCAL_MACHINE", subKeyName = "Software${wow64}\Microsoft\VisualStudio\11.0", writable = False
Installer.exe: #66: RegistryHelper.GetValue: key = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\11.0", name = "InstallDir", defaultValue =
Installer.exe: #67: Installer.AddVsDevEnvSetup: fileName = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 11.0} Common7 IDE devenv.exe]]", arguments = "/setup", workingDirectory = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 11.0} Common7 IDE]]\", useShellExecute = False, redirectStandardOutput = True, redirectStandardError = True
-Installer.exe: #68: Installer.Main: subKeysCreated = 12, subKeysDeleted = 1, keyValuesSet = 23, keyValuesDeleted = 0
+Installer.exe: #68: Installer.Main: subKeysCreated = 12, subKeysDeleted = 1, keyValuesRead = 5, keyValuesWritten = 23, keyValuesDeleted = 0
Installer.exe: #69: Installer.Main: filesCreated = 1, filesModified = 2, filesDeleted = 0
Installer.exe: #70: Installer.Main: Success.
Index: Tests/data/Installer_Test_Vs2013.log
==================================================================
--- Tests/data/Installer_Test_Vs2013.log
+++ Tests/data/Installer_Test_Vs2013.log
@@ -63,8 +63,8 @@
Installer.exe: #63: RegistryHelper.CreateSubKey: rootKey = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\12.0\DataProviders\{0ebaab6e-ca80-4b4a-8ddf-cbe6bf058c70}", subKeyName = "SupportedObjects\DataObjectSupport"
Installer.exe: #64: RegistryHelper.CreateSubKey: rootKey = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\12.0\DataProviders\{0ebaab6e-ca80-4b4a-8ddf-cbe6bf058c70}", subKeyName = "SupportedObjects\DataViewSupport"
Installer.exe: #65: RegistryHelper.OpenSubKey: rootKey = "HKEY_LOCAL_MACHINE", subKeyName = "Software${wow64}\Microsoft\VisualStudio\12.0", writable = False
Installer.exe: #66: RegistryHelper.GetValue: key = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\12.0", name = "InstallDir", defaultValue =
Installer.exe: #67: Installer.AddVsDevEnvSetup: fileName = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 12.0} Common7 IDE devenv.exe]]", arguments = "/setup", workingDirectory = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 12.0} Common7 IDE]]\", useShellExecute = False, redirectStandardOutput = True, redirectStandardError = True
-Installer.exe: #68: Installer.Main: subKeysCreated = 12, subKeysDeleted = 1, keyValuesSet = 23, keyValuesDeleted = 0
+Installer.exe: #68: Installer.Main: subKeysCreated = 12, subKeysDeleted = 1, keyValuesRead = 5, keyValuesWritten = 23, keyValuesDeleted = 0
Installer.exe: #69: Installer.Main: filesCreated = 1, filesModified = 2, filesDeleted = 0
Installer.exe: #70: Installer.Main: Success.
Index: Tests/data/Uninstaller_Test_Vs2005.log
==================================================================
--- Tests/data/Uninstaller_Test_Vs2005.log
+++ Tests/data/Uninstaller_Test_Vs2005.log
@@ -29,8 +29,8 @@
Installer.exe: #29: RegistryHelper.DeleteSubKeyTree: rootKey = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\8.0\DataProviders", subKeyName = "{0ebaab6e-ca80-4b4a-8ddf-cbe6bf058c70}"
Installer.exe: #30: RegistryHelper.OpenSubKey: rootKey = "HKEY_LOCAL_MACHINE", subKeyName = "Software${wow64}\Microsoft\VisualStudio\8.0", writable = False
Installer.exe: #31: RegistryHelper.GetValue: key = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\8.0", name = "InstallDir", defaultValue =
Installer.exe: #32: Installer.RemoveVsDevEnvSetup: Preparing to run Visual Studio v8.0 'setup' mode to refresh its configuration.
Installer.exe: #33: Installer.AddVsDevEnvSetup: fileName = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 8} Common7 IDE devenv.exe]]", arguments = "/setup", workingDirectory = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 8} Common7 IDE]]\", useShellExecute = False, redirectStandardOutput = True, redirectStandardError = True
-Installer.exe: #34: Installer.Main: subKeysCreated = 0, subKeysDeleted = 5, keyValuesSet = 0, keyValuesDeleted = 1
+Installer.exe: #34: Installer.Main: subKeysCreated = 0, subKeysDeleted = 5, keyValuesRead = 5, keyValuesWritten = 0, keyValuesDeleted = 1
Installer.exe: #35: Installer.Main: filesCreated = 1, filesModified = 1, filesDeleted = 0
Installer.exe: #36: Installer.Main: Success.
Index: Tests/data/Uninstaller_Test_Vs2008.log
==================================================================
--- Tests/data/Uninstaller_Test_Vs2008.log
+++ Tests/data/Uninstaller_Test_Vs2008.log
@@ -36,8 +36,8 @@
Installer.exe: #36: RegistryHelper.DeleteSubKeyTree: rootKey = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\9.0\DataProviders", subKeyName = "{0ebaab6e-ca80-4b4a-8ddf-cbe6bf058c70}"
Installer.exe: #37: RegistryHelper.OpenSubKey: rootKey = "HKEY_LOCAL_MACHINE", subKeyName = "Software${wow64}\Microsoft\VisualStudio\9.0", writable = False
Installer.exe: #38: RegistryHelper.GetValue: key = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\9.0", name = "InstallDir", defaultValue =
Installer.exe: #39: Installer.RemoveVsDevEnvSetup: Preparing to run Visual Studio v9.0 'setup' mode to refresh its configuration.
Installer.exe: #40: Installer.AddVsDevEnvSetup: fileName = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 9.0} Common7 IDE devenv.exe]]", arguments = "/setup", workingDirectory = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 9.0} Common7 IDE]]\", useShellExecute = False, redirectStandardOutput = True, redirectStandardError = True
-Installer.exe: #41: Installer.Main: subKeysCreated = 0, subKeysDeleted = 6, keyValuesSet = 0, keyValuesDeleted = 1
+Installer.exe: #41: Installer.Main: subKeysCreated = 0, subKeysDeleted = 6, keyValuesRead = 6, keyValuesWritten = 0, keyValuesDeleted = 1
Installer.exe: #42: Installer.Main: filesCreated = 1, filesModified = 1, filesDeleted = 0
Installer.exe: #43: Installer.Main: Success.
Index: Tests/data/Uninstaller_Test_Vs2010.log
==================================================================
--- Tests/data/Uninstaller_Test_Vs2010.log
+++ Tests/data/Uninstaller_Test_Vs2010.log
@@ -32,8 +32,8 @@
Installer.exe: #32: RegistryHelper.DeleteSubKeyTree: rootKey = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\10.0\DataProviders", subKeyName = "{0ebaab6e-ca80-4b4a-8ddf-cbe6bf058c70}"
Installer.exe: #33: RegistryHelper.OpenSubKey: rootKey = "HKEY_LOCAL_MACHINE", subKeyName = "Software${wow64}\Microsoft\VisualStudio\10.0", writable = False
Installer.exe: #34: RegistryHelper.GetValue: key = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\10.0", name = "InstallDir", defaultValue =
Installer.exe: #35: Installer.RemoveVsDevEnvSetup: Preparing to run Visual Studio v10.0 'setup' mode to refresh its configuration.
Installer.exe: #36: Installer.AddVsDevEnvSetup: fileName = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 10.0} Common7 IDE devenv.exe]]", arguments = "/setup", workingDirectory = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 10.0} Common7 IDE]]\", useShellExecute = False, redirectStandardOutput = True, redirectStandardError = True
-Installer.exe: #37: Installer.Main: subKeysCreated = 0, subKeysDeleted = 5, keyValuesSet = 0, keyValuesDeleted = 1
+Installer.exe: #37: Installer.Main: subKeysCreated = 0, subKeysDeleted = 5, keyValuesRead = 5, keyValuesWritten = 0, keyValuesDeleted = 1
Installer.exe: #38: Installer.Main: filesCreated = 1, filesModified = 1, filesDeleted = 0
Installer.exe: #39: Installer.Main: Success.
Index: Tests/data/Uninstaller_Test_Vs2012.log
==================================================================
--- Tests/data/Uninstaller_Test_Vs2012.log
+++ Tests/data/Uninstaller_Test_Vs2012.log
@@ -32,8 +32,8 @@
Installer.exe: #32: RegistryHelper.DeleteSubKeyTree: rootKey = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\11.0\DataProviders", subKeyName = "{0ebaab6e-ca80-4b4a-8ddf-cbe6bf058c70}"
Installer.exe: #33: RegistryHelper.OpenSubKey: rootKey = "HKEY_LOCAL_MACHINE", subKeyName = "Software${wow64}\Microsoft\VisualStudio\11.0", writable = False
Installer.exe: #34: RegistryHelper.GetValue: key = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\11.0", name = "InstallDir", defaultValue =
Installer.exe: #35: Installer.RemoveVsDevEnvSetup: Preparing to run Visual Studio v11.0 'setup' mode to refresh its configuration.
Installer.exe: #36: Installer.AddVsDevEnvSetup: fileName = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 11.0} Common7 IDE devenv.exe]]", arguments = "/setup", workingDirectory = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 11.0} Common7 IDE]]\", useShellExecute = False, redirectStandardOutput = True, redirectStandardError = True
-Installer.exe: #37: Installer.Main: subKeysCreated = 0, subKeysDeleted = 5, keyValuesSet = 0, keyValuesDeleted = 1
+Installer.exe: #37: Installer.Main: subKeysCreated = 0, subKeysDeleted = 5, keyValuesRead = 5, keyValuesWritten = 0, keyValuesDeleted = 1
Installer.exe: #38: Installer.Main: filesCreated = 1, filesModified = 1, filesDeleted = 0
Installer.exe: #39: Installer.Main: Success.
Index: Tests/data/Uninstaller_Test_Vs2013.log
==================================================================
--- Tests/data/Uninstaller_Test_Vs2013.log
+++ Tests/data/Uninstaller_Test_Vs2013.log
@@ -32,8 +32,8 @@
Installer.exe: #32: RegistryHelper.DeleteSubKeyTree: rootKey = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\12.0\DataProviders", subKeyName = "{0ebaab6e-ca80-4b4a-8ddf-cbe6bf058c70}"
Installer.exe: #33: RegistryHelper.OpenSubKey: rootKey = "HKEY_LOCAL_MACHINE", subKeyName = "Software${wow64}\Microsoft\VisualStudio\12.0", writable = False
Installer.exe: #34: RegistryHelper.GetValue: key = "HKEY_LOCAL_MACHINE\Software${wow64}\Microsoft\VisualStudio\12.0", name = "InstallDir", defaultValue =
Installer.exe: #35: Installer.RemoveVsDevEnvSetup: Preparing to run Visual Studio v12.0 'setup' mode to refresh its configuration.
Installer.exe: #36: Installer.AddVsDevEnvSetup: fileName = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 12.0} Common7 IDE devenv.exe]]", arguments = "/setup", workingDirectory = "[file nativename [file join [expr {$is64 ? ${::env(ProgramFiles(x86))} : $::env(ProgramFiles)}] {Microsoft Visual Studio 12.0} Common7 IDE]]\", useShellExecute = False, redirectStandardOutput = True, redirectStandardError = True
-Installer.exe: #37: Installer.Main: subKeysCreated = 0, subKeysDeleted = 5, keyValuesSet = 0, keyValuesDeleted = 1
+Installer.exe: #37: Installer.Main: subKeysCreated = 0, subKeysDeleted = 5, keyValuesRead = 5, keyValuesWritten = 0, keyValuesDeleted = 1
Installer.exe: #38: Installer.Main: filesCreated = 1, filesModified = 1, filesDeleted = 0
Installer.exe: #39: Installer.Main: Success.
Index: Tests/speed.eagle
==================================================================
--- Tests/speed.eagle
+++ Tests/speed.eagle
@@ -70,13 +70,18 @@
sql execute $db "INSERT INTO t3 (y) VALUES(NULL);"
sql execute $db "INSERT INTO t3 (y) VALUES('1');"
sql execute $db "INSERT INTO t3 (y) VALUES('1.1');"
+ set char [expr {int(rand() * 0x7F) + 1}]; # NOTE: Skip NUL.
+
+ tputs $test_channel [appendArgs \
+ "---- using random character 0x" [format %X $char] ...\n]
+
sql execute $db [appendArgs \
"INSERT INTO t3 (y) VALUES('" [string map [list ' ''] [string \
- repeat [format %c [expr {int(rand() * 0x80)}]] 1048576]] "');"]
+ repeat [format %c $char] 1048576]] "');"]
sql execute $db "INSERT INTO t4 (z) VALUES(NULL);"
sql execute $db "INSERT INTO t4 (z) VALUES(X'01');"
sql execute $db "INSERT INTO t4 (z) VALUES(X'0123456789');"
sql execute $db "INSERT INTO t4 (z) VALUES(randomblob(1048576));"
@@ -105,11 +110,11 @@
set result
} -cleanup {
cleanupDb $fileName
- unset -nocomplain time sql result db fileName
+ unset -nocomplain time sql result char db fileName
} -time true -constraints {eagle monoBug28 command.sql compile.DATA SQLite\
System.Data.SQLite} -result {{-9223372036854775808 0 9223372036854775807}\
{-Infinity 0 Infinity} {1 1.1 1048576} {1 {1 35 69 103 137} 1048576}}}
###############################################################################
@@ -134,13 +139,18 @@
sql execute $db "INSERT INTO t3 (y) VALUES(NULL);"
sql execute $db "INSERT INTO t3 (y) VALUES('1');"
sql execute $db "INSERT INTO t3 (y) VALUES('1.1');"
+ set char [expr {int(rand() * 0x7F) + 1}]; # NOTE: Skip NUL.
+
+ tputs $test_channel [appendArgs \
+ "---- using random character 0x" [format %X $char] ...\n]
+
sql execute $db [appendArgs \
"INSERT INTO t3 (y) VALUES('" [string map [list ' ''] [string \
- repeat [format %c [expr {int(rand() * 0x80)}]] 1048576]] "');"]
+ repeat [format %c $char] 1048576]] "');"]
sql execute $db "INSERT INTO t4 (z) VALUES(NULL);"
sql execute $db "INSERT INTO t4 (z) VALUES(X'01');"
sql execute $db "INSERT INTO t4 (z) VALUES(X'0123456789');"
sql execute $db "INSERT INTO t4 (z) VALUES(randomblob(1048576));"
@@ -163,11 +173,11 @@
set result
} -cleanup {
cleanupDb $fileName
- unset -nocomplain time sql table column result db fileName
+ unset -nocomplain time sql table column result char db fileName
} -time true -constraints {eagle monoBug28 command.sql compile.DATA SQLite\
System.Data.SQLite} -result {3 3 3 3}}
###############################################################################
Index: Tests/tkt-58ed318f2f.eagle
==================================================================
--- Tests/tkt-58ed318f2f.eagle
+++ Tests/tkt-58ed318f2f.eagle
@@ -18,14 +18,10 @@
package require System.Data.SQLite.Test
runSQLiteTestPrologue
###############################################################################
-reportSQLiteResources $test_channel true
-
-###############################################################################
-
proc getSettingReadCount { name } {
if {[haveConstraint buildConfiguration.Debug] && [catch {
object invoke -flags +NonPublic -alias \
System.Data.SQLite.UnsafeNativeMethods settingReadCounts
} settingReadCounts] == 0} then {
@@ -43,10 +39,14 @@
return -1
}
###############################################################################
+reportSQLiteResources $test_channel true
+
+###############################################################################
+
runTest {test tkt-58ed318f2f-1.1 {standard GetDefaultDbType usage} -setup {
setupDb [set fileName tkt-58ed318f2f-1.1.db]
} -body {
sql execute $db {
CREATE TABLE t1(x, y);
@@ -53,11 +53,12 @@
INSERT INTO t1 (x, y) VALUES(0, 1);
INSERT INTO t1 (x, y) VALUES('0', '1');
}
sql execute -execute reader -format list $db "SELECT x, y FROM t1;"
- expr {[getSettingReadCount Use_SQLiteConvert_DefaultDbType] == 2}
+
+ expr {[getSettingReadCount Use_SQLiteConvert_DefaultDbType] == 1}
} -cleanup {
cleanupDb $fileName
unset -nocomplain db fileName
} -constraints \
@@ -78,11 +79,12 @@
INSERT INTO t1 (x, y) VALUES(0, 1);
INSERT INTO t1 (x, y) VALUES('0', '1');
}
sql execute -execute reader -format list $db "SELECT x, y FROM t1;"
- expr {[getSettingReadCount Use_SQLiteConvert_DefaultDbType] == 2}
+
+ expr {[getSettingReadCount Use_SQLiteConvert_DefaultDbType] == 1}
} -cleanup {
cleanupDb $fileName
unset -nocomplain db fileName
} -constraints \
@@ -104,10 +106,11 @@
INSERT INTO t1 (x, y) VALUES(0, 1);
INSERT INTO t1 (x, y) VALUES('0', '1');
}
sql execute -execute reader -format list $db "SELECT x, y FROM t1;"
+
expr {[getSettingReadCount Use_SQLiteConvert_DefaultDbType] == -1}
} -cleanup {
cleanupDb $fileName
unset -nocomplain db fileName
@@ -130,15 +133,261 @@
INSERT INTO t1 (x, y) VALUES(0, 1);
INSERT INTO t1 (x, y) VALUES('0', '1');
}
sql execute -execute reader -format list $db "SELECT x, y FROM t1;"
+
+ expr {[getSettingReadCount Use_SQLiteConvert_DefaultDbType] == -1}
+} -cleanup {
+ cleanupDb $fileName
+
+ unset -nocomplain db fileName
+} -constraints \
+{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\
+buildConfiguration.Debug} -result {True}}
+
+###############################################################################
+
+reportSQLiteResources $test_channel true
+
+###############################################################################
+
+runTest {test tkt-58ed318f2f-1.5 {standard GetDefaultTypeName usage} -setup {
+ setupDb [set fileName tkt-58ed318f2f-1.5.db]
+} -body {
+ set connection [getDbConnection]
+
+ sql execute $db {
+ CREATE TABLE t1(x, y);
+ INSERT INTO t1 (x, y) VALUES(0, 1);
+ INSERT INTO t1 (x, y) VALUES('0', '1');
+ }
+
+ set columns [$connection GetSchema COLUMNS]
+
+ expr {[getSettingReadCount Use_SQLiteConvert_DefaultTypeName] == 1}
+} -cleanup {
+ cleanupDb $fileName
+
+ freeDbConnection
+
+ unset -nocomplain columns connection db fileName
+} -constraints \
+{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\
+buildConfiguration.Debug} -result {True}}
+
+###############################################################################
+
+reportSQLiteResources $test_channel true
+
+###############################################################################
+
+runTest {test tkt-58ed318f2f-1.6 {no property GetDefaultTypeName usage} -setup {
+ setupDb [set fileName tkt-58ed318f2f-1.6.db] "" "" "" UseConnectionTypes
+} -body {
+ set connection [getDbConnection]
+
+ sql execute $db {
+ CREATE TABLE t1(x, y);
+ INSERT INTO t1 (x, y) VALUES(0, 1);
+ INSERT INTO t1 (x, y) VALUES('0', '1');
+ }
+
+ set columns [$connection GetSchema COLUMNS]
+
+ expr {[getSettingReadCount Use_SQLiteConvert_DefaultTypeName] == 1}
+} -cleanup {
+ cleanupDb $fileName
+
+ freeDbConnection
+
+ unset -nocomplain columns connection db fileName
+} -constraints \
+{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\
+buildConfiguration.Debug} -result {True}}
+
+###############################################################################
+
+reportSQLiteResources $test_channel true
+
+###############################################################################
+
+runTest {test tkt-58ed318f2f-1.7 {no flag GetDefaultTypeName usage} -setup {
+ setupDb [set fileName tkt-58ed318f2f-1.7.db] "" "" "" "" \
+ "DefaultDbType=String;"
+} -body {
+ set connection [getDbConnection]
+
+ sql execute $db {
+ CREATE TABLE t1(x, y);
+ INSERT INTO t1 (x, y) VALUES(0, 1);
+ INSERT INTO t1 (x, y) VALUES('0', '1');
+ }
+
+ set columns [$connection GetSchema COLUMNS]
+
+ expr {[getSettingReadCount Use_SQLiteConvert_DefaultTypeName] == -1}
+} -cleanup {
+ cleanupDb $fileName
+
+ freeDbConnection
+
+ unset -nocomplain columns connection db fileName
+} -constraints \
+{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\
+buildConfiguration.Debug} -result {True}}
+
+###############################################################################
+
+reportSQLiteResources $test_channel true
+
+###############################################################################
+
+runTest {test tkt-58ed318f2f-1.8 {zero GetDefaultTypeName usage} -setup {
+ setupDb [set fileName tkt-58ed318f2f-1.8.db] "" "" "" UseConnectionTypes \
+ "DefaultTypeName=TEXT;"
+} -body {
+ set connection [getDbConnection]
+
+ sql execute $db {
+ CREATE TABLE t1(x, y);
+ INSERT INTO t1 (x, y) VALUES(0, 1);
+ INSERT INTO t1 (x, y) VALUES('0', '1');
+ }
+
+ set columns [$connection GetSchema COLUMNS]
+
+ expr {[getSettingReadCount Use_SQLiteConvert_DefaultTypeName] == -1}
+} -cleanup {
+ cleanupDb $fileName
+
+ freeDbConnection
+
+ unset -nocomplain columns connection db fileName
+} -constraints \
+{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\
+buildConfiguration.Debug} -result {True}}
+
+###############################################################################
+
+reportSQLiteResources $test_channel true
+
+###############################################################################
+
+runTest {test tkt-58ed318f2f-1.9 {zero DefaultDbType settings read} -setup {
+ setupDb [set fileName tkt-58ed318f2f-1.9.db] "" "" "" NoConvertSettings
+} -body {
+ sql execute $db {
+ CREATE TABLE t1(x, y);
+ INSERT INTO t1 (x, y) VALUES(0, 1);
+ INSERT INTO t1 (x, y) VALUES('0', '1');
+ }
+
+ sql execute -execute reader -format list $db "SELECT x, y FROM t1;"
+
expr {[getSettingReadCount Use_SQLiteConvert_DefaultDbType] == -1}
} -cleanup {
cleanupDb $fileName
unset -nocomplain db fileName
+} -constraints \
+{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\
+buildConfiguration.Debug} -result {True}}
+
+###############################################################################
+
+reportSQLiteResources $test_channel true
+
+###############################################################################
+
+runTest {test tkt-58ed318f2f-1.10 {zero DefaultTypeName settings read} -setup {
+ setupDb [set fileName tkt-58ed318f2f-1.10.db] "" "" "" NoConvertSettings
+} -body {
+ set connection [getDbConnection]
+
+ sql execute $db {
+ CREATE TABLE t1(x, y);
+ INSERT INTO t1 (x, y) VALUES(0, 1);
+ INSERT INTO t1 (x, y) VALUES('0', '1');
+ }
+
+ set columns [$connection GetSchema COLUMNS]
+
+ expr {[getSettingReadCount Use_SQLiteConvert_DefaultTypeName] == -1}
+} -cleanup {
+ cleanupDb $fileName
+
+ freeDbConnection
+
+ unset -nocomplain columns connection db fileName
+} -constraints \
+{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\
+buildConfiguration.Debug} -result {True}}
+
+###############################################################################
+
+reportSQLiteResources $test_channel true
+
+###############################################################################
+
+runTest {test tkt-58ed318f2f-1.11 {normal SQLiteConvert settings usage} -setup {
+ setupDb [set fileName tkt-58ed318f2f-1.11.db]
+} -body {
+ set connection [getDbConnection]
+
+ sql execute $db {
+ CREATE TABLE t1(x, y);
+ INSERT INTO t1 (x, y) VALUES(0, 1);
+ INSERT INTO t1 (x, y) VALUES('0', '1');
+ }
+
+ sql execute -execute reader -format list $db "SELECT x, y FROM t1;"
+ set columns [$connection GetSchema COLUMNS]
+
+ #
+ # TODO: These counts may need to be updated in future versions.
+ #
+ expr {[getSettingReadCount Use_SQLiteConvert_DefaultDbType] == 1 && \
+ [getSettingReadCount Use_SQLiteConvert_DefaultTypeName] == 1}
+} -cleanup {
+ cleanupDb $fileName
+
+ freeDbConnection
+
+ unset -nocomplain columns connection db fileName
+} -constraints \
+{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\
+buildConfiguration.Debug} -result {True}}
+
+###############################################################################
+
+reportSQLiteResources $test_channel true
+
+###############################################################################
+
+runTest {test tkt-58ed318f2f-1.12 {zero SQLiteConvert settings usage} -setup {
+ setupDb [set fileName tkt-58ed318f2f-1.12.db] "" "" "" NoConvertSettings
+} -body {
+ set connection [getDbConnection]
+
+ sql execute $db {
+ CREATE TABLE t1(x, y);
+ INSERT INTO t1 (x, y) VALUES(0, 1);
+ INSERT INTO t1 (x, y) VALUES('0', '1');
+ }
+
+ sql execute -execute reader -format list $db "SELECT x, y FROM t1;"
+ set columns [$connection GetSchema COLUMNS]
+
+ expr {[getSettingReadCount Use_SQLiteConvert_DefaultDbType] == -1 && \
+ [getSettingReadCount Use_SQLiteConvert_DefaultTypeName] == -1}
+} -cleanup {
+ cleanupDb $fileName
+
+ freeDbConnection
+
+ unset -nocomplain columns connection db fileName
} -constraints \
{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\
buildConfiguration.Debug} -result {True}}
###############################################################################
Index: Tests/version.eagle
==================================================================
--- Tests/version.eagle
+++ Tests/version.eagle
@@ -347,42 +347,42 @@
lappend patterns \
[appendArgs [string map [list . \\.] $version(nuget)] \
] \
[appendArgs " targetFramework=\"net20\".*? " \
- "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \
- "\" "] \
+ "id=\"System\\.Data\\.SQLite\\.Core\\.Beta\" version=\"" \
+ $version(nuget) "\" "] \
[appendArgs " targetFramework=\"net40\".*? " \
- "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \
- "\" "] \
+ "id=\"System\\.Data\\.SQLite\\.Core\\.Beta\" version=\"" \
+ $version(nuget) "\" "] \
[appendArgs " targetFramework=\"net45\".*? " \
- "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \
- "\" "] \
+ "id=\"System\\.Data\\.SQLite\\.Core\\.Beta\" version=\"" \
+ $version(nuget) "\" "] \
[appendArgs " targetFramework=\"net451\".*? " \
- "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \
- "\" "] \
+ "id=\"System\\.Data\\.SQLite\\.Core\\.Beta\" version=\"" \
+ $version(nuget) "\" "] \
[appendArgs " targetFramework=\"net20\".*? " \
- "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \
- "\" "] \
- [appendArgs " targetFramework=\"net40\".*? " \
- "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \
- "\" "] \
- [appendArgs " targetFramework=\"net45\".*? " \
- "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \
- "\" "] \
- [appendArgs " targetFramework=\"net451\".*? " \
- "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \
- "\" "] \
- [appendArgs " targetFramework=\"net40\".*? " \
- "id=\"System\\.Data\\.SQLite\\.EF6\" version=\"" $version(nuget) \
- "\" "] \
- [appendArgs " targetFramework=\"net45\".*? " \
- "id=\"System\\.Data\\.SQLite\\.EF6\" version=\"" $version(nuget) \
- "\" "] \
- [appendArgs " targetFramework=\"net451\".*? " \
- "id=\"System\\.Data\\.SQLite\\.EF6\" version=\"" $version(nuget) \
- "\" "]
+ "id=\"System\\.Data\\.SQLite\\.Linq\\.Beta\" version=\"" \
+ $version(nuget) "\" "] \
+ [appendArgs " targetFramework=\"net40\".*? " \
+ "id=\"System\\.Data\\.SQLite\\.Linq\\.Beta\" version=\"" \
+ $version(nuget) "\" "] \
+ [appendArgs " targetFramework=\"net45\".*? " \
+ "id=\"System\\.Data\\.SQLite\\.Linq\\.Beta\" version=\"" \
+ $version(nuget) "\" "] \
+ [appendArgs " targetFramework=\"net451\".*? " \
+ "id=\"System\\.Data\\.SQLite\\.Linq\\.Beta\" version=\"" \
+ $version(nuget) "\" "] \
+ [appendArgs " targetFramework=\"net40\".*? " \
+ "id=\"System\\.Data\\.SQLite\\.EF6\\.Beta\" version=\"" \
+ $version(nuget) "\" "] \
+ [appendArgs " targetFramework=\"net45\".*? " \
+ "id=\"System\\.Data\\.SQLite\\.EF6\\.Beta\" version=\"" \
+ $version(nuget) "\" "] \
+ [appendArgs " targetFramework=\"net451\".*? " \
+ "id=\"System\\.Data\\.SQLite\\.EF6\\.Beta\" version=\"" \
+ $version(nuget) "\" "]
###############################################################################
# SQLite.Core.nuspec
###############################################################################
@@ -550,42 +550,42 @@
lappend patterns \
[appendArgs [string map [list . \\.] $version(nuget)] \
] \
[appendArgs " targetFramework=\"net20\".*? " \
- "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \
- "\" "] \
+ "id=\"System\\.Data\\.SQLite\\.Core\\.Test\" version=\"" \
+ $version(nuget) "\" "] \
[appendArgs " targetFramework=\"net40\".*? " \
- "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \
- "\" "] \
+ "id=\"System\\.Data\\.SQLite\\.Core\\.Test\" version=\"" \
+ $version(nuget) "\" "] \
[appendArgs " targetFramework=\"net45\".*? " \
- "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \
- "\" "] \
+ "id=\"System\\.Data\\.SQLite\\.Core\\.Test\" version=\"" \
+ $version(nuget) "\" "] \
[appendArgs " targetFramework=\"net451\".*? " \
- "id=\"System\\.Data\\.SQLite\\.Core\" version=\"" $version(nuget) \
- "\" "] \
+ "id=\"System\\.Data\\.SQLite\\.Core\\.Test\" version=\"" \
+ $version(nuget) "\" "] \
[appendArgs " targetFramework=\"net20\".*? " \
- "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \
- "\" "] \
- [appendArgs " targetFramework=\"net40\".*? " \
- "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \
- "\" "] \
- [appendArgs " targetFramework=\"net45\".*? " \
- "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \
- "\" "] \
- [appendArgs " targetFramework=\"net451\".*? " \
- "id=\"System\\.Data\\.SQLite\\.Linq\" version=\"" $version(nuget) \
- "\" "] \
- [appendArgs " targetFramework=\"net40\".*? " \
- "id=\"System\\.Data\\.SQLite\\.EF6\" version=\"" $version(nuget) \
- "\" "] \
- [appendArgs " targetFramework=\"net45\".*? " \
- "id=\"System\\.Data\\.SQLite\\.EF6\" version=\"" $version(nuget) \
- "\" "] \
- [appendArgs " targetFramework=\"net451\".*? " \
- "id=\"System\\.Data\\.SQLite\\.EF6\" version=\"" $version(nuget) \
- "\" "]
+ "id=\"System\\.Data\\.SQLite\\.Linq\\.Test\" version=\"" \
+ $version(nuget) "\" "] \
+ [appendArgs " targetFramework=\"net40\".*? " \
+ "id=\"System\\.Data\\.SQLite\\.Linq\\.Test\" version=\"" \
+ $version(nuget) "\" "] \
+ [appendArgs " targetFramework=\"net45\".*? " \
+ "id=\"System\\.Data\\.SQLite\\.Linq\\.Test\" version=\"" \
+ $version(nuget) "\" "] \
+ [appendArgs " targetFramework=\"net451\".*? " \
+ "id=\"System\\.Data\\.SQLite\\.Linq\\.Test\" version=\"" \
+ $version(nuget) "\" "] \
+ [appendArgs " targetFramework=\"net40\".*? " \
+ "id=\"System\\.Data\\.SQLite\\.EF6\\.Test\" version=\"" \
+ $version(nuget) "\" "] \
+ [appendArgs " targetFramework=\"net45\".*? " \
+ "id=\"System\\.Data\\.SQLite\\.EF6\\.Test\" version=\"" \
+ $version(nuget) "\" "] \
+ [appendArgs " targetFramework=\"net451\".*? " \
+ "id=\"System\\.Data\\.SQLite\\.EF6\\.Test\" version=\"" \
+ $version(nuget) "\" "]
###############################################################################
# SQLite.x64.nuspec
###############################################################################
Index: readme.htm
==================================================================
--- readme.htm
+++ readme.htm
@@ -3,12 +3,12 @@
ADO.NET SQLite Data Provider
-Version 1.0.94.0 August XX, 2014 (release scheduled)
-Using SQLite 3.8.5
+Version 1.0.94.0 September XX, 2014 (release scheduled)
+Using SQLite 3.8.6
Originally written by Robert Simpson
Released to the public domain, use at your own risk!
Official provider website: http://system.data.sqlite.org/
Legacy versions: http://sqlite.phxsoftware.com/
@@ -143,11 +143,11 @@
<configuration>
<system.data>
<DbProviderFactories>
<remove invariant="System.Data.SQLite" />
- <add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".Net Framework Data Provider for SQLite"
+ <add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".NET Framework Data Provider for SQLite"
type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite, Version=1.0.94.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139" />
</DbProviderFactories>
</system.data>
</configuration>
@@ -207,17 +207,20 @@
Version History
- 1.0.94.0 - August XX, 2014 (release scheduled)
+ 1.0.94.0 - September XX, 2014 (release scheduled)
+ - Updated to SQLite 3.8.6.
- Updated to Entity Framework 6.1.1.
- Add RefreshFlags method to the SQLiteDataReader class to forcibly refresh its connection flags.
- Improve automatic detection and handling of the Entity Framework 6 assembly by the design-time components installer. Pursuant to [e634e330a6]. ** Potentially Incompatible Change **
- Improve SQLiteDataReader performance slightly by caching the connection flags. ** Potentially Incompatible Change **
+ - Add ClearCachedSettings method to the SQLiteConnection class.
+ - Add NoConvertSettings connection flag to disable querying of runtime configuration settings from within the SQLiteConvert class. Pursuant to [58ed318f2f].
- Minimize usage of the "Use_SQLiteConvert_DefaultDbType" and "Use_SQLiteConvert_DefaultTypeName" settings. Fix for [58ed318f2f]. ** Potentially Incompatible Change **
1.0.93.0 - June 23, 2014
Index: test/app.config
==================================================================
--- test/app.config
+++ test/app.config
@@ -1,8 +1,8 @@
-
+
Index: testlinq/2008/LINQ/App.config
==================================================================
--- testlinq/2008/LINQ/App.config
+++ testlinq/2008/LINQ/App.config
@@ -2,11 +2,11 @@
-
+
Index: testlinq/2010/EF6/App.config
==================================================================
--- testlinq/2010/EF6/App.config
+++ testlinq/2010/EF6/App.config
@@ -5,11 +5,11 @@
-
+
Index: testlinq/2010/LINQ/App.config
==================================================================
--- testlinq/2010/LINQ/App.config
+++ testlinq/2010/LINQ/App.config
@@ -2,11 +2,11 @@
-
+
Index: testlinq/2012/EF6/App.config
==================================================================
--- testlinq/2012/EF6/App.config
+++ testlinq/2012/EF6/App.config
@@ -5,11 +5,11 @@
-
+
Index: testlinq/2012/LINQ/App.config
==================================================================
--- testlinq/2012/LINQ/App.config
+++ testlinq/2012/LINQ/App.config
@@ -2,11 +2,11 @@
-
+
Index: testlinq/2013/EF6/App.config
==================================================================
--- testlinq/2013/EF6/App.config
+++ testlinq/2013/EF6/App.config
@@ -5,11 +5,11 @@
-
+
Index: testlinq/2013/LINQ/App.config
==================================================================
--- testlinq/2013/LINQ/App.config
+++ testlinq/2013/LINQ/App.config
@@ -2,11 +2,11 @@
-
+
Index: tools/install/Installer.cs
==================================================================
--- tools/install/Installer.cs
+++ tools/install/Installer.cs
@@ -95,53 +95,92 @@
#region Public Enumerations
[Flags()]
public enum InstallFlags
{
- #region Normal Flags
+ #region Normal Values
None = 0x0,
- GlobalAssemblyCache = 0x1,
- AssemblyFolders = 0x2,
- DbProviderFactory = 0x4,
- VsPackage = 0x8,
- VsPackageGlobalAssemblyCache = 0x10,
- VsDataSource = 0x20,
- VsDataProvider = 0x40,
- VsDevEnvSetup = 0x80,
+ CoreGlobalAssemblyCache = 0x1,
+ LinqGlobalAssemblyCache = 0x2,
+ Ef6GlobalAssemblyCache = 0x4,
+ AssemblyFolders = 0x8,
+ DbProviderFactory = 0x10,
+ VsPackage = 0x20,
+ VsPackageGlobalAssemblyCache = 0x40,
+ VsDataSource = 0x80,
+ VsDataProvider = 0x100,
+ VsDevEnvSetup = 0x200,
#endregion
///////////////////////////////////////////////////////////////////////
- #region Composite Flags
- Framework = GlobalAssemblyCache | AssemblyFolders |
+ #region Composite Values
+ FrameworkGlobalAssemblyCache = CoreGlobalAssemblyCache |
+ LinqGlobalAssemblyCache |
+ Ef6GlobalAssemblyCache,
+
+ ///////////////////////////////////////////////////////////////////////
+
+ Framework = FrameworkGlobalAssemblyCache | AssemblyFolders |
DbProviderFactory,
///////////////////////////////////////////////////////////////////////
Vs = VsPackage | VsPackageGlobalAssemblyCache | VsDataSource |
VsDataProvider | VsDevEnvSetup,
///////////////////////////////////////////////////////////////////////
+ AllGlobalAssemblyCache = FrameworkGlobalAssemblyCache |
+ VsPackageGlobalAssemblyCache,
+
+ ///////////////////////////////////////////////////////////////////////
+
All = Framework | Vs,
///////////////////////////////////////////////////////////////////////
- AllExceptGlobalAssemblyCache = All & ~(GlobalAssemblyCache |
- VsPackageGlobalAssemblyCache),
+ AllExceptGlobalAssemblyCache = All & ~AllGlobalAssemblyCache,
#endregion
///////////////////////////////////////////////////////////////////////
+ #region Suggested Default Values
Default = All
+ #endregion
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ [Flags()]
+ public enum ProviderFlags
+ {
+ #region Normal Values
+ None = 0x0,
+ SystemEf6MustBeGlobal = 0x1,
+ DidLinqForceTrace = 0x2,
+ DidEf6ForceTrace = 0x4,
+ DidEf6ResolveTrace = 0x8,
+ ForceLinqEnabled = 0x10,
+ ForceLinqDisabled = 0x20,
+ ForceEf6Enabled = 0x40,
+ ForceEf6Disabled = 0x80,
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Suggested Default Values
+ Default = None
+ #endregion
}
///////////////////////////////////////////////////////////////////////////
[Flags()]
public enum TracePriority
{
+ #region Normal Values
None = 0x0,
Lowest = 0x1,
Lower = 0x2,
Low = 0x4,
MediumLow = 0x8,
@@ -148,11 +187,17 @@
Medium = 0x10,
MediumHigh = 0x20,
High = 0x40,
Higher = 0x80,
Highest = 0x100,
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////
+
+ #region Suggested Default Flags
Default = Medium
+ #endregion
}
#endregion
///////////////////////////////////////////////////////////////////////////
@@ -837,10 +882,11 @@
#endregion
///////////////////////////////////////////////////////////////////
#region Public "Registry" Methods
+#if false
public object GetValue(
string keyName,
string valueName,
object defaultValue
)
@@ -878,10 +924,11 @@
CheckReadOnly();
if (!whatIf)
Registry.SetValue(keyName, valueName, value, valueKind);
}
+#endif
#endregion
///////////////////////////////////////////////////////////////////
#region Private Methods
@@ -1488,14 +1535,22 @@
get { return subKeysDeleted; }
}
///////////////////////////////////////////////////////////////////
- private static int keyValuesSet;
- public static int KeyValuesSet
+ private static int keyValuesRead;
+ public static int KeyValuesRead
{
- get { return keyValuesSet; }
+ get { return keyValuesRead; }
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ private static int keyValuesWritten;
+ public static int KeyValuesWritten
+ {
+ get { return keyValuesWritten; }
}
///////////////////////////////////////////////////////////////////
private static int keyValuesDeleted;
@@ -1684,11 +1739,15 @@
debugCallback, traceCallback, String.Format(
"key = {0}, name = {1}, defaultValue = {2}",
ForDisplay(key), ForDisplay(name),
ForDisplay(defaultValue)), traceCategory);
- return key.GetValue(name, defaultValue);
+ object value = key.GetValue(name, defaultValue);
+
+ keyValuesRead++;
+
+ return value;
}
///////////////////////////////////////////////////////////////////
[MethodImpl(MethodImplOptions.NoInlining)]
@@ -1711,11 +1770,11 @@
traceCategory);
if (!whatIf)
key.SetValue(name, value);
- keyValuesSet++;
+ keyValuesWritten++;
}
///////////////////////////////////////////////////////////////////
[MethodImpl(MethodImplOptions.NoInlining)]
@@ -1824,19 +1883,10 @@
#endregion
///////////////////////////////////////////////////////////////////
#region Public Properties
- private string configInvariantName;
- public string ConfigInvariantName
- {
- get { return configInvariantName; }
- set { configInvariantName = value; }
- }
-
- ///////////////////////////////////////////////////////////////////
-
private string providerInvariantName;
public string ProviderInvariantName
{
get { return providerInvariantName; }
set { providerInvariantName = value; }
@@ -1985,10 +2035,11 @@
string configVersion,
string vsVersionSuffix,
string debugFormat,
string traceFormat,
InstallFlags installFlags,
+ ProviderFlags providerFlags,
TracePriority debugPriority,
TracePriority tracePriority,
bool perUser,
bool install,
bool wow64,
@@ -2026,10 +2077,11 @@
this.configVersion = configVersion;
this.vsVersionSuffix = vsVersionSuffix;
this.debugFormat = debugFormat;
this.traceFormat = traceFormat;
this.installFlags = installFlags;
+ this.providerFlags = providerFlags;
this.debugPriority = debugPriority;
this.tracePriority = tracePriority;
this.perUser = perUser;
this.install = install;
this.wow64 = wow64;
@@ -2187,11 +2239,13 @@
return null;
}
///////////////////////////////////////////////////////////////////
- private static bool IsSystemEf6AssemblyAvailable()
+ private static bool IsSystemEf6AssemblyAvailable(
+ bool trace
+ )
{
if (systemEf6Assembly != null)
return true;
try
@@ -2199,41 +2253,58 @@
systemEf6Assembly = Assembly.ReflectionOnlyLoad(
SystemEf6AssemblyName);
if (systemEf6Assembly != null)
{
- TraceOps.DebugAndTrace(TracePriority.Highest,
- debugCallback, traceCallback, String.Format(
- "Entity Framework 6 assembly was resolved to {0}.",
- ForDisplay(systemEf6Assembly.Location)),
- traceCategory);
+ if (trace)
+ {
+ TraceOps.DebugAndTrace(TracePriority.Highest,
+ debugCallback, traceCallback, String.Format(
+ "Entity Framework 6 assembly was " +
+ "resolved to {0}.", ForDisplay(
+ systemEf6Assembly.Location)),
+ traceCategory);
+ }
return true;
}
}
catch
{
// do nothing.
}
- TraceOps.DebugAndTrace(TracePriority.Highest,
- debugCallback, traceCallback,
- "Entity Framework 6 assembly was not resolved.",
- traceCategory);
+ if (trace)
+ {
+ TraceOps.DebugAndTrace(TracePriority.Highest,
+ debugCallback, traceCallback,
+ "Entity Framework 6 assembly was not resolved.",
+ traceCategory);
+ }
return false;
}
+
+ ///////////////////////////////////////////////////////////////////
+
+ private static bool IsSystemEf6AssemblyGlobal()
+ {
+ if (systemEf6Assembly == null)
+ return false;
+
+ return systemEf6Assembly.GlobalAssemblyCache;
+ }
#endregion
///////////////////////////////////////////////////////////////////
#region Public Static Methods
public static void BreakIntoDebugger()
{
Console.WriteLine(
- "Attach a debugger to process {0} and press any key to " +
- "continue.", (thisProcess != null) ?
+ "Attach a debugger to process {0} and press " +
+ "any key to continue.", (thisProcess != null) ?
thisProcess.Id.ToString() : "");
try
{
Console.ReadKey(true); /* throw */
@@ -2262,15 +2333,15 @@
return new Configuration(
thisAssembly, null, directory, coreFileName, linqFileName,
ef6FileName, designerFileName, null, null, null,
TraceOps.DebugFormat, TraceOps.TraceFormat,
- InstallFlags.Default, TracePriority.Default,
- TracePriority.Default, false, true, false, false, false,
+ InstallFlags.Default, ProviderFlags.Default,
+ TracePriority.Default, TracePriority.Default, false, true,
+ false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false,
- false, false, false, false, false, false, true, true,
- false, false, false);
+ false, true, true, false, false, false);
}
///////////////////////////////////////////////////////////////////
[MethodImpl(MethodImplOptions.NoInlining)]
@@ -2931,10 +3002,31 @@
continue;
}
configuration.perUser = (bool)value;
}
+ else if (MatchOption(newArg, "providerFlags"))
+ {
+ object value = ParseEnum(
+ typeof(ProviderFlags), text, true);
+
+ if (value == null)
+ {
+ error = TraceOps.DebugAndTrace(
+ TracePriority.Lowest, debugCallback,
+ traceCallback, String.Format(
+ "Invalid provider flags value: {0}",
+ ForDisplay(text)), traceCategory);
+
+ if (strict)
+ return false;
+
+ continue;
+ }
+
+ configuration.providerFlags = (ProviderFlags)value;
+ }
else if (MatchOption(newArg, "registryVersion"))
{
configuration.registryVersion = text;
}
else if (MatchOption(newArg, "strict"))
@@ -3403,10 +3495,19 @@
}
#endregion
///////////////////////////////////////////////////////////////////
+ #region Private Methods
+ private string GetInvariantName()
+ {
+ return UseEf6Provider() ? Ef6InvariantName : InvariantName;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////
+
#region Public Methods
public bool HasFlags(
InstallFlags hasFlags,
bool all
)
@@ -3417,12 +3518,59 @@
return ((installFlags & hasFlags) != InstallFlags.None);
}
///////////////////////////////////////////////////////////////////
+ public bool HasFlags(
+ ProviderFlags hasFlags,
+ bool all
+ )
+ {
+ if (all)
+ return ((providerFlags & hasFlags) == hasFlags);
+ else
+ return ((providerFlags & hasFlags) != ProviderFlags.None);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
public bool IsLinqSupported()
{
+ //
+ // NOTE: Check to see if the caller has forced LINQ support to
+ // be enabled -OR- disabled, thereby bypassing the need
+ // for "automatic detection" by this method.
+ //
+ if (HasFlags(ProviderFlags.ForceLinqEnabled, true))
+ {
+ if (!HasFlags(ProviderFlags.DidLinqForceTrace, true))
+ {
+ TraceOps.DebugAndTrace(TracePriority.MediumHigh,
+ debugCallback, traceCallback,
+ "Forced to enable support for \"Linq\".",
+ traceCategory);
+
+ providerFlags |= ProviderFlags.DidLinqForceTrace;
+ }
+
+ return true;
+ }
+ else if (HasFlags(ProviderFlags.ForceLinqDisabled, true))
+ {
+ if (!HasFlags(ProviderFlags.DidLinqForceTrace, true))
+ {
+ TraceOps.DebugAndTrace(TracePriority.MediumHigh,
+ debugCallback, traceCallback,
+ "Forced to disable support for \"Linq\".",
+ traceCategory);
+
+ providerFlags |= ProviderFlags.DidLinqForceTrace;
+ }
+
+ return false;
+ }
+
//
// NOTE: Return non-zero if the System.Data.SQLite.Linq
// assembly should be processed during the install.
// If the target is Visual Studio 2005, this must
// return zero.
@@ -3432,27 +3580,109 @@
///////////////////////////////////////////////////////////////////
public bool IsEf6Supported()
{
+ //
+ // NOTE: Check to see if the caller has forced EF6 support to
+ // be enabled -OR- disabled, thereby bypassing the need
+ // for "automatic detection" by this method.
+ //
+ if (HasFlags(ProviderFlags.ForceEf6Enabled, true))
+ {
+ if (!HasFlags(ProviderFlags.DidEf6ForceTrace, true))
+ {
+ TraceOps.DebugAndTrace(TracePriority.MediumHigh,
+ debugCallback, traceCallback,
+ "Forced to enable support for \"Ef6\".",
+ traceCategory);
+
+ providerFlags |= ProviderFlags.DidEf6ForceTrace;
+ }
+
+ return true;
+ }
+ else if (HasFlags(ProviderFlags.ForceEf6Disabled, true))
+ {
+ if (!HasFlags(ProviderFlags.DidEf6ForceTrace, true))
+ {
+ TraceOps.DebugAndTrace(TracePriority.MediumHigh,
+ debugCallback, traceCallback,
+ "Forced to disable support for \"Ef6\".",
+ traceCategory);
+
+ providerFlags |= ProviderFlags.DidEf6ForceTrace;
+ }
+
+ return false;
+ }
+
//
// NOTE: Return non-zero if the System.Data.SQLite.EF6
// assembly should be processed during the install.
// If the target is Visual Studio 2005 or Visual
- // Studio 2008, this must return zero. Also, if
- // the EF6 core assembly is unavailable, this must
- // return zero.
+ // Studio 2008, this must return zero.
//
if (noNetFx40 && noNetFx45 && noNetFx451)
return false;
- return IsSystemEf6AssemblyAvailable();
+ //
+ // NOTE: Also, if the EF6 core assembly is unavailable, this
+ // must return zero.
+ //
+ if (!IsSystemEf6AssemblyAvailable(!HasFlags(
+ ProviderFlags.DidEf6ResolveTrace, true)))
+ {
+ providerFlags |= ProviderFlags.DidEf6ResolveTrace;
+ return false;
+ }
+
+ //
+ // NOTE: Finally, if the EF6 core assembly is not available
+ // globally [and this is a requirement for the current
+ // install], return zero.
+ //
+ return HasFlags(ProviderFlags.SystemEf6MustBeGlobal, true) ?
+ IsSystemEf6AssemblyGlobal() : true;
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ private bool IsEf6AssemblyGlobal()
+ {
+ if (ef6AssemblyName == null)
+ return false;
+
+ Assembly assembly = Assembly.ReflectionOnlyLoad(
+ ef6AssemblyName.ToString());
+
+ return (assembly != null) && assembly.GlobalAssemblyCache;
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ public bool UseEf6Provider()
+ {
+ //
+ // NOTE: We cannot use the EF6 assembly as the provider if it
+ // is not supported by this installation.
+ //
+ if (!IsEf6Supported())
+ return false;
+
+ //
+ // NOTE: For the EF6 assembly to be usable as a provider in
+ // the machine configuration file, it must be in the
+ // global assembly cache.
+ //
+ return IsEf6AssemblyGlobal();
}
///////////////////////////////////////////////////////////////////
- public AssemblyName GetCoreAssemblyName() /* REQUIRED */
+ /* REQUIRED */
+ public AssemblyName GetCoreAssemblyName() /* throw */
{
if (coreAssemblyName == null)
{
coreAssemblyName = AssemblyName.GetAssemblyName(
CoreFileName); /* throw */
@@ -3461,11 +3691,12 @@
return coreAssemblyName;
}
///////////////////////////////////////////////////////////////////
- public AssemblyName GetLinqAssemblyName() /* OPTIONAL */
+ /* OPTIONAL */
+ public AssemblyName GetLinqAssemblyName() /* throw */
{
if (IsLinqSupported() && (linqAssemblyName == null))
{
linqAssemblyName = AssemblyName.GetAssemblyName(
LinqFileName); /* throw */
@@ -3474,11 +3705,12 @@
return linqAssemblyName;
}
///////////////////////////////////////////////////////////////////
- public AssemblyName GetEf6AssemblyName() /* OPTIONAL */
+ /* OPTIONAL */
+ public AssemblyName GetEf6AssemblyName() /* throw */
{
if (IsEf6Supported() && (ef6AssemblyName == null))
{
ef6AssemblyName = AssemblyName.GetAssemblyName(
Ef6FileName); /* throw */
@@ -3487,11 +3719,12 @@
return ef6AssemblyName;
}
///////////////////////////////////////////////////////////////////
- public AssemblyName GetDesignerAssemblyName() /* REQUIRED */
+ /* REQUIRED */
+ public AssemblyName GetDesignerAssemblyName() /* throw */
{
if (designerAssemblyName == null)
{
designerAssemblyName = AssemblyName.GetAssemblyName(
DesignerFileName); /* throw */
@@ -3500,35 +3733,36 @@
return designerAssemblyName;
}
///////////////////////////////////////////////////////////////////
+ /* REQUIRED */
+ public AssemblyName GetProviderAssemblyName() /* throw */
+ {
+ return UseEf6Provider() ?
+ GetEf6AssemblyName() : GetCoreAssemblyName();
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
public string GetConfigInvariantName()
{
- return InvariantName;
+ return GetInvariantName();
}
///////////////////////////////////////////////////////////////////
public string GetProviderInvariantName()
{
- return IsEf6Supported() ? Ef6InvariantName : InvariantName;
+ return GetInvariantName();
}
///////////////////////////////////////////////////////////////////
public string GetFactoryTypeName()
{
- return IsEf6Supported() ? Ef6FactoryTypeName : FactoryTypeName;
- }
-
- ///////////////////////////////////////////////////////////////////
-
- public AssemblyName GetProviderAssemblyName()
- {
- return IsEf6Supported() ?
- GetEf6AssemblyName() : GetCoreAssemblyName(); /* throw */
+ return UseEf6Provider() ? Ef6FactoryTypeName : FactoryTypeName;
}
///////////////////////////////////////////////////////////////////
public void Dump(
@@ -3586,10 +3820,14 @@
traceCategory);
traceCallback(String.Format(NameAndValueFormat,
"InstallFlags", ForDisplay(installFlags)),
traceCategory);
+
+ traceCallback(String.Format(NameAndValueFormat,
+ "ProviderFlags", ForDisplay(providerFlags)),
+ traceCategory);
traceCallback(String.Format(NameAndValueFormat,
"DebugPriority", ForDisplay(debugPriority)),
traceCategory);
@@ -3708,37 +3946,104 @@
traceCategory);
}
///////////////////////////////////////////////////////////
+ traceCallback(String.Format(NameAndValueFormat,
+ "IsSystemEf6AssemblyAvailable", ForDisplay(
+ IsSystemEf6AssemblyAvailable(false))),
+ traceCategory);
+
+ traceCallback(String.Format(NameAndValueFormat,
+ "IsSystemEf6AssemblyGlobal", ForDisplay(
+ IsSystemEf6AssemblyGlobal())),
+ traceCategory);
+
+ ///////////////////////////////////////////////////////////
+
traceCallback(String.Format(NameAndValueFormat,
"IsLinqSupported", ForDisplay(IsLinqSupported())),
traceCategory);
traceCallback(String.Format(NameAndValueFormat,
"IsEf6Supported", ForDisplay(IsEf6Supported())),
traceCategory);
+
+ traceCallback(String.Format(NameAndValueFormat,
+ "IsEf6AssemblyGlobal", ForDisplay(
+ IsEf6AssemblyGlobal())),
+ traceCategory);
+
+ traceCallback(String.Format(NameAndValueFormat,
+ "UseEf6Provider", ForDisplay(UseEf6Provider())),
+ traceCategory);
+
+ ///////////////////////////////////////////////////////////
+
+ try
+ {
+ traceCallback(String.Format(NameAndValueFormat,
+ "GetCoreAssemblyName", ForDisplay(
+ GetCoreAssemblyName())), traceCategory);
+ }
+ catch (Exception e)
+ {
+ traceCallback(String.Format(NameAndValueFormat,
+ "GetCoreAssemblyName", ForDisplay(e)),
+ traceCategory);
+ }
+
+ ///////////////////////////////////////////////////////////
+
+ try
+ {
+ traceCallback(String.Format(NameAndValueFormat,
+ "GetLinqAssemblyName", ForDisplay(
+ GetLinqAssemblyName())), traceCategory);
+ }
+ catch (Exception e)
+ {
+ traceCallback(String.Format(NameAndValueFormat,
+ "GetLinqAssemblyName", ForDisplay(e)),
+ traceCategory);
+ }
+
+ ///////////////////////////////////////////////////////////
+
+ try
+ {
+ traceCallback(String.Format(NameAndValueFormat,
+ "GetEf6AssemblyName", ForDisplay(
+ GetEf6AssemblyName())), traceCategory);
+ }
+ catch (Exception e)
+ {
+ traceCallback(String.Format(NameAndValueFormat,
+ "GetEf6AssemblyName", ForDisplay(e)),
+ traceCategory);
+ }
+
+ ///////////////////////////////////////////////////////////
+
+ try
+ {
+ traceCallback(String.Format(NameAndValueFormat,
+ "GetDesignerAssemblyName", ForDisplay(
+ GetDesignerAssemblyName())), traceCategory);
+ }
+ catch (Exception e)
+ {
+ traceCallback(String.Format(NameAndValueFormat,
+ "GetDesignerAssemblyName", ForDisplay(e)),
+ traceCategory);
+ }
///////////////////////////////////////////////////////////
traceCallback(String.Format(NameAndValueFormat,
- "GetCoreAssemblyName", ForDisplay(
- GetCoreAssemblyName())), traceCategory);
-
- traceCallback(String.Format(NameAndValueFormat,
- "GetLinqAssemblyName", ForDisplay(
- GetLinqAssemblyName())), traceCategory);
-
- traceCallback(String.Format(NameAndValueFormat,
- "GetEf6AssemblyName", ForDisplay(
- GetEf6AssemblyName())), traceCategory);
-
- traceCallback(String.Format(NameAndValueFormat,
- "GetDesignerAssemblyName", ForDisplay(
- GetDesignerAssemblyName())), traceCategory);
-
- ///////////////////////////////////////////////////////////
+ "GetInvariantName", ForDisplay(GetInvariantName())),
+ traceCategory);
traceCallback(String.Format(NameAndValueFormat,
"GetConfigInvariantName", ForDisplay(
GetConfigInvariantName())), traceCategory);
@@ -3748,13 +4053,24 @@
traceCallback(String.Format(NameAndValueFormat,
"GetFactoryTypeName", ForDisplay(
GetFactoryTypeName())), traceCategory);
- traceCallback(String.Format(NameAndValueFormat,
- "GetProviderAssemblyName", ForDisplay(
- GetProviderAssemblyName())), traceCategory);
+ ///////////////////////////////////////////////////////////
+
+ try
+ {
+ traceCallback(String.Format(NameAndValueFormat,
+ "GetProviderAssemblyName", ForDisplay(
+ GetProviderAssemblyName())), traceCategory);
+ }
+ catch (Exception e)
+ {
+ traceCallback(String.Format(NameAndValueFormat,
+ "GetProviderAssemblyName", ForDisplay(e)),
+ traceCategory);
+ }
}
}
#endregion
///////////////////////////////////////////////////////////////////
@@ -3872,10 +4188,19 @@
public InstallFlags InstallFlags
{
get { return installFlags; }
set { installFlags = value; }
}
+
+ ///////////////////////////////////////////////////////////////////
+
+ private ProviderFlags providerFlags;
+ public ProviderFlags ProviderFlags
+ {
+ get { return providerFlags; }
+ set { providerFlags = value; }
+ }
///////////////////////////////////////////////////////////////////
private TracePriority debugPriority;
public TracePriority DebugPriority
@@ -4491,13 +4816,19 @@
result = value.ToString();
if (result.Length == 0)
return "";
- result = String.Format(
- type.IsSubclassOf(typeof(ValueType)) ? "{0}" : "\"{0}\"",
- result);
+ if (type.IsSubclassOf(typeof(Exception)))
+ {
+ result = String.Format(
+ "{0}{1}{0}", Environment.NewLine, result);
+ }
+ else if (!type.IsSubclassOf(typeof(ValueType)))
+ {
+ result = String.Format("\"{0}\"", result);
+ }
}
return result;
}
#endregion
@@ -6196,11 +6527,10 @@
///////////////////////////////////////////////////////////////////////
#region Visual Studio Package Handling
private static void InitializeVsPackage(
- string configInvariantName,
string providerInvariantName,
string factoryTypeName,
AssemblyName providerAssemblyName,
AssemblyName designerAssemblyName,
bool globalAssemblyCache,
@@ -6209,11 +6539,10 @@
{
if (package == null)
{
package = new Package();
- package.ConfigInvariantName = configInvariantName;
package.ProviderInvariantName = providerInvariantName;
package.FactoryTypeName = factoryTypeName;
package.ProviderAssemblyName = providerAssemblyName;
package.DesignerAssemblyName = designerAssemblyName;
package.GlobalAssemblyCache = globalAssemblyCache;
@@ -6757,11 +7086,11 @@
#endregion
#endregion
///////////////////////////////////////////////////////////////////////
- #region Application Entry Point
+ #region Installer Entry Point
[MethodImpl(MethodImplOptions.NoInlining)]
private static int Main(
string[] args
)
{
@@ -6800,21 +7129,30 @@
}
#endregion
///////////////////////////////////////////////////////////////
+ //
+ // NOTE: Setup the "mock" registry per the "what-if" mode.
+ // Since all registry access performed by this installer
+ // uses this "mock" registry, it is impossible for any
+ // actual system changes to occur unless "what-if" mode
+ // is disabled. Furthermore, protections are in place
+ // to prevent direct access to the wrapped registry keys
+ // when "safe" mode is enabled.
+ //
using (MockRegistry registry = new MockRegistry(
configuration.WhatIf, false, false))
{
- #region Core Assembly Name Check
+ #region Assembly Name Checks
//
// NOTE: Query all the assembly names first, before making
- // any changes to the system, because this will throw
- // an exception if any of the file names do not point
- // to a valid managed assembly. The values of these
- // local variables are never used after this point;
- // however, do not remove them.
+ // any changes to the system, because these calls
+ // will throw exceptions if any of the file names do
+ // not point to a valid managed assembly. The values
+ // of these local variables are never used after this
+ // point; however, do not remove them.
//
AssemblyName coreAssemblyName =
configuration.GetCoreAssemblyName(); /* NOT USED */
AssemblyName linqAssemblyName =
@@ -6860,17 +7198,16 @@
VsList vsList = null;
///////////////////////////////////////////////////////////
InitializeVsPackage(
- configuration.GetConfigInvariantName(),
configuration.GetProviderInvariantName(),
configuration.GetFactoryTypeName(),
configuration.GetProviderAssemblyName(),
configuration.GetDesignerAssemblyName(),
configuration.HasFlags(
- InstallFlags.GlobalAssemblyCache, true) &&
+ InstallFlags.AllGlobalAssemblyCache, true) &&
configuration.HasFlags(
InstallFlags.VsPackageGlobalAssemblyCache, true),
ref package);
///////////////////////////////////////////////////////////
@@ -6896,61 +7233,91 @@
///////////////////////////////////////////////////////////
#region .NET GAC Install/Remove
if (configuration.HasFlags(
- InstallFlags.GlobalAssemblyCache, true))
+ InstallFlags.AllGlobalAssemblyCache, false))
{
Publish publish = null;
if (!configuration.WhatIf)
publish = new Publish();
if (configuration.Install)
{
- if (!configuration.WhatIf)
- /* throw */
- publish.GacInstall(configuration.CoreFileName);
-
- TraceOps.DebugAndTrace(TracePriority.Highest,
- debugCallback, traceCallback, String.Format(
- "GacInstall: assemblyPath = {0}",
- ForDisplay(configuration.CoreFileName)),
- traceCategory);
-
- if (configuration.IsLinqSupported())
- {
- if (!configuration.WhatIf)
- /* throw */
- publish.GacInstall(configuration.LinqFileName);
+ if (configuration.HasFlags(
+ InstallFlags.CoreGlobalAssemblyCache,
+ true))
+ {
+ if (!configuration.WhatIf)
+ {
+ /* throw */
+ publish.GacInstall(
+ configuration.CoreFileName);
+ }
+
+ TraceOps.DebugAndTrace(TracePriority.Highest,
+ debugCallback, traceCallback, String.Format(
+ "GacInstall: assemblyPath = {0}",
+ ForDisplay(configuration.CoreFileName)),
+ traceCategory);
+ }
+
+ ///////////////////////////////////////////////////
+
+ if (configuration.HasFlags(
+ InstallFlags.LinqGlobalAssemblyCache,
+ true) &&
+ configuration.IsLinqSupported())
+ {
+ if (!configuration.WhatIf)
+ {
+ /* throw */
+ publish.GacInstall(
+ configuration.LinqFileName);
+ }
TraceOps.DebugAndTrace(TracePriority.Highest,
debugCallback, traceCallback, String.Format(
"GacInstall: assemblyPath = {0}",
ForDisplay(configuration.LinqFileName)),
traceCategory);
}
- if (configuration.IsEf6Supported())
+ ///////////////////////////////////////////////////
+
+ if (configuration.HasFlags(
+ InstallFlags.Ef6GlobalAssemblyCache,
+ true) &&
+ configuration.IsEf6Supported())
{
if (!configuration.WhatIf)
+ {
/* throw */
- publish.GacInstall(configuration.Ef6FileName);
+ publish.GacInstall(
+ configuration.Ef6FileName);
+ }
TraceOps.DebugAndTrace(TracePriority.Highest,
debugCallback, traceCallback, String.Format(
"GacInstall: assemblyPath = {0}",
ForDisplay(configuration.Ef6FileName)),
traceCategory);
}
+ ///////////////////////////////////////////////////
+
if (configuration.HasFlags(
- InstallFlags.VsPackageGlobalAssemblyCache, true))
+ InstallFlags.VsPackageGlobalAssemblyCache,
+ true))
{
if (!configuration.WhatIf)
+ {
/* throw */
- publish.GacInstall(configuration.DesignerFileName);
+ publish.GacInstall(
+ configuration.DesignerFileName);
+ }
TraceOps.DebugAndTrace(TracePriority.Highest,
debugCallback, traceCallback, String.Format(
"GacInstall: assemblyPath = {0}",
ForDisplay(configuration.DesignerFileName)),
@@ -6958,58 +7325,88 @@
}
}
else
{
if (configuration.HasFlags(
- InstallFlags.VsPackageGlobalAssemblyCache, true))
+ InstallFlags.VsPackageGlobalAssemblyCache,
+ true))
{
if (!configuration.WhatIf)
+ {
/* throw */
- publish.GacRemove(configuration.DesignerFileName);
+ publish.GacRemove(
+ configuration.DesignerFileName);
+ }
TraceOps.DebugAndTrace(TracePriority.Highest,
debugCallback, traceCallback, String.Format(
"GacRemove: assemblyPath = {0}",
ForDisplay(configuration.DesignerFileName)),
traceCategory);
}
- if (configuration.IsEf6Supported())
+ ///////////////////////////////////////////////////
+
+ if (configuration.HasFlags(
+ InstallFlags.Ef6GlobalAssemblyCache,
+ true) &&
+ configuration.IsEf6Supported())
{
if (!configuration.WhatIf)
+ {
/* throw */
- publish.GacRemove(configuration.Ef6FileName);
+ publish.GacRemove(
+ configuration.Ef6FileName);
+ }
TraceOps.DebugAndTrace(TracePriority.Highest,
debugCallback, traceCallback, String.Format(
"GacRemove: assemblyPath = {0}",
ForDisplay(configuration.Ef6FileName)),
traceCategory);
}
- if (configuration.IsLinqSupported())
+ ///////////////////////////////////////////////////
+
+ if (configuration.HasFlags(
+ InstallFlags.LinqGlobalAssemblyCache,
+ true) &&
+ configuration.IsLinqSupported())
{
if (!configuration.WhatIf)
+ {
/* throw */
- publish.GacRemove(configuration.LinqFileName);
+ publish.GacRemove(
+ configuration.LinqFileName);
+ }
TraceOps.DebugAndTrace(TracePriority.Highest,
debugCallback, traceCallback, String.Format(
"GacRemove: assemblyPath = {0}",
ForDisplay(configuration.LinqFileName)),
traceCategory);
}
- if (!configuration.WhatIf)
- /* throw */
- publish.GacRemove(configuration.CoreFileName);
-
- TraceOps.DebugAndTrace(TracePriority.Highest,
- debugCallback, traceCallback, String.Format(
- "GacRemove: assemblyPath = {0}",
- ForDisplay(configuration.CoreFileName)),
- traceCategory);
+ ///////////////////////////////////////////////////
+
+ if (configuration.HasFlags(
+ InstallFlags.CoreGlobalAssemblyCache,
+ true))
+ {
+ if (!configuration.WhatIf)
+ {
+ /* throw */
+ publish.GacRemove(
+ configuration.CoreFileName);
+ }
+
+ TraceOps.DebugAndTrace(TracePriority.Highest,
+ debugCallback, traceCallback, String.Format(
+ "GacRemove: assemblyPath = {0}",
+ ForDisplay(configuration.CoreFileName)),
+ traceCategory);
+ }
}
}
#endregion
///////////////////////////////////////////////////////////
@@ -7050,12 +7447,13 @@
bool saved = false;
if (!ForEachFrameworkConfig(registry,
frameworkList, ProcessDbProviderFactory,
configuration.ConfigVersion,
- package.ConfigInvariantName, ProviderName,
- Description, package.FactoryTypeName,
+ configuration.GetConfigInvariantName(),
+ ProviderName, Description,
+ package.FactoryTypeName,
package.ProviderAssemblyName, directoryData,
configuration.PerUser,
NetFxIs32BitOnly || configuration.Wow64,
configuration.ThrowOnMissing,
configuration.WhatIf, configuration.Verbose,
@@ -7195,14 +7593,16 @@
#region Log Summary
TraceOps.DebugAndTrace(TracePriority.MediumHigh,
debugCallback, traceCallback, String.Format(
"subKeysCreated = {0}, subKeysDeleted = {1}, " +
- "keyValuesSet = {2}, keyValuesDeleted = {3}",
+ "keyValuesRead = {2}, keyValuesWritten = {3}, " +
+ "keyValuesDeleted = {4}",
ForDisplay(RegistryHelper.SubKeysCreated),
ForDisplay(RegistryHelper.SubKeysDeleted),
- ForDisplay(RegistryHelper.KeyValuesSet),
+ ForDisplay(RegistryHelper.KeyValuesRead),
+ ForDisplay(RegistryHelper.KeyValuesWritten),
ForDisplay(RegistryHelper.KeyValuesDeleted)),
traceCategory);
TraceOps.DebugAndTrace(TracePriority.MediumHigh,
debugCallback, traceCallback, String.Format(
Index: www/news.wiki
==================================================================
--- www/news.wiki
+++ www/news.wiki
@@ -1,17 +1,20 @@
News
Version History
- 1.0.94.0 - August XX, 2014
+ 1.0.94.0 - September XX, 2014
- - Updated to Entity Framework 6.1.1.
+ - Updated to [http://www.sqlite.org/releaselog/3_8_6.html|SQLite 3.8.6].
+ - Updated to [http://www.nuget.org/packages/EntityFramework/6.1.1|Entity Framework 6.1.1].
- Add RefreshFlags method to the SQLiteDataReader class to forcibly refresh its connection flags.
- Improve automatic detection and handling of the Entity Framework 6 assembly by the design-time components installer. Pursuant to [e634e330a6]. ** Potentially Incompatible Change **
- Improve SQLiteDataReader performance slightly by caching the connection flags. ** Potentially Incompatible Change **
+ - Add ClearCachedSettings method to the SQLiteConnection class.
+ - Add NoConvertSettings connection flag to disable querying of runtime configuration settings from within the SQLiteConvert class. Pursuant to [58ed318f2f].
- Minimize usage of the "Use_SQLiteConvert_DefaultDbType" and "Use_SQLiteConvert_DefaultTypeName" settings. Fix for [58ed318f2f]. ** Potentially Incompatible Change **
1.0.93.0 - June 23, 2014