Files
MSYS2-packages/sqlite/sqlite3-3.30.0-1.src.patch
T

56411 lines
1.9 MiB
Plaintext

--- origsrc/sqlite-autoconf-3300000/, 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/, 2019-03-05 13:14:40.375000000 +0100
@@ -0,0 +1,896 @@
+#! /bin/sh
+# restart with tclsh \
+exec tclsh "$0" ${1+"$@"}
+package require sqlite3
+
+# Run this TCL script using an SQLite-enabled TCL interpreter to get a report
+# on how much disk space is used by a particular data to actually store data
+# versus how much space is unused.
+#
+# The dbstat virtual table is required.
+#
+
+if {[catch {
+
+# Argument $tname is the name of a table within the database opened by
+# database handle [db]. Return true if it is a WITHOUT ROWID table, or
+# false otherwise.
+#
+proc is_without_rowid {tname} {
+ set t [string map {' ''} $tname]
+ db eval "PRAGMA index_list = '$t'" o {
+ if {$o(origin) == "pk"} {
+ set n $o(name)
+ if {0==[db one { SELECT count(*) FROM sqlite_master WHERE name=$n }]} {
+ return 1
+ }
+ }
+ }
+ return 0
+}
+
+# Read and run TCL commands from standard input. Used to implement
+# the --tclsh option.
+#
+proc tclsh {} {
+ set line {}
+ while {![eof stdin]} {
+ if {$line!=""} {
+ puts -nonewline "> "
+ } else {
+ puts -nonewline "% "
+ }
+ flush stdout
+ append line [gets stdin]
+ if {[info complete $line]} {
+ if {[catch {uplevel #0 $line} result]} {
+ puts stderr "Error: $result"
+ } elseif {$result!=""} {
+ puts $result
+ }
+ set line {}
+ } else {
+ append line \n
+ }
+ }
+}
+
+
+# Get the name of the database to analyze
+#
+proc usage {} {
+ set argv0 [file rootname [file tail [info script]]]
+ puts stderr "Usage: $argv0 ?--pageinfo? ?--stats? database-filename"
+ puts stderr {
+Analyze the SQLite3 database file specified by the "database-filename"
+argument and output a report detailing size and storage efficiency
+information for the database and its constituent tables and indexes.
+
+Options:
+
+ --pageinfo Show how each page of the database-file is used
+
+ --stats Output SQL text that creates a new database containing
+ statistics about the database that was analyzed
+
+ --tclsh Run the built-in TCL interpreter interactively (for debugging)
+
+ --version Show the version number of SQLite
+}
+ exit 1
+}
+set file_to_analyze {}
+set flags(-pageinfo) 0
+set flags(-stats) 0
+set flags(-debug) 0
+append argv {}
+foreach arg $argv {
+ if {[regexp {^-+pageinfo$} $arg]} {
+ set flags(-pageinfo) 1
+ } elseif {[regexp {^-+stats$} $arg]} {
+ set flags(-stats) 1
+ } elseif {[regexp {^-+debug$} $arg]} {
+ set flags(-debug) 1
+ } elseif {[regexp {^-+tclsh$} $arg]} {
+ tclsh
+ exit 0
+ } elseif {[regexp {^-+version$} $arg]} {
+ sqlite3 mem :memory:
+ puts [mem one {SELECT sqlite_version()||' '||sqlite_source_id()}]
+ mem close
+ exit 0
+ } elseif {[regexp {^-} $arg]} {
+ puts stderr "Unknown option: $arg"
+ usage
+ } elseif {$file_to_analyze!=""} {
+ usage
+ } else {
+ set file_to_analyze $arg
+ }
+}
+if {$file_to_analyze==""} usage
+set root_filename $file_to_analyze
+regexp {^file:(//)?([^?]*)} $file_to_analyze all x1 root_filename
+if {![file exists $root_filename]} {
+ puts stderr "No such file: $root_filename"
+ exit 1
+}
+if {![file readable $root_filename]} {
+ puts stderr "File is not readable: $root_filename"
+ exit 1
+}
+set true_file_size [file size $root_filename]
+if {$true_file_size<512} {
+ puts stderr "Empty or malformed database: $root_filename"
+ exit 1
+}
+
+# Compute the total file size assuming test_multiplexor is being used.
+# Assume that SQLITE_ENABLE_8_3_NAMES might be enabled
+#
+set extension [file extension $root_filename]
+set pattern $root_filename
+append pattern {[0-3][0-9][0-9]}
+foreach f [glob -nocomplain $pattern] {
+ incr true_file_size [file size $f]
+ set extension {}
+}
+if {[string length $extension]>=2 && [string length $extension]<=4} {
+ set pattern [file rootname $root_filename]
+ append pattern {.[0-3][0-9][0-9]}
+ foreach f [glob -nocomplain $pattern] {
+ incr true_file_size [file size $f]
+ }
+}
+
+# Open the database
+#
+if {[catch {sqlite3 db $file_to_analyze -uri 1} msg]} {
+ puts stderr "error trying to open $file_to_analyze: $msg"
+ exit 1
+}
+if {$flags(-debug)} {
+ proc dbtrace {txt} {puts $txt; flush stdout;}
+ db trace ::dbtrace
+}
+
+# Make sure all required compile-time options are available
+#
+if {![db exists {SELECT 1 FROM pragma_compile_options
+ WHERE compile_options='ENABLE_DBSTAT_VTAB'}]} {
+ puts "The SQLite database engine linked with this application\
+ lacks required capabilities. Recompile using the\
+ -DSQLITE_ENABLE_DBSTAT_VTAB compile-time option to fix\
+ this problem."
+ exit 1
+}
+
+db eval {SELECT count(*) FROM sqlite_master}
+set pageSize [expr {wide([db one {PRAGMA page_size}])}]
+
+if {$flags(-pageinfo)} {
+ db eval {CREATE VIRTUAL TABLE temp.stat USING dbstat}
+ db eval {SELECT name, path, pageno FROM temp.stat ORDER BY pageno} {
+ puts "$pageno $name $path"
+ }
+ exit 0
+}
+if {$flags(-stats)} {
+ db eval {CREATE VIRTUAL TABLE temp.stat USING dbstat}
+ puts "BEGIN;"
+ puts "CREATE TABLE stats("
+ puts " name STRING, /* Name of table or index */"
+ puts " path INTEGER, /* Path to page from root */"
+ puts " pageno INTEGER, /* Page number */"
+ puts " pagetype STRING, /* 'internal', 'leaf' or 'overflow' */"
+ puts " ncell INTEGER, /* Cells on page (0 for overflow) */"
+ puts " payload INTEGER, /* Bytes of payload on this page */"
+ puts " unused INTEGER, /* Bytes of unused space on this page */"
+ puts " mx_payload INTEGER, /* Largest payload size of all cells */"
+ puts " pgoffset INTEGER, /* Offset of page in file */"
+ puts " pgsize INTEGER /* Size of the page */"
+ puts ");"
+ db eval {SELECT quote(name) || ',' ||
+ quote(path) || ',' ||
+ quote(pageno) || ',' ||
+ quote(pagetype) || ',' ||
+ quote(ncell) || ',' ||
+ quote(payload) || ',' ||
+ quote(unused) || ',' ||
+ quote(mx_payload) || ',' ||
+ quote(pgoffset) || ',' ||
+ quote(pgsize) AS x FROM stat} {
+ puts "INSERT INTO stats VALUES($x);"
+ }
+ puts "COMMIT;"
+ exit 0
+}
+
+
+# In-memory database for collecting statistics. This script loops through
+# the tables and indices in the database being analyzed, adding a row for each
+# to an in-memory database (for which the schema is shown below). It then
+# queries the in-memory db to produce the space-analysis report.
+#
+sqlite3 mem :memory:
+if {$flags(-debug)} {
+ proc dbtrace {txt} {puts $txt; flush stdout;}
+ mem trace ::dbtrace
+}
+set tabledef {CREATE TABLE space_used(
+ name clob, -- Name of a table or index in the database file
+ tblname clob, -- Name of associated table
+ is_index boolean, -- TRUE if it is an index, false for a table
+ is_without_rowid boolean, -- TRUE if WITHOUT ROWID table
+ nentry int, -- Number of entries in the BTree
+ leaf_entries int, -- Number of leaf entries
+ depth int, -- Depth of the b-tree
+ payload int, -- Total amount of data stored in this table or index
+ ovfl_payload int, -- Total amount of data stored on overflow pages
+ ovfl_cnt int, -- Number of entries that use overflow
+ mx_payload int, -- Maximum payload size
+ int_pages int, -- Number of interior pages used
+ leaf_pages int, -- Number of leaf pages used
+ ovfl_pages int, -- Number of overflow pages used
+ int_unused int, -- Number of unused bytes on interior pages
+ leaf_unused int, -- Number of unused bytes on primary pages
+ ovfl_unused int, -- Number of unused bytes on overflow pages
+ gap_cnt int, -- Number of gaps in the page layout
+ compressed_size int -- Total bytes stored on disk
+);}
+mem eval $tabledef
+
+# Create a temporary "dbstat" virtual table.
+#
+db eval {CREATE VIRTUAL TABLE temp.stat USING dbstat}
+db eval {CREATE TEMP TABLE dbstat AS SELECT * FROM temp.stat
+ ORDER BY name, path}
+db eval {DROP TABLE temp.stat}
+
+set isCompressed 0
+set compressOverhead 0
+set depth 0
+set sql { SELECT name, tbl_name FROM sqlite_master WHERE rootpage>0 }
+foreach {name tblname} [concat sqlite_master sqlite_master [db eval $sql]] {
+
+ set is_index [expr {$name!=$tblname}]
+ set is_without_rowid [is_without_rowid $name]
+ db eval {
+ SELECT
+ sum(ncell) AS nentry,
+ sum((pagetype=='leaf')*ncell) AS leaf_entries,
+ sum(payload) AS payload,
+ sum((pagetype=='overflow') * payload) AS ovfl_payload,
+ sum(path LIKE '%+000000') AS ovfl_cnt,
+ max(mx_payload) AS mx_payload,
+ sum(pagetype=='internal') AS int_pages,
+ sum(pagetype=='leaf') AS leaf_pages,
+ sum(pagetype=='overflow') AS ovfl_pages,
+ sum((pagetype=='internal') * unused) AS int_unused,
+ sum((pagetype=='leaf') * unused) AS leaf_unused,
+ sum((pagetype=='overflow') * unused) AS ovfl_unused,
+ sum(pgsize) AS compressed_size,
+ max((length(CASE WHEN path LIKE '%+%' THEN '' ELSE path END)+3)/4)
+ AS depth
+ FROM temp.dbstat WHERE name = $name
+ } break
+
+ set total_pages [expr {$leaf_pages+$int_pages+$ovfl_pages}]
+ set storage [expr {$total_pages*$pageSize}]
+ if {!$isCompressed && $storage>$compressed_size} {
+ set isCompressed 1
+ set compressOverhead 14
+ }
+
+ # Column 'gap_cnt' is set to the number of non-contiguous entries in the
+ # list of pages visited if the b-tree structure is traversed in a top-down
+ # fashion (each node visited before its child-tree is passed). Any overflow
+ # chains present are traversed from start to finish before any child-tree
+ # is.
+ #
+ set gap_cnt 0
+ set prev 0
+ db eval {
+ SELECT pageno, pagetype FROM temp.dbstat
+ WHERE name=$name
+ ORDER BY pageno
+ } {
+ if {$prev>0 && $pagetype=="leaf" && $pageno!=$prev+1} {
+ incr gap_cnt
+ }
+ set prev $pageno
+ }
+ mem eval {
+ INSERT INTO space_used VALUES(
+ $name,
+ $tblname,
+ $is_index,
+ $is_without_rowid,
+ $nentry,
+ $leaf_entries,
+ $depth,
+ $payload,
+ $ovfl_payload,
+ $ovfl_cnt,
+ $mx_payload,
+ $int_pages,
+ $leaf_pages,
+ $ovfl_pages,
+ $int_unused,
+ $leaf_unused,
+ $ovfl_unused,
+ $gap_cnt,
+ $compressed_size
+ );
+ }
+}
+
+proc integerify {real} {
+ if {[string is double -strict $real]} {
+ return [expr {wide($real)}]
+ } else {
+ return 0
+ }
+}
+mem function int integerify
+
+# Quote a string for use in an SQL query. Examples:
+#
+# [quote {hello world}] == {'hello world'}
+# [quote {hello world's}] == {'hello world''s'}
+#
+proc quote {txt} {
+ return [string map {' ''} $txt]
+}
+
+# Output a title line
+#
+proc titleline {title} {
+ if {$title==""} {
+ puts [string repeat * 79]
+ } else {
+ set len [string length $title]
+ set stars [string repeat * [expr 79-$len-5]]
+ puts "*** $title $stars"
+ }
+}
+
+# Generate a single line of output in the statistics section of the
+# report.
+#
+proc statline {title value {extra {}}} {
+ set len [string length $title]
+ set dots [string repeat . [expr 50-$len]]
+ set len [string length $value]
+ set sp2 [string range { } $len end]
+ if {$extra ne ""} {
+ set extra " $extra"
+ }
+ puts "$title$dots $value$sp2$extra"
+}
+
+# Generate a formatted percentage value for $num/$denom
+#
+proc percent {num denom {of {}}} {
+ if {$denom==0.0} {return ""}
+ set v [expr {$num*100.0/$denom}]
+ set of {}
+ if {$v==100.0 || $v<0.001 || ($v>1.0 && $v<99.0)} {
+ return [format {%5.1f%% %s} $v $of]
+ } elseif {$v<0.1 || $v>99.9} {
+ return [format {%7.3f%% %s} $v $of]
+ } else {
+ return [format {%6.2f%% %s} $v $of]
+ }
+}
+
+proc divide {num denom} {
+ if {$denom==0} {return 0.0}
+ return [format %.2f [expr double($num)/double($denom)]]
+}
+
+# Generate a subreport that covers some subset of the database.
+# the $where clause determines which subset to analyze.
+#
+proc subreport {title where showFrag} {
+ global pageSize file_pgcnt compressOverhead
+
+ # Query the in-memory database for the sum of various statistics
+ # for the subset of tables/indices identified by the WHERE clause in
+ # $where. Note that even if the WHERE clause matches no rows, the
+ # following query returns exactly one row (because it is an aggregate).
+ #
+ # The results of the query are stored directly by SQLite into local
+ # variables (i.e. $nentry, $payload etc.).
+ #
+ mem eval "
+ SELECT
+ int(sum(
+ CASE WHEN (is_without_rowid OR is_index) THEN nentry
+ ELSE leaf_entries
+ END
+ )) AS nentry,
+ int(sum(payload)) AS payload,
+ int(sum(ovfl_payload)) AS ovfl_payload,
+ max(mx_payload) AS mx_payload,
+ int(sum(ovfl_cnt)) as ovfl_cnt,
+ int(sum(leaf_pages)) AS leaf_pages,
+ int(sum(int_pages)) AS int_pages,
+ int(sum(ovfl_pages)) AS ovfl_pages,
+ int(sum(leaf_unused)) AS leaf_unused,
+ int(sum(int_unused)) AS int_unused,
+ int(sum(ovfl_unused)) AS ovfl_unused,
+ int(sum(gap_cnt)) AS gap_cnt,
+ int(sum(compressed_size)) AS compressed_size,
+ int(max(depth)) AS depth,
+ count(*) AS cnt
+ FROM space_used WHERE $where" {} {}
+
+ # Output the sub-report title, nicely decorated with * characters.
+ #
+ puts ""
+ titleline $title
+ puts ""
+
+ # Calculate statistics and store the results in TCL variables, as follows:
+ #
+ # total_pages: Database pages consumed.
+ # total_pages_percent: Pages consumed as a percentage of the file.
+ # storage: Bytes consumed.
+ # payload_percent: Payload bytes used as a percentage of $storage.
+ # total_unused: Unused bytes on pages.
+ # avg_payload: Average payload per btree entry.
+ # avg_fanout: Average fanout for internal pages.
+ # avg_unused: Average unused bytes per btree entry.
+ # avg_meta: Average metadata overhead per entry.
+ # ovfl_cnt_percent: Percentage of btree entries that use overflow pages.
+ #
+ set total_pages [expr {$leaf_pages+$int_pages+$ovfl_pages}]
+ set total_pages_percent [percent $total_pages $file_pgcnt]
+ set storage [expr {$total_pages*$pageSize}]
+ set payload_percent [percent $payload $storage {of storage consumed}]
+ set total_unused [expr {$ovfl_unused+$int_unused+$leaf_unused}]
+ set avg_payload [divide $payload $nentry]
+ set avg_unused [divide $total_unused $nentry]
+ set total_meta [expr {$storage - $payload - $total_unused}]
+ set total_meta [expr {$total_meta + 4*($ovfl_pages - $ovfl_cnt)}]
+ set meta_percent [percent $total_meta $storage {of metadata}]
+ set avg_meta [divide $total_meta $nentry]
+ if {$int_pages>0} {
+ # TODO: Is this formula correct?
+ set nTab [mem eval "
+ SELECT count(*) FROM (
+ SELECT DISTINCT tblname FROM space_used WHERE $where AND is_index=0
+ )
+ "]
+ set avg_fanout [mem eval "
+ SELECT (sum(leaf_pages+int_pages)-$nTab)/sum(int_pages) FROM space_used
+ WHERE $where
+ "]
+ set avg_fanout [format %.2f $avg_fanout]
+ }
+ set ovfl_cnt_percent [percent $ovfl_cnt $nentry {of all entries}]
+
+ # Print out the sub-report statistics.
+ #
+ statline {Percentage of total database} $total_pages_percent
+ statline {Number of entries} $nentry
+ statline {Bytes of storage consumed} $storage
+ if {$compressed_size!=$storage} {
+ set compressed_size [expr {$compressed_size+$compressOverhead*$total_pages}]
+ set pct [expr {$compressed_size*100.0/$storage}]
+ set pct [format {%5.1f%%} $pct]
+ statline {Bytes used after compression} $compressed_size $pct
+ }
+ statline {Bytes of payload} $payload $payload_percent
+ statline {Bytes of metadata} $total_meta $meta_percent
+ if {$cnt==1} {statline {B-tree depth} $depth}
+ statline {Average payload per entry} $avg_payload
+ statline {Average unused bytes per entry} $avg_unused
+ statline {Average metadata per entry} $avg_meta
+ if {[info exists avg_fanout]} {
+ statline {Average fanout} $avg_fanout
+ }
+ if {$showFrag && $total_pages>1} {
+ set fragmentation [percent $gap_cnt [expr {$total_pages-1}]]
+ statline {Non-sequential pages} $gap_cnt $fragmentation
+ }
+ statline {Maximum payload per entry} $mx_payload
+ statline {Entries that use overflow} $ovfl_cnt $ovfl_cnt_percent
+ if {$int_pages>0} {
+ statline {Index pages used} $int_pages
+ }
+ statline {Primary pages used} $leaf_pages
+ statline {Overflow pages used} $ovfl_pages
+ statline {Total pages used} $total_pages
+ if {$int_unused>0} {
+ set int_unused_percent [
+ percent $int_unused [expr {$int_pages*$pageSize}] {of index space}]
+ statline "Unused bytes on index pages" $int_unused $int_unused_percent
+ }
+ statline "Unused bytes on primary pages" $leaf_unused [
+ percent $leaf_unused [expr {$leaf_pages*$pageSize}] {of primary space}]
+ statline "Unused bytes on overflow pages" $ovfl_unused [
+ percent $ovfl_unused [expr {$ovfl_pages*$pageSize}] {of overflow space}]
+ statline "Unused bytes on all pages" $total_unused [
+ percent $total_unused $storage {of all space}]
+ return 1
+}
+
+# Calculate the overhead in pages caused by auto-vacuum.
+#
+# This procedure calculates and returns the number of pages used by the
+# auto-vacuum 'pointer-map'. If the database does not support auto-vacuum,
+# then 0 is returned. The two arguments are the size of the database file in
+# pages and the page size used by the database (in bytes).
+proc autovacuum_overhead {filePages pageSize} {
+
+ # Set $autovacuum to non-zero for databases that support auto-vacuum.
+ set autovacuum [db one {PRAGMA auto_vacuum}]
+
+ # If the database is not an auto-vacuum database or the file consists
+ # of one page only then there is no overhead for auto-vacuum. Return zero.
+ if {0==$autovacuum || $filePages==1} {
+ return 0
+ }
+
+ # The number of entries on each pointer map page. The layout of the
+ # database file is one pointer-map page, followed by $ptrsPerPage other
+ # pages, followed by a pointer-map page etc. The first pointer-map page
+ # is the second page of the file overall.
+ set ptrsPerPage [expr double($pageSize/5)]
+
+ # Return the number of pointer map pages in the database.
+ return [expr wide(ceil( ($filePages-1.0)/($ptrsPerPage+1.0) ))]
+}
+
+
+# Calculate the summary statistics for the database and store the results
+# in TCL variables. They are output below. Variables are as follows:
+#
+# pageSize: Size of each page in bytes.
+# file_bytes: File size in bytes.
+# file_pgcnt: Number of pages in the file.
+# file_pgcnt2: Number of pages in the file (calculated).
+# av_pgcnt: Pages consumed by the auto-vacuum pointer-map.
+# av_percent: Percentage of the file consumed by auto-vacuum pointer-map.
+# inuse_pgcnt: Data pages in the file.
+# inuse_percent: Percentage of pages used to store data.
+# free_pgcnt: Free pages calculated as (<total pages> - <in-use pages>)
+# free_pgcnt2: Free pages in the file according to the file header.
+# free_percent: Percentage of file consumed by free pages (calculated).
+# free_percent2: Percentage of file consumed by free pages (header).
+# ntable: Number of tables in the db.
+# nindex: Number of indices in the db.
+# nautoindex: Number of indices created automatically.
+# nmanindex: Number of indices created manually.
+# user_payload: Number of bytes of payload in table btrees
+# (not including sqlite_master)
+# user_percent: $user_payload as a percentage of total file size.
+
+### The following, setting $file_bytes based on the actual size of the file
+### on disk, causes this tool to choke on zipvfs databases. So set it based
+### on the return of [PRAGMA page_count] instead.
+if 0 {
+ set file_bytes [file size $file_to_analyze]
+ set file_pgcnt [expr {$file_bytes/$pageSize}]
+}
+set file_pgcnt [db one {PRAGMA page_count}]
+set file_bytes [expr {$file_pgcnt * $pageSize}]
+
+set av_pgcnt [autovacuum_overhead $file_pgcnt $pageSize]
+set av_percent [percent $av_pgcnt $file_pgcnt]
+
+set sql {SELECT sum(leaf_pages+int_pages+ovfl_pages) FROM space_used}
+set inuse_pgcnt [expr wide([mem eval $sql])]
+set inuse_percent [percent $inuse_pgcnt $file_pgcnt]
+
+set free_pgcnt [expr {$file_pgcnt-$inuse_pgcnt-$av_pgcnt}]
+set free_percent [percent $free_pgcnt $file_pgcnt]
+set free_pgcnt2 [db one {PRAGMA freelist_count}]
+set free_percent2 [percent $free_pgcnt2 $file_pgcnt]
+
+set file_pgcnt2 [expr {$inuse_pgcnt+$free_pgcnt2+$av_pgcnt}]
+
+set ntable [db eval {SELECT count(*)+1 FROM sqlite_master WHERE type='table'}]
+set nindex [db eval {SELECT count(*) FROM sqlite_master WHERE type='index'}]
+set sql {SELECT count(*) FROM sqlite_master WHERE name LIKE 'sqlite_autoindex%'}
+set nautoindex [db eval $sql]
+set nmanindex [expr {$nindex-$nautoindex}]
+
+# set total_payload [mem eval "SELECT sum(payload) FROM space_used"]
+set user_payload [mem one {SELECT int(sum(payload)) FROM space_used
+ WHERE NOT is_index AND name NOT LIKE 'sqlite_master'}]
+set user_percent [percent $user_payload $file_bytes]
+
+# Output the summary statistics calculated above.
+#
+puts "/** Disk-Space Utilization Report For $root_filename"
+puts ""
+statline {Page size in bytes} $pageSize
+statline {Pages in the whole file (measured)} $file_pgcnt
+statline {Pages in the whole file (calculated)} $file_pgcnt2
+statline {Pages that store data} $inuse_pgcnt $inuse_percent
+statline {Pages on the freelist (per header)} $free_pgcnt2 $free_percent2
+statline {Pages on the freelist (calculated)} $free_pgcnt $free_percent
+statline {Pages of auto-vacuum overhead} $av_pgcnt $av_percent
+statline {Number of tables in the database} $ntable
+statline {Number of indices} $nindex
+statline {Number of defined indices} $nmanindex
+statline {Number of implied indices} $nautoindex
+if {$isCompressed} {
+ statline {Size of uncompressed content in bytes} $file_bytes
+ set efficiency [percent $true_file_size $file_bytes]
+ statline {Size of compressed file on disk} $true_file_size $efficiency
+} else {
+ statline {Size of the file in bytes} $file_bytes
+}
+statline {Bytes of user payload stored} $user_payload $user_percent
+
+# Output table rankings
+#
+puts ""
+titleline "Page counts for all tables with their indices"
+puts ""
+mem eval {SELECT tblname, count(*) AS cnt,
+ int(sum(int_pages+leaf_pages+ovfl_pages)) AS size
+ FROM space_used GROUP BY tblname ORDER BY size+0 DESC, tblname} {} {
+ statline [string toupper $tblname] $size [percent $size $file_pgcnt]
+}
+puts ""
+titleline "Page counts for all tables and indices separately"
+puts ""
+mem eval {
+ SELECT
+ upper(name) AS nm,
+ int(int_pages+leaf_pages+ovfl_pages) AS size
+ FROM space_used
+ ORDER BY size+0 DESC, name} {} {
+ statline $nm $size [percent $size $file_pgcnt]
+}
+if {$isCompressed} {
+ puts ""
+ titleline "Bytes of disk space used after compression"
+ puts ""
+ set csum 0
+ mem eval {SELECT tblname,
+ int(sum(compressed_size)) +
+ $compressOverhead*sum(int_pages+leaf_pages+ovfl_pages)
+ AS csize
+ FROM space_used GROUP BY tblname ORDER BY csize+0 DESC, tblname} {} {
+ incr csum $csize
+ statline [string toupper $tblname] $csize [percent $csize $true_file_size]
+ }
+ set overhead [expr {$true_file_size - $csum}]
+ if {$overhead>0} {
+ statline {Header and free space} $overhead [percent $overhead $true_file_size]
+ }
+}
+
+# Output subreports
+#
+if {$nindex>0} {
+ subreport {All tables and indices} 1 0
+}
+subreport {All tables} {NOT is_index} 0
+if {$nindex>0} {
+ subreport {All indices} {is_index} 0
+}
+foreach tbl [mem eval {SELECT DISTINCT tblname name FROM space_used
+ ORDER BY name}] {
+ set qn [quote $tbl]
+ set name [string toupper $tbl]
+ set n [mem eval {SELECT count(*) FROM space_used WHERE tblname=$tbl}]
+ if {$n>1} {
+ set idxlist [mem eval "SELECT name FROM space_used
+ WHERE tblname='$qn' AND is_index
+ ORDER BY 1"]
+ subreport "Table $name and all its indices" "tblname='$qn'" 0
+ subreport "Table $name w/o any indices" "name='$qn'" 1
+ if {[llength $idxlist]>1} {
+ subreport "Indices of table $name" "tblname='$qn' AND is_index" 0
+ }
+ foreach idx $idxlist {
+ set qidx [quote $idx]
+ subreport "Index [string toupper $idx] of table $name" "name='$qidx'" 1
+ }
+ } else {
+ subreport "Table $name" "name='$qn'" 1
+ }
+}
+
+# Output instructions on what the numbers above mean.
+#
+puts ""
+titleline Definitions
+puts {
+Page size in bytes
+
+ The number of bytes in a single page of the database file.
+ Usually 1024.
+
+Number of pages in the whole file
+}
+puts " The number of $pageSize-byte pages that go into forming the complete
+ database"
+puts {
+Pages that store data
+
+ The number of pages that store data, either as primary B*Tree pages or
+ as overflow pages. The number at the right is the data pages divided by
+ the total number of pages in the file.
+
+Pages on the freelist
+
+ The number of pages that are not currently in use but are reserved for
+ future use. The percentage at the right is the number of freelist pages
+ divided by the total number of pages in the file.
+
+Pages of auto-vacuum overhead
+
+ The number of pages that store data used by the database to facilitate
+ auto-vacuum. This is zero for databases that do not support auto-vacuum.
+
+Number of tables in the database
+
+ The number of tables in the database, including the SQLITE_MASTER table
+ used to store schema information.
+
+Number of indices
+
+ The total number of indices in the database.
+
+Number of defined indices
+
+ The number of indices created using an explicit CREATE INDEX statement.
+
+Number of implied indices
+
+ The number of indices used to implement PRIMARY KEY or UNIQUE constraints
+ on tables.
+
+Size of the file in bytes
+
+ The total amount of disk space used by the entire database files.
+
+Bytes of user payload stored
+
+ The total number of bytes of user payload stored in the database. The
+ schema information in the SQLITE_MASTER table is not counted when
+ computing this number. The percentage at the right shows the payload
+ divided by the total file size.
+
+Percentage of total database
+
+ The amount of the complete database file that is devoted to storing
+ information described by this category.
+
+Number of entries
+
+ The total number of B-Tree key/value pairs stored under this category.
+
+Bytes of storage consumed
+
+ The total amount of disk space required to store all B-Tree entries
+ under this category. The is the total number of pages used times
+ the pages size.
+
+Bytes of payload
+
+ The amount of payload stored under this category. Payload is the data
+ part of table entries and the key part of index entries. The percentage
+ at the right is the bytes of payload divided by the bytes of storage
+ consumed.
+
+Bytes of metadata
+
+ The amount of formatting and structural information stored in the
+ table or index. Metadata includes the btree page header, the cell pointer
+ array, the size field for each cell, the left child pointer or non-leaf
+ cells, the overflow pointers for overflow cells, and the rowid value for
+ rowid table cells. In other words, metadata is everything that is neither
+ unused space nor content. The record header in the payload is counted as
+ content, not metadata.
+
+Average payload per entry
+
+ The average amount of payload on each entry. This is just the bytes of
+ payload divided by the number of entries.
+
+Average unused bytes per entry
+
+ The average amount of free space remaining on all pages under this
+ category on a per-entry basis. This is the number of unused bytes on
+ all pages divided by the number of entries.
+
+Non-sequential pages
+
+ The number of pages in the table or index that are out of sequence.
+ Many filesystems are optimized for sequential file access so a small
+ number of non-sequential pages might result in faster queries,
+ especially for larger database files that do not fit in the disk cache.
+ Note that after running VACUUM, the root page of each table or index is
+ at the beginning of the database file and all other pages are in a
+ separate part of the database file, resulting in a single non-
+ sequential page.
+
+Maximum payload per entry
+
+ The largest payload size of any entry.
+
+Entries that use overflow
+
+ The number of entries that user one or more overflow pages.
+
+Total pages used
+
+ This is the number of pages used to hold all information in the current
+ category. This is the sum of index, primary, and overflow pages.
+
+Index pages used
+
+ This is the number of pages in a table B-tree that hold only key (rowid)
+ information and no data.
+
+Primary pages used
+
+ This is the number of B-tree pages that hold both key and data.
+
+Overflow pages used
+
+ The total number of overflow pages used for this category.
+
+Unused bytes on index pages
+
+ The total number of bytes of unused space on all index pages. The
+ percentage at the right is the number of unused bytes divided by the
+ total number of bytes on index pages.
+
+Unused bytes on primary pages
+
+ The total number of bytes of unused space on all primary pages. The
+ percentage at the right is the number of unused bytes divided by the
+ total number of bytes on primary pages.
+
+Unused bytes on overflow pages
+
+ The total number of bytes of unused space on all overflow pages. The
+ percentage at the right is the number of unused bytes divided by the
+ total number of bytes on overflow pages.
+
+Unused bytes on all pages
+
+ The total number of bytes of unused space on all primary and overflow
+ pages. The percentage at the right is the number of unused bytes
+ divided by the total number of bytes.
+}
+
+# Output a dump of the in-memory database. This can be used for more
+# complex offline analysis.
+#
+titleline {}
+puts "The entire text of this report can be sourced into any SQL database"
+puts "engine for further analysis. All of the text above is an SQL comment."
+puts "The data used to generate this report follows:"
+puts "*/"
+puts "BEGIN;"
+puts $tabledef
+unset -nocomplain x
+mem eval {SELECT * FROM space_used} x {
+ puts -nonewline "INSERT INTO space_used VALUES"
+ set sep (
+ foreach col $x(*) {
+ set v $x($col)
+ if {$v=="" || ![string is double $v]} {set v '[quote $v]'}
+ puts -nonewline $sep$v
+ set sep ,
+ }
+ puts ");"
+}
+puts "COMMIT;"
+
+} err]} {
+ puts "ERROR: $err"
+ puts $errorInfo
+ exit 1
+}
--- origsrc/sqlite-autoconf-3300000/Makefile.am 2019-10-04 18:28:13.000000000 +0200
+++ src/sqlite-autoconf-3300000/Makefile.am 2019-10-08 14:46:46.800725900 +0200
@@ -1,15 +1,99 @@
+AM_CFLAGS = -DUSE_SYSTEM_SQLITE=1 -DSQLITE_ENABLE_COLUMN_METADATA=1 -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 -DSQLITE_ENABLE_FTS4=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_GEOPOLY=1 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 -DSQLITE_OMIT_LOOKASIDE=1 -DSQLITE_SECURE_DELETE=1 -DSQLITE_ENABLE_JSON1=1 -DSQLITE_USE_ALLOCA=1
-AM_CFLAGS = @BUILD_CFLAGS@
-lib_LTLIBRARIES = libsqlite3.la
+lib_LTLIBRARIES = libsqlite3.la libsqlite3amatch.la libsqlite3anycollseq.la \
+ libsqlite3carray.la libsqlite3closure.la libsqlite3compress.la \
+ libsqlite3completion.la libsqlite3csv.la libsqlite3eval.la \
+ libsqlite3fileio.la libsqlite3fuzzer.la libsqlite3ieee754.la \
+ libsqlite3memvfs.la libsqlite3nextchar.la libsqlite3percentile.la \
+ libsqlite3rbu.la libsqlite3regexp.la libsqlite3remember.la \
+ libsqlite3rot13.la libsqlite3series.la libsqlite3sha1.la \
+ libsqlite3shathree.la libsqlite3showauth.la libsqlite3spellfix.la \
+ libsqlite3stmt.la libsqlite3totype.la libsqlite3unionvtab.la \
+ libsqlite3vfslog.la libsqlite3vfsstat.la libsqlite3vtshim.la \
+ libsqlite3wholenumber.la libsqlite3icu.la
libsqlite3_la_SOURCES = sqlite3.c
-libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8
+libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3amatch_la_SOURCES = amatch.c
+libsqlite3amatch_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3anycollseq_la_SOURCES = anycollseq.c
+libsqlite3anycollseq_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3carray_la_SOURCES = carray.c
+libsqlite3carray_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3closure_la_SOURCES = closure.c
+libsqlite3closure_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3compress_la_SOURCES = compress.c
+libsqlite3compress_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc -lz
+libsqlite3completion_la_SOURCES = completion.c
+libsqlite3completion_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3csv_la_SOURCES = csv.c
+libsqlite3csv_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3eval_la_SOURCES = eval.c
+libsqlite3eval_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3fileio_la_SOURCES = fileio.c
+libsqlite3fileio_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3fuzzer_la_SOURCES = fuzzer.c
+libsqlite3fuzzer_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3icu_la_SOURCES = icu.c
+libsqlite3icu_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc -licui18n -licuuc
+libsqlite3ieee754_la_SOURCES = ieee754.c
+libsqlite3ieee754_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3memvfs_la_SOURCES = memvfs.c
+libsqlite3memvfs_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3nextchar_la_SOURCES = nextchar.c
+libsqlite3nextchar_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3percentile_la_SOURCES = percentile.c
+libsqlite3percentile_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3rbu_la_SOURCES = sqlite3rbu.c
+libsqlite3rbu_la_LIBADD = $(top_builddir)/libsqlite3.la
+libsqlite3rbu_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3rbu_la_DEPENDENCIES = $(top_builddir)/libsqlite3.la
+libsqlite3regexp_la_SOURCES = regexp.c
+libsqlite3regexp_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3remember_la_SOURCES = remember.c
+libsqlite3remember_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3rot13_la_SOURCES = rot13.c
+libsqlite3rot13_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3sha1_la_SOURCES = sha1.c
+libsqlite3sha1_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3shathree_la_SOURCES = shathree.c
+libsqlite3shathree_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3series_la_SOURCES = series.c
+libsqlite3series_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3showauth_la_SOURCES = showauth.c
+libsqlite3showauth_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3spellfix_la_SOURCES = spellfix.c
+libsqlite3spellfix_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3stmt_la_SOURCES = stmt.c
+libsqlite3stmt_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3totype_la_SOURCES = totype.c
+libsqlite3totype_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3unionvtab_la_SOURCES = unionvtab.c
+libsqlite3unionvtab_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3vfslog_la_SOURCES = vfslog.c
+libsqlite3vfslog_la_LIBADD = $(top_builddir)/libsqlite3.la
+libsqlite3vfslog_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3vfslog_la_DEPENDENCIES = $(top_builddir)/libsqlite3.la
+libsqlite3vtshim_la_SOURCES = vtshim.c
+libsqlite3vtshim_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3vfsstat_la_SOURCES = vfsstat.c
+libsqlite3vfsstat_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
+libsqlite3wholenumber_la_SOURCES = wholenumber.c
+libsqlite3wholenumber_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc
-bin_PROGRAMS = sqlite3
+bin_PROGRAMS = sqlite3 sqldiff rbu
sqlite3_SOURCES = shell.c sqlite3.h
EXTRA_sqlite3_SOURCES = sqlite3.c
-sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@
-sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@
-sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_STMTVTAB -DSQLITE_ENABLE_DBSTAT_VTAB $(SHELL_CFLAGS)
+sqlite3_LDADD = $(top_builddir)/libsqlite3vfslog.la @EXTRA_SHELL_OBJ@ @READLINE_LIBS@
+sqlite3_DEPENDENCIES = $(top_builddir)/libsqlite3vfslog.la @EXTRA_SHELL_OBJ@
+sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_STMTVTAB -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_HAVE_ZLIB $(SHELL_CFLAGS)
+sqldiff_SOURCES = sqldiff.c sqlite3.h
+sqldiff_LDADD = @EXTRA_SHELL_OBJ@
+sqldiff_DEPENDENCIES = @EXTRA_SHELL_OBJ@
+sqldiff_CFLAGS = $(AM_CFLAGS)
+rbu_SOURCES = rbu.c sqlite3.h
+rbu_LDADD = $(top_builddir)/libsqlite3rbu.la @EXTRA_SHELL_OBJ@
+rbu_DEPENDENCIES = $(top_builddir)/libsqlite3rbu.la @EXTRA_SHELL_OBJ@
+rbu_CFLAGS = $(AM_CFLAGS)
include_HEADERS = sqlite3.h sqlite3ext.h
--- origsrc/sqlite-autoconf-3300000/Makefile.msc 2019-10-04 18:28:13.000000000 +0200
+++ src/sqlite-autoconf-3300000/Makefile.msc 2019-03-05 13:14:40.396000000 +0100
@@ -73,7 +73,7 @@ API_ARMOR = 0
!IFNDEF NO_WARN
!IF $(USE_FULLWARN)!=0
NO_WARN = -wd4054 -wd4055 -wd4100 -wd4127 -wd4130 -wd4152 -wd4189 -wd4206
-NO_WARN = $(NO_WARN) -wd4210 -wd4232 -wd4244 -wd4305 -wd4306 -wd4702 -wd4706
+NO_WARN = $(NO_WARN) -wd4210 -wd4232 -wd4305 -wd4306 -wd4702 -wd4706
!ENDIF
!ENDIF
@@ -277,13 +277,6 @@ SQLITE3EXEPDB = /pdb:sqlite3sh.pdb
!IF $(MINIMAL_AMALGAMATION)==0
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1
-OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_GEOPOLY=1
-OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1=1
-OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
-OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
-OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1
-OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_INTROSPECTION_PRAGMAS=1
-OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1
!ENDIF
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
!ENDIF
@@ -433,9 +426,9 @@ UCRTLIBPATH = $(UCRTLIBPATH:\\=\)
# will run on the platform that is doing the build.
#
!IF $(USE_FULLWARN)!=0
-BCC = $(NCC) -nologo -W4 -Fd$*.pdb $(CCOPTS) $(BCCOPTS)
+BCC = $(NCC) -nologo -W4 $(CCOPTS) $(BCCOPTS)
!ELSE
-BCC = $(NCC) -nologo -W3 -Fd$*.pdb $(CCOPTS) $(BCCOPTS)
+BCC = $(NCC) -nologo -W3 $(CCOPTS) $(BCCOPTS)
!ENDIF
# Check if assembly code listings should be generated for the source
@@ -568,7 +561,6 @@ SHELL_CORE_DEP =
!ENDIF
!ENDIF
-
# This is the core library that the shell executable should link with.
#
!IFNDEF SHELL_CORE_LIB
@@ -808,7 +800,7 @@ BCC = $(BCC) -Zi
# Command line prefixes for compiling code, compiling resources,
# linking, etc.
#
-LTCOMPILE = $(TCC) -Fo$@ -Fd$*.pdb
+LTCOMPILE = $(TCC) -Fo$@
LTRCOMPILE = $(RCC) -r
LTLIB = lib.exe
LTLINK = $(TCC) -Fe$@
@@ -816,7 +808,7 @@ LTLINK = $(TCC) -Fe$@
# If requested, link to the RPCRT4 library.
#
!IF $(USE_RPCRT4_LIB)!=0
-LTLIBS = $(LTLIBS) rpcrt4.lib
+LTLINK = $(LTLINK) rpcrt4.lib
!ENDIF
# If a platform was set, force the linker to target that.
@@ -826,11 +818,6 @@ LTLIBS = $(LTLIBS) rpcrt4.lib
!IFDEF PLATFORM
LTLINKOPTS = /NOLOGO /MACHINE:$(PLATFORM)
LTLIBOPTS = /NOLOGO /MACHINE:$(PLATFORM)
-!ELSEIF "$(VISUALSTUDIOVERSION)"=="12.0" || \
- "$(VISUALSTUDIOVERSION)"=="14.0" || \
- "$(VISUALSTUDIOVERSION)"=="15.0"
-LTLINKOPTS = /NOLOGO /MACHINE:x86
-LTLIBOPTS = /NOLOGO /MACHINE:x86
!ELSE
LTLINKOPTS = /NOLOGO
LTLIBOPTS = /NOLOGO
@@ -940,25 +927,14 @@ LIBRESOBJS =
# when the shell is not being dynamically linked.
#
!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0
-SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1
-SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1
-SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1
-SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DESERIALIZE=1
+SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_SHELL_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS
!ENDIF
# This is the default Makefile target. The objects listed here
# are what get build when you type just "make" with no arguments.
#
-core: dll shell
-
-# Targets that require the Tcl library.
-#
-tcl: $(ALL_TCL_TARGETS)
-
-# This Makefile target builds all of the standard binaries.
-#
-all: core tcl
+all: dll shell
# Dynamic link library section.
#
@@ -978,11 +954,11 @@ Replace.exe:
sqlite3.def: Replace.exe $(LIBOBJ)
echo EXPORTS > sqlite3.def
dumpbin /all $(LIBOBJ) \
- | .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup|rebaser)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \
+ | .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \
| sort >> sqlite3.def
-$(SQLITE3EXE): shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H)
- $(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) shell.c $(SHELL_CORE_SRC) \
+$(SQLITE3EXE): $(TOP)\shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H)
+ $(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) $(TOP)\shell.c $(SHELL_CORE_SRC) \
/link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS)
@@ -997,7 +973,7 @@ sqlite3.lo: $(SQLITE3C)
!IF $(USE_RC)!=0
_HASHCHAR=^#
!IF ![echo !IFNDEF VERSION > rcver.vc] && \
- ![for /F "delims=" %V in ('type "$(SQLITE3H)" ^| "%SystemRoot%\System32\find.exe" "$(_HASHCHAR)define SQLITE_VERSION "') do (echo VERSION = ^^%V >> rcver.vc)] && \
+ ![for /F "delims=" %V in ('type "$(SQLITE3H)" ^| find "$(_HASHCHAR)define SQLITE_VERSION "') do (echo VERSION = ^^%V >> rcver.vc)] && \
![echo !ENDIF >> rcver.vc]
!INCLUDE rcver.vc
!ENDIF
--- origsrc/sqlite-autoconf-3300000/README.first 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/README.first 2019-03-05 13:14:40.406000000 +0100
@@ -0,0 +1,11 @@
+This directory contains components use to build an autoconf-ready package
+of the SQLite amalgamation: sqlite-autoconf-30XXXXXX.tar.gz
+
+To build the autoconf amalgamation, run from the top-level:
+
+ ./configure
+ make amalgamation-tarball
+
+The amalgamation-tarball target (also available in "main.mk") runs the
+script tool/mkautoconfamal.sh which does the work. Refer to that script
+for details.
--- origsrc/sqlite-autoconf-3300000/amatch.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/amatch.c 2019-10-08 13:42:19.069529400 +0200
@@ -0,0 +1,1515 @@
+/*
+** 2013-03-14
+**
+** 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 code for a demonstration virtual table that finds
+** "approximate matches" - strings from a finite set that are nearly the
+** same as a single input string. The virtual table is called "amatch".
+**
+** A amatch virtual table is created like this:
+**
+** CREATE VIRTUAL TABLE f USING approximate_match(
+** vocabulary_table=<tablename>, -- V
+** vocabulary_word=<columnname>, -- W
+** vocabulary_language=<columnname>, -- L
+** edit_distances=<edit-cost-table>
+** );
+**
+** When it is created, the new amatch table must be supplied with the
+** the name of a table V and columns V.W and V.L such that
+**
+** SELECT W FROM V WHERE L=$language
+**
+** returns the allowed vocabulary for the match. If the "vocabulary_language"
+** or L columnname is left unspecified or is an empty string, then no
+** filtering of the vocabulary by language is performed.
+**
+** For efficiency, it is essential that the vocabulary table be indexed:
+**
+** CREATE vocab_index ON V(W)
+**
+** A separate edit-cost-table provides scoring information that defines
+** what it means for one string to be "close" to another.
+**
+** The edit-cost-table must contain exactly four columns (more precisely,
+** the statement "SELECT * FROM <edit-cost-table>" must return records
+** that consist of four columns). It does not matter what the columns are
+** named.
+**
+** Each row in the edit-cost-table represents a single character
+** transformation going from user input to the vocabulary. The leftmost
+** column of the row (column 0) contains an integer identifier of the
+** language to which the transformation rule belongs (see "MULTIPLE LANGUAGES"
+** below). The second column of the row (column 1) contains the input
+** character or characters - the characters of user input. The third
+** column contains characters as they appear in the vocabulary table.
+** And the fourth column contains the integer cost of making the
+** transformation. For example:
+**
+** CREATE TABLE f_data(iLang, cFrom, cTo, Cost);
+** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, '', 'a', 100);
+** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, 'b', '', 87);
+** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, 'o', 'oe', 38);
+** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, 'oe', 'o', 40);
+**
+** The first row inserted into the edit-cost-table by the SQL script
+** above indicates that the cost of having an extra 'a' in the vocabulary
+** table that is missing in the user input 100. (All costs are integers.
+** Overall cost must not exceed 16777216.) The second INSERT statement
+** creates a rule saying that the cost of having a single letter 'b' in
+** user input which is missing in the vocabulary table is 87. The third
+** INSERT statement mean that the cost of matching an 'o' in user input
+** against an 'oe' in the vocabulary table is 38. And so forth.
+**
+** The following rules are special:
+**
+** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, '?', '', 97);
+** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, '', '?', 98);
+** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, '?', '?', 99);
+**
+** The '?' to '' rule is the cost of having any single character in the input
+** that is not found in the vocabular. The '' to '?' rule is the cost of
+** having a character in the vocabulary table that is missing from input.
+** And the '?' to '?' rule is the cost of doing an arbitrary character
+** substitution. These three generic rules apply across all languages.
+** In other words, the iLang field is ignored for the generic substitution
+** rules. If more than one cost is given for a generic substitution rule,
+** then the lowest cost is used.
+**
+** Once it has been created, the amatch virtual table can be queried
+** as follows:
+**
+** SELECT word, distance FROM f
+** WHERE word MATCH 'abcdefg'
+** AND distance<200;
+**
+** This query outputs the strings contained in the T(F) field that
+** are close to "abcdefg" and in order of increasing distance. No string
+** is output more than once. If there are multiple ways to transform the
+** target string ("abcdefg") into a string in the vocabulary table then
+** the lowest cost transform is the one that is returned. In this example,
+** the search is limited to strings with a total distance of less than 200.
+**
+** For efficiency, it is important to put tight bounds on the distance.
+** The time and memory space needed to perform this query is exponential
+** in the maximum distance. A good rule of thumb is to limit the distance
+** to no more than 1.5 or 2 times the maximum cost of any rule in the
+** edit-cost-table.
+**
+** The amatch is a read-only table. Any attempt to DELETE, INSERT, or
+** UPDATE on a amatch table will throw an error.
+**
+** It is important to put some kind of a limit on the amatch output. This
+** can be either in the form of a LIMIT clause at the end of the query,
+** or better, a "distance<NNN" constraint where NNN is some number. The
+** running time and memory requirement is exponential in the value of NNN
+** so you want to make sure that NNN is not too big. A value of NNN that
+** is about twice the average transformation cost seems to give good results.
+**
+** The amatch table can be useful for tasks such as spelling correction.
+** Suppose all allowed words are in table vocabulary(w). Then one would create
+** an amatch virtual table like this:
+**
+** CREATE VIRTUAL TABLE ex1 USING amatch(
+** vocabtable=vocabulary,
+** vocabcolumn=w,
+** edit_distances=ec1
+** );
+**
+** Then given an input word $word, look up close spellings this way:
+**
+** SELECT word, distance FROM ex1
+** WHERE word MATCH $word AND distance<200;
+**
+** MULTIPLE LANGUAGES
+**
+** Normally, the "iLang" value associated with all character transformations
+** in the edit-cost-table is zero. However, if required, the amatch
+** virtual table allows multiple languages to be defined. Each query uses
+** only a single iLang value. This allows, for example, a single
+** amatch table to support multiple languages.
+**
+** By default, only the rules with iLang=0 are used. To specify an
+** alternative language, a "language = ?" expression must be added to the
+** WHERE clause of a SELECT, where ? is the integer identifier of the desired
+** language. For example:
+**
+** SELECT word, distance FROM ex1
+** WHERE word MATCH $word
+** AND distance<=200
+** AND language=1 -- Specify use language 1 instead of 0
+**
+** If no "language = ?" constraint is specified in the WHERE clause, language
+** 0 is used.
+**
+** LIMITS
+**
+** The maximum language number is 2147483647. The maximum length of either
+** of the strings in the second or third column of the amatch data table
+** is 50 bytes. The maximum cost on a rule is 1000.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/*
+** Forward declaration of objects used by this implementation
+*/
+typedef struct amatch_vtab amatch_vtab;
+typedef struct amatch_cursor amatch_cursor;
+typedef struct amatch_rule amatch_rule;
+typedef struct amatch_word amatch_word;
+typedef struct amatch_avl amatch_avl;
+
+
+/*****************************************************************************
+** AVL Tree implementation
+*/
+/*
+** Objects that want to be members of the AVL tree should embedded an
+** instance of this structure.
+*/
+struct amatch_avl {
+ amatch_word *pWord; /* Points to the object being stored in the tree */
+ char *zKey; /* Key. zero-terminated string. Must be unique */
+ amatch_avl *pBefore; /* Other elements less than zKey */
+ amatch_avl *pAfter; /* Other elements greater than zKey */
+ amatch_avl *pUp; /* Parent element */
+ short int height; /* Height of this node. Leaf==1 */
+ short int imbalance; /* Height difference between pBefore and pAfter */
+};
+
+/* Recompute the amatch_avl.height and amatch_avl.imbalance fields for p.
+** Assume that the children of p have correct heights.
+*/
+static void amatchAvlRecomputeHeight(amatch_avl *p){
+ short int hBefore = p->pBefore ? p->pBefore->height : 0;
+ short int hAfter = p->pAfter ? p->pAfter->height : 0;
+ p->imbalance = hBefore - hAfter; /* -: pAfter higher. +: pBefore higher */
+ p->height = (hBefore>hAfter ? hBefore : hAfter)+1;
+}
+
+/*
+** P B
+** / \ / \
+** B Z ==> X P
+** / \ / \
+** X Y Y Z
+**
+*/
+static amatch_avl *amatchAvlRotateBefore(amatch_avl *pP){
+ amatch_avl *pB = pP->pBefore;
+ amatch_avl *pY = pB->pAfter;
+ pB->pUp = pP->pUp;
+ pB->pAfter = pP;
+ pP->pUp = pB;
+ pP->pBefore = pY;
+ if( pY ) pY->pUp = pP;
+ amatchAvlRecomputeHeight(pP);
+ amatchAvlRecomputeHeight(pB);
+ return pB;
+}
+
+/*
+** P A
+** / \ / \
+** X A ==> P Z
+** / \ / \
+** Y Z X Y
+**
+*/
+static amatch_avl *amatchAvlRotateAfter(amatch_avl *pP){
+ amatch_avl *pA = pP->pAfter;
+ amatch_avl *pY = pA->pBefore;
+ pA->pUp = pP->pUp;
+ pA->pBefore = pP;
+ pP->pUp = pA;
+ pP->pAfter = pY;
+ if( pY ) pY->pUp = pP;
+ amatchAvlRecomputeHeight(pP);
+ amatchAvlRecomputeHeight(pA);
+ return pA;
+}
+
+/*
+** Return a pointer to the pBefore or pAfter pointer in the parent
+** of p that points to p. Or if p is the root node, return pp.
+*/
+static amatch_avl **amatchAvlFromPtr(amatch_avl *p, amatch_avl **pp){
+ amatch_avl *pUp = p->pUp;
+ if( pUp==0 ) return pp;
+ if( pUp->pAfter==p ) return &pUp->pAfter;
+ return &pUp->pBefore;
+}
+
+/*
+** Rebalance all nodes starting with p and working up to the root.
+** Return the new root.
+*/
+static amatch_avl *amatchAvlBalance(amatch_avl *p){
+ amatch_avl *pTop = p;
+ amatch_avl **pp;
+ while( p ){
+ amatchAvlRecomputeHeight(p);
+ if( p->imbalance>=2 ){
+ amatch_avl *pB = p->pBefore;
+ if( pB->imbalance<0 ) p->pBefore = amatchAvlRotateAfter(pB);
+ pp = amatchAvlFromPtr(p,&p);
+ p = *pp = amatchAvlRotateBefore(p);
+ }else if( p->imbalance<=(-2) ){
+ amatch_avl *pA = p->pAfter;
+ if( pA->imbalance>0 ) p->pAfter = amatchAvlRotateBefore(pA);
+ pp = amatchAvlFromPtr(p,&p);
+ p = *pp = amatchAvlRotateAfter(p);
+ }
+ pTop = p;
+ p = p->pUp;
+ }
+ return pTop;
+}
+
+/* Search the tree rooted at p for an entry with zKey. Return a pointer
+** to the entry or return NULL.
+*/
+static amatch_avl *amatchAvlSearch(amatch_avl *p, const char *zKey){
+ int c;
+ while( p && (c = strcmp(zKey, p->zKey))!=0 ){
+ p = (c<0) ? p->pBefore : p->pAfter;
+ }
+ return p;
+}
+
+/* Find the first node (the one with the smallest key).
+*/
+static amatch_avl *amatchAvlFirst(amatch_avl *p){
+ if( p ) while( p->pBefore ) p = p->pBefore;
+ return p;
+}
+
+#if 0 /* NOT USED */
+/* Return the node with the next larger key after p.
+*/
+static amatch_avl *amatchAvlNext(amatch_avl *p){
+ amatch_avl *pPrev = 0;
+ while( p && p->pAfter==pPrev ){
+ pPrev = p;
+ p = p->pUp;
+ }
+ if( p && pPrev==0 ){
+ p = amatchAvlFirst(p->pAfter);
+ }
+ return p;
+}
+#endif
+
+#if 0 /* NOT USED */
+/* Verify AVL tree integrity
+*/
+static int amatchAvlIntegrity(amatch_avl *pHead){
+ amatch_avl *p;
+ if( pHead==0 ) return 1;
+ if( (p = pHead->pBefore)!=0 ){
+ assert( p->pUp==pHead );
+ assert( amatchAvlIntegrity(p) );
+ assert( strcmp(p->zKey, pHead->zKey)<0 );
+ while( p->pAfter ) p = p->pAfter;
+ assert( strcmp(p->zKey, pHead->zKey)<0 );
+ }
+ if( (p = pHead->pAfter)!=0 ){
+ assert( p->pUp==pHead );
+ assert( amatchAvlIntegrity(p) );
+ assert( strcmp(p->zKey, pHead->zKey)>0 );
+ p = amatchAvlFirst(p);
+ assert( strcmp(p->zKey, pHead->zKey)>0 );
+ }
+ return 1;
+}
+static int amatchAvlIntegrity2(amatch_avl *pHead){
+ amatch_avl *p, *pNext;
+ for(p=amatchAvlFirst(pHead); p; p=pNext){
+ pNext = amatchAvlNext(p);
+ if( pNext==0 ) break;
+ assert( strcmp(p->zKey, pNext->zKey)<0 );
+ }
+ return 1;
+}
+#endif
+
+/* Insert a new node pNew. Return NULL on success. If the key is not
+** unique, then do not perform the insert but instead leave pNew unchanged
+** and return a pointer to an existing node with the same key.
+*/
+static amatch_avl *amatchAvlInsert(amatch_avl **ppHead, amatch_avl *pNew){
+ int c;
+ amatch_avl *p = *ppHead;
+ if( p==0 ){
+ p = pNew;
+ pNew->pUp = 0;
+ }else{
+ while( p ){
+ c = strcmp(pNew->zKey, p->zKey);
+ if( c<0 ){
+ if( p->pBefore ){
+ p = p->pBefore;
+ }else{
+ p->pBefore = pNew;
+ pNew->pUp = p;
+ break;
+ }
+ }else if( c>0 ){
+ if( p->pAfter ){
+ p = p->pAfter;
+ }else{
+ p->pAfter = pNew;
+ pNew->pUp = p;
+ break;
+ }
+ }else{
+ return p;
+ }
+ }
+ }
+ pNew->pBefore = 0;
+ pNew->pAfter = 0;
+ pNew->height = 1;
+ pNew->imbalance = 0;
+ *ppHead = amatchAvlBalance(p);
+ /* assert( amatchAvlIntegrity(*ppHead) ); */
+ /* assert( amatchAvlIntegrity2(*ppHead) ); */
+ return 0;
+}
+
+/* Remove node pOld from the tree. pOld must be an element of the tree or
+** the AVL tree will become corrupt.
+*/
+static void amatchAvlRemove(amatch_avl **ppHead, amatch_avl *pOld){
+ amatch_avl **ppParent;
+ amatch_avl *pBalance = 0;
+ /* assert( amatchAvlSearch(*ppHead, pOld->zKey)==pOld ); */
+ ppParent = amatchAvlFromPtr(pOld, ppHead);
+ if( pOld->pBefore==0 && pOld->pAfter==0 ){
+ *ppParent = 0;
+ pBalance = pOld->pUp;
+ }else if( pOld->pBefore && pOld->pAfter ){
+ amatch_avl *pX, *pY;
+ pX = amatchAvlFirst(pOld->pAfter);
+ *amatchAvlFromPtr(pX, 0) = pX->pAfter;
+ if( pX->pAfter ) pX->pAfter->pUp = pX->pUp;
+ pBalance = pX->pUp;
+ pX->pAfter = pOld->pAfter;
+ if( pX->pAfter ){
+ pX->pAfter->pUp = pX;
+ }else{
+ assert( pBalance==pOld );
+ pBalance = pX;
+ }
+ pX->pBefore = pY = pOld->pBefore;
+ if( pY ) pY->pUp = pX;
+ pX->pUp = pOld->pUp;
+ *ppParent = pX;
+ }else if( pOld->pBefore==0 ){
+ *ppParent = pBalance = pOld->pAfter;
+ pBalance->pUp = pOld->pUp;
+ }else if( pOld->pAfter==0 ){
+ *ppParent = pBalance = pOld->pBefore;
+ pBalance->pUp = pOld->pUp;
+ }
+ *ppHead = amatchAvlBalance(pBalance);
+ pOld->pUp = 0;
+ pOld->pBefore = 0;
+ pOld->pAfter = 0;
+ /* assert( amatchAvlIntegrity(*ppHead) ); */
+ /* assert( amatchAvlIntegrity2(*ppHead) ); */
+}
+/*
+** End of the AVL Tree implementation
+******************************************************************************/
+
+
+/*
+** Various types.
+**
+** amatch_cost is the "cost" of an edit operation.
+**
+** amatch_len is the length of a matching string.
+**
+** amatch_langid is an ruleset identifier.
+*/
+typedef int amatch_cost;
+typedef signed char amatch_len;
+typedef int amatch_langid;
+
+/*
+** Limits
+*/
+#define AMATCH_MX_LENGTH 50 /* Maximum length of a rule string */
+#define AMATCH_MX_LANGID 2147483647 /* Maximum rule ID */
+#define AMATCH_MX_COST 1000 /* Maximum single-rule cost */
+
+/*
+** A match or partial match
+*/
+struct amatch_word {
+ amatch_word *pNext; /* Next on a list of all amatch_words */
+ amatch_avl sCost; /* Linkage of this node into the cost tree */
+ amatch_avl sWord; /* Linkage of this node into the word tree */
+ amatch_cost rCost; /* Cost of the match so far */
+ int iSeq; /* Sequence number */
+ char zCost[10]; /* Cost key (text rendering of rCost) */
+ short int nMatch; /* Input characters matched */
+ char zWord[4]; /* Text of the word. Extra space appended as needed */
+};
+
+/*
+** Each transformation rule is stored as an instance of this object.
+** All rules are kept on a linked list sorted by rCost.
+*/
+struct amatch_rule {
+ amatch_rule *pNext; /* Next rule in order of increasing rCost */
+ char *zFrom; /* Transform from (a string from user input) */
+ amatch_cost rCost; /* Cost of this transformation */
+ amatch_langid iLang; /* The langauge to which this rule belongs */
+ amatch_len nFrom, nTo; /* Length of the zFrom and zTo strings */
+ char zTo[4]; /* Tranform to V.W value (extra space appended) */
+};
+
+/*
+** A amatch virtual-table object
+*/
+struct amatch_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ char *zClassName; /* Name of this class. Default: "amatch" */
+ char *zDb; /* Name of database. (ex: "main") */
+ char *zSelf; /* Name of this virtual table */
+ char *zCostTab; /* Name of edit-cost-table */
+ char *zVocabTab; /* Name of vocabulary table */
+ char *zVocabWord; /* Name of vocabulary table word column */
+ char *zVocabLang; /* Name of vocabulary table language column */
+ amatch_rule *pRule; /* All active rules in this amatch */
+ amatch_cost rIns; /* Generic insertion cost '' -> ? */
+ amatch_cost rDel; /* Generic deletion cost ? -> '' */
+ amatch_cost rSub; /* Generic substitution cost ? -> ? */
+ sqlite3 *db; /* The database connection */
+ sqlite3_stmt *pVCheck; /* Query to check zVocabTab */
+ int nCursor; /* Number of active cursors */
+};
+
+/* A amatch cursor object */
+struct amatch_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3_int64 iRowid; /* The rowid of the current word */
+ amatch_langid iLang; /* Use this language ID */
+ amatch_cost rLimit; /* Maximum cost of any term */
+ int nBuf; /* Space allocated for zBuf */
+ int oomErr; /* True following an OOM error */
+ int nWord; /* Number of amatch_word objects */
+ char *zBuf; /* Temp-use buffer space */
+ char *zInput; /* Input word to match against */
+ amatch_vtab *pVtab; /* The virtual table this cursor belongs to */
+ amatch_word *pAllWords; /* List of all amatch_word objects */
+ amatch_word *pCurrent; /* Most recent solution */
+ amatch_avl *pCost; /* amatch_word objects keyed by iCost */
+ amatch_avl *pWord; /* amatch_word objects keyed by zWord */
+};
+
+/*
+** The two input rule lists are both sorted in order of increasing
+** cost. Merge them together into a single list, sorted by cost, and
+** return a pointer to the head of that list.
+*/
+static amatch_rule *amatchMergeRules(amatch_rule *pA, amatch_rule *pB){
+ amatch_rule head;
+ amatch_rule *pTail;
+
+ pTail = &head;
+ while( pA && pB ){
+ if( pA->rCost<=pB->rCost ){
+ pTail->pNext = pA;
+ pTail = pA;
+ pA = pA->pNext;
+ }else{
+ pTail->pNext = pB;
+ pTail = pB;
+ pB = pB->pNext;
+ }
+ }
+ if( pA==0 ){
+ pTail->pNext = pB;
+ }else{
+ pTail->pNext = pA;
+ }
+ return head.pNext;
+}
+
+/*
+** Statement pStmt currently points to a row in the amatch data table. This
+** function allocates and populates a amatch_rule structure according to
+** the content of the row.
+**
+** If successful, *ppRule is set to point to the new object and SQLITE_OK
+** is returned. Otherwise, *ppRule is zeroed, *pzErr may be set to point
+** to an error message and an SQLite error code returned.
+*/
+static int amatchLoadOneRule(
+ amatch_vtab *p, /* Fuzzer virtual table handle */
+ sqlite3_stmt *pStmt, /* Base rule on statements current row */
+ amatch_rule **ppRule, /* OUT: New rule object */
+ char **pzErr /* OUT: Error message */
+){
+ sqlite3_int64 iLang = sqlite3_column_int64(pStmt, 0);
+ const char *zFrom = (const char *)sqlite3_column_text(pStmt, 1);
+ const char *zTo = (const char *)sqlite3_column_text(pStmt, 2);
+ amatch_cost rCost = sqlite3_column_int(pStmt, 3);
+
+ int rc = SQLITE_OK; /* Return code */
+ int nFrom; /* Size of string zFrom, in bytes */
+ int nTo; /* Size of string zTo, in bytes */
+ amatch_rule *pRule = 0; /* New rule object to return */
+
+ if( zFrom==0 ) zFrom = "";
+ if( zTo==0 ) zTo = "";
+ nFrom = (int)strlen(zFrom);
+ nTo = (int)strlen(zTo);
+
+ /* Silently ignore null transformations */
+ if( strcmp(zFrom, zTo)==0 ){
+ if( zFrom[0]=='?' && zFrom[1]==0 ){
+ if( p->rSub==0 || p->rSub>rCost ) p->rSub = rCost;
+ }
+ *ppRule = 0;
+ return SQLITE_OK;
+ }
+
+ if( rCost<=0 || rCost>AMATCH_MX_COST ){
+ *pzErr = sqlite3_mprintf("%s: cost must be between 1 and %d",
+ p->zClassName, AMATCH_MX_COST
+ );
+ rc = SQLITE_ERROR;
+ }else
+ if( nFrom>AMATCH_MX_LENGTH || nTo>AMATCH_MX_LENGTH ){
+ *pzErr = sqlite3_mprintf("%s: maximum string length is %d",
+ p->zClassName, AMATCH_MX_LENGTH
+ );
+ rc = SQLITE_ERROR;
+ }else
+ if( iLang<0 || iLang>AMATCH_MX_LANGID ){
+ *pzErr = sqlite3_mprintf("%s: iLang must be between 0 and %d",
+ p->zClassName, AMATCH_MX_LANGID
+ );
+ rc = SQLITE_ERROR;
+ }else
+ if( strcmp(zFrom,"")==0 && strcmp(zTo,"?")==0 ){
+ if( p->rIns==0 || p->rIns>rCost ) p->rIns = rCost;
+ }else
+ if( strcmp(zFrom,"?")==0 && strcmp(zTo,"")==0 ){
+ if( p->rDel==0 || p->rDel>rCost ) p->rDel = rCost;
+ }else
+ {
+ pRule = sqlite3_malloc( sizeof(*pRule) + nFrom + nTo );
+ if( pRule==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(pRule, 0, sizeof(*pRule));
+ pRule->zFrom = &pRule->zTo[nTo+1];
+ pRule->nFrom = (amatch_len)nFrom;
+ memcpy(pRule->zFrom, zFrom, nFrom+1);
+ memcpy(pRule->zTo, zTo, nTo+1);
+ pRule->nTo = (amatch_len)nTo;
+ pRule->rCost = rCost;
+ pRule->iLang = (int)iLang;
+ }
+ }
+
+ *ppRule = pRule;
+ return rc;
+}
+
+/*
+** Free all the content in the edit-cost-table
+*/
+static void amatchFreeRules(amatch_vtab *p){
+ while( p->pRule ){
+ amatch_rule *pRule = p->pRule;
+ p->pRule = pRule->pNext;
+ sqlite3_free(pRule);
+ }
+ p->pRule = 0;
+}
+
+/*
+** Load the content of the amatch data table into memory.
+*/
+static int amatchLoadRules(
+ sqlite3 *db, /* Database handle */
+ amatch_vtab *p, /* Virtual amatch table to configure */
+ char **pzErr /* OUT: Error message */
+){
+ int rc = SQLITE_OK; /* Return code */
+ char *zSql; /* SELECT used to read from rules table */
+ amatch_rule *pHead = 0;
+
+ zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", p->zDb, p->zCostTab);
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ int rc2; /* finalize() return code */
+ sqlite3_stmt *pStmt = 0;
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+ if( rc!=SQLITE_OK ){
+ *pzErr = sqlite3_mprintf("%s: %s", p->zClassName, sqlite3_errmsg(db));
+ }else if( sqlite3_column_count(pStmt)!=4 ){
+ *pzErr = sqlite3_mprintf("%s: %s has %d columns, expected 4",
+ p->zClassName, p->zCostTab, sqlite3_column_count(pStmt)
+ );
+ rc = SQLITE_ERROR;
+ }else{
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ amatch_rule *pRule = 0;
+ rc = amatchLoadOneRule(p, pStmt, &pRule, pzErr);
+ if( pRule ){
+ pRule->pNext = pHead;
+ pHead = pRule;
+ }
+ }
+ }
+ rc2 = sqlite3_finalize(pStmt);
+ if( rc==SQLITE_OK ) rc = rc2;
+ }
+ sqlite3_free(zSql);
+
+ /* All rules are now in a singly linked list starting at pHead. This
+ ** block sorts them by cost and then sets amatch_vtab.pRule to point to
+ ** point to the head of the sorted list.
+ */
+ if( rc==SQLITE_OK ){
+ unsigned int i;
+ amatch_rule *pX;
+ amatch_rule *a[15];
+ for(i=0; i<sizeof(a)/sizeof(a[0]); i++) a[i] = 0;
+ while( (pX = pHead)!=0 ){
+ pHead = pX->pNext;
+ pX->pNext = 0;
+ for(i=0; a[i] && i<sizeof(a)/sizeof(a[0])-1; i++){
+ pX = amatchMergeRules(a[i], pX);
+ a[i] = 0;
+ }
+ a[i] = amatchMergeRules(a[i], pX);
+ }
+ for(pX=a[0], i=1; i<sizeof(a)/sizeof(a[0]); i++){
+ pX = amatchMergeRules(a[i], pX);
+ }
+ p->pRule = amatchMergeRules(p->pRule, pX);
+ }else{
+ /* An error has occurred. Setting p->pRule to point to the head of the
+ ** allocated list ensures that the list will be cleaned up in this case.
+ */
+ assert( p->pRule==0 );
+ p->pRule = pHead;
+ }
+
+ return rc;
+}
+
+/*
+** This function converts an SQL quoted string into an unquoted string
+** and returns a pointer to a buffer allocated using sqlite3_malloc()
+** containing the result. The caller should eventually free this buffer
+** using sqlite3_free.
+**
+** Examples:
+**
+** "abc" becomes abc
+** 'xyz' becomes xyz
+** [pqr] becomes pqr
+** `mno` becomes mno
+*/
+static char *amatchDequote(const char *zIn){
+ size_t nIn; /* Size of input string, in bytes */
+ char *zOut; /* Output (dequoted) string */
+
+ nIn = strlen(zIn);
+ zOut = sqlite3_malloc(nIn+1);
+ if( zOut ){
+ char q = zIn[0]; /* Quote character (if any ) */
+
+ if( q!='[' && q!= '\'' && q!='"' && q!='`' ){
+ memcpy(zOut, zIn, (size_t)(nIn+1));
+ }else{
+ int iOut = 0; /* Index of next byte to write to output */
+ int iIn; /* Index of next byte to read from input */
+
+ if( q=='[' ) q = ']';
+ for(iIn=1; iIn<nIn; iIn++){
+ if( zIn[iIn]==q ) iIn++;
+ zOut[iOut++] = zIn[iIn];
+ }
+ }
+ assert( (int)strlen(zOut)<=nIn );
+ }
+ return zOut;
+}
+
+/*
+** Deallocate the pVCheck prepared statement.
+*/
+static void amatchVCheckClear(amatch_vtab *p){
+ if( p->pVCheck ){
+ sqlite3_finalize(p->pVCheck);
+ p->pVCheck = 0;
+ }
+}
+
+/*
+** Deallocate an amatch_vtab object
+*/
+static void amatchFree(amatch_vtab *p){
+ if( p ){
+ amatchFreeRules(p);
+ amatchVCheckClear(p);
+ sqlite3_free(p->zClassName);
+ sqlite3_free(p->zDb);
+ sqlite3_free(p->zCostTab);
+ sqlite3_free(p->zVocabTab);
+ sqlite3_free(p->zVocabWord);
+ sqlite3_free(p->zVocabLang);
+ sqlite3_free(p->zSelf);
+ memset(p, 0, sizeof(*p));
+ sqlite3_free(p);
+ }
+}
+
+/*
+** xDisconnect/xDestroy method for the amatch module.
+*/
+static int amatchDisconnect(sqlite3_vtab *pVtab){
+ amatch_vtab *p = (amatch_vtab*)pVtab;
+ assert( p->nCursor==0 );
+ amatchFree(p);
+ return SQLITE_OK;
+}
+
+/*
+** Check to see if the argument is of the form:
+**
+** KEY = VALUE
+**
+** If it is, return a pointer to the first character of VALUE.
+** If not, return NULL. Spaces around the = are ignored.
+*/
+static const char *amatchValueOfKey(const char *zKey, const char *zStr){
+ int nKey = (int)strlen(zKey);
+ int nStr = (int)strlen(zStr);
+ int i;
+ if( nStr<nKey+1 ) return 0;
+ if( memcmp(zStr, zKey, nKey)!=0 ) return 0;
+ for(i=nKey; isspace((unsigned char)zStr[i]); i++){}
+ if( zStr[i]!='=' ) return 0;
+ i++;
+ while( isspace((unsigned char)zStr[i]) ){ i++; }
+ return zStr+i;
+}
+
+/*
+** xConnect/xCreate method for the amatch module. Arguments are:
+**
+** argv[0] -> module name ("approximate_match")
+** argv[1] -> database name
+** argv[2] -> table name
+** argv[3...] -> arguments
+*/
+static int amatchConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ int rc = SQLITE_OK; /* Return code */
+ amatch_vtab *pNew = 0; /* New virtual table */
+ const char *zModule = argv[0];
+ const char *zDb = argv[1];
+ const char *zVal;
+ int i;
+
+ (void)pAux;
+ *ppVtab = 0;
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ if( pNew==0 ) return SQLITE_NOMEM;
+ rc = SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->db = db;
+ pNew->zClassName = sqlite3_mprintf("%s", zModule);
+ if( pNew->zClassName==0 ) goto amatchConnectError;
+ pNew->zDb = sqlite3_mprintf("%s", zDb);
+ if( pNew->zDb==0 ) goto amatchConnectError;
+ pNew->zSelf = sqlite3_mprintf("%s", argv[2]);
+ if( pNew->zSelf==0 ) goto amatchConnectError;
+ for(i=3; i<argc; i++){
+ zVal = amatchValueOfKey("vocabulary_table", argv[i]);
+ if( zVal ){
+ sqlite3_free(pNew->zVocabTab);
+ pNew->zVocabTab = amatchDequote(zVal);
+ if( pNew->zVocabTab==0 ) goto amatchConnectError;
+ continue;
+ }
+ zVal = amatchValueOfKey("vocabulary_word", argv[i]);
+ if( zVal ){
+ sqlite3_free(pNew->zVocabWord);
+ pNew->zVocabWord = amatchDequote(zVal);
+ if( pNew->zVocabWord==0 ) goto amatchConnectError;
+ continue;
+ }
+ zVal = amatchValueOfKey("vocabulary_language", argv[i]);
+ if( zVal ){
+ sqlite3_free(pNew->zVocabLang);
+ pNew->zVocabLang = amatchDequote(zVal);
+ if( pNew->zVocabLang==0 ) goto amatchConnectError;
+ continue;
+ }
+ zVal = amatchValueOfKey("edit_distances", argv[i]);
+ if( zVal ){
+ sqlite3_free(pNew->zCostTab);
+ pNew->zCostTab = amatchDequote(zVal);
+ if( pNew->zCostTab==0 ) goto amatchConnectError;
+ continue;
+ }
+ *pzErr = sqlite3_mprintf("unrecognized argument: [%s]\n", argv[i]);
+ amatchFree(pNew);
+ *ppVtab = 0;
+ return SQLITE_ERROR;
+ }
+ rc = SQLITE_OK;
+ if( pNew->zCostTab==0 ){
+ *pzErr = sqlite3_mprintf("no edit_distances table specified");
+ rc = SQLITE_ERROR;
+ }else{
+ rc = amatchLoadRules(db, pNew, pzErr);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x(word,distance,language,"
+ "command HIDDEN,nword HIDDEN)"
+ );
+#define AMATCH_COL_WORD 0
+#define AMATCH_COL_DISTANCE 1
+#define AMATCH_COL_LANGUAGE 2
+#define AMATCH_COL_COMMAND 3
+#define AMATCH_COL_NWORD 4
+ }
+ if( rc!=SQLITE_OK ){
+ amatchFree(pNew);
+ }
+ *ppVtab = &pNew->base;
+ return rc;
+
+amatchConnectError:
+ amatchFree(pNew);
+ return rc;
+}
+
+/*
+** Open a new amatch cursor.
+*/
+static int amatchOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+ amatch_vtab *p = (amatch_vtab*)pVTab;
+ amatch_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ pCur->pVtab = p;
+ *ppCursor = &pCur->base;
+ p->nCursor++;
+ return SQLITE_OK;
+}
+
+/*
+** Free up all the memory allocated by a cursor. Set it rLimit to 0
+** to indicate that it is at EOF.
+*/
+static void amatchClearCursor(amatch_cursor *pCur){
+ amatch_word *pWord, *pNextWord;
+ for(pWord=pCur->pAllWords; pWord; pWord=pNextWord){
+ pNextWord = pWord->pNext;
+ sqlite3_free(pWord);
+ }
+ pCur->pAllWords = 0;
+ sqlite3_free(pCur->zInput);
+ pCur->zInput = 0;
+ sqlite3_free(pCur->zBuf);
+ pCur->zBuf = 0;
+ pCur->nBuf = 0;
+ pCur->pCost = 0;
+ pCur->pWord = 0;
+ pCur->pCurrent = 0;
+ pCur->rLimit = 1000000;
+ pCur->iLang = 0;
+ pCur->nWord = 0;
+}
+
+/*
+** Close a amatch cursor.
+*/
+static int amatchClose(sqlite3_vtab_cursor *cur){
+ amatch_cursor *pCur = (amatch_cursor *)cur;
+ amatchClearCursor(pCur);
+ pCur->pVtab->nCursor--;
+ sqlite3_free(pCur);
+ return SQLITE_OK;
+}
+
+/*
+** Render a 24-bit unsigned integer as a 4-byte base-64 number.
+*/
+static void amatchEncodeInt(int x, char *z){
+ static const char a[] =
+ "0123456789"
+ "ABCDEFGHIJ"
+ "KLMNOPQRST"
+ "UVWXYZ^abc"
+ "defghijklm"
+ "nopqrstuvw"
+ "xyz~";
+ z[0] = a[(x>>18)&0x3f];
+ z[1] = a[(x>>12)&0x3f];
+ z[2] = a[(x>>6)&0x3f];
+ z[3] = a[x&0x3f];
+}
+
+/*
+** Write the zCost[] field for a amatch_word object
+*/
+static void amatchWriteCost(amatch_word *pWord){
+ amatchEncodeInt(pWord->rCost, pWord->zCost);
+ amatchEncodeInt(pWord->iSeq, pWord->zCost+4);
+ pWord->zCost[8] = 0;
+}
+
+/* Circumvent compiler warnings about the use of strcpy() by supplying
+** our own implementation.
+*/
+static void amatchStrcpy(char *dest, const char *src){
+ while( (*(dest++) = *(src++))!=0 ){}
+}
+static void amatchStrcat(char *dest, const char *src){
+ while( *dest ) dest++;
+ amatchStrcpy(dest, src);
+}
+
+/*
+** Add a new amatch_word object to the queue.
+**
+** If a prior amatch_word object with the same zWord, and nMatch
+** already exists, update its rCost (if the new rCost is less) but
+** otherwise leave it unchanged. Do not add a duplicate.
+**
+** Do nothing if the cost exceeds threshold.
+*/
+static void amatchAddWord(
+ amatch_cursor *pCur,
+ amatch_cost rCost,
+ int nMatch,
+ const char *zWordBase,
+ const char *zWordTail
+){
+ amatch_word *pWord;
+ amatch_avl *pNode;
+ amatch_avl *pOther;
+ int nBase, nTail;
+ char zBuf[4];
+
+ if( rCost>pCur->rLimit ){
+ return;
+ }
+ nBase = (int)strlen(zWordBase);
+ nTail = (int)strlen(zWordTail);
+ if( nBase+nTail+3>pCur->nBuf ){
+ pCur->nBuf = nBase+nTail+100;
+ pCur->zBuf = sqlite3_realloc(pCur->zBuf, pCur->nBuf);
+ if( pCur->zBuf==0 ){
+ pCur->nBuf = 0;
+ return;
+ }
+ }
+ amatchEncodeInt(nMatch, zBuf);
+ memcpy(pCur->zBuf, zBuf+2, 2);
+ memcpy(pCur->zBuf+2, zWordBase, nBase);
+ memcpy(pCur->zBuf+2+nBase, zWordTail, nTail+1);
+ pNode = amatchAvlSearch(pCur->pWord, pCur->zBuf);
+ if( pNode ){
+ pWord = pNode->pWord;
+ if( pWord->rCost>rCost ){
+#ifdef AMATCH_TRACE_1
+ printf("UPDATE [%s][%.*s^%s] %d (\"%s\" \"%s\")\n",
+ pWord->zWord+2, pWord->nMatch, pCur->zInput, pCur->zInput,
+ pWord->rCost, pWord->zWord, pWord->zCost);
+#endif
+ amatchAvlRemove(&pCur->pCost, &pWord->sCost);
+ pWord->rCost = rCost;
+ amatchWriteCost(pWord);
+#ifdef AMATCH_TRACE_1
+ printf(" ---> %d (\"%s\" \"%s\")\n",
+ pWord->rCost, pWord->zWord, pWord->zCost);
+#endif
+ pOther = amatchAvlInsert(&pCur->pCost, &pWord->sCost);
+ assert( pOther==0 ); (void)pOther;
+ }
+ return;
+ }
+ pWord = sqlite3_malloc( sizeof(*pWord) + nBase + nTail - 1 );
+ if( pWord==0 ) return;
+ memset(pWord, 0, sizeof(*pWord));
+ pWord->rCost = rCost;
+ pWord->iSeq = pCur->nWord++;
+ amatchWriteCost(pWord);
+ pWord->nMatch = (short)nMatch;
+ pWord->pNext = pCur->pAllWords;
+ pCur->pAllWords = pWord;
+ pWord->sCost.zKey = pWord->zCost;
+ pWord->sCost.pWord = pWord;
+ pOther = amatchAvlInsert(&pCur->pCost, &pWord->sCost);
+ assert( pOther==0 ); (void)pOther;
+ pWord->sWord.zKey = pWord->zWord;
+ pWord->sWord.pWord = pWord;
+ amatchStrcpy(pWord->zWord, pCur->zBuf);
+ pOther = amatchAvlInsert(&pCur->pWord, &pWord->sWord);
+ assert( pOther==0 ); (void)pOther;
+#ifdef AMATCH_TRACE_1
+ printf("INSERT [%s][%.*s^%s] %d (\"%s\" \"%s\")\n", pWord->zWord+2,
+ pWord->nMatch, pCur->zInput, pCur->zInput+pWord->nMatch, rCost,
+ pWord->zWord, pWord->zCost);
+#endif
+}
+
+
+/*
+** Advance a cursor to its next row of output
+*/
+static int amatchNext(sqlite3_vtab_cursor *cur){
+ amatch_cursor *pCur = (amatch_cursor*)cur;
+ amatch_word *pWord = 0;
+ amatch_avl *pNode;
+ int isMatch = 0;
+ amatch_vtab *p = pCur->pVtab;
+ int nWord;
+ int rc;
+ int i;
+ const char *zW;
+ amatch_rule *pRule;
+ char *zBuf = 0;
+ char nBuf = 0;
+ char zNext[8];
+ char zNextIn[8];
+ int nNextIn;
+
+ if( p->pVCheck==0 ){
+ char *zSql;
+ if( p->zVocabLang && p->zVocabLang[0] ){
+ zSql = sqlite3_mprintf(
+ "SELECT \"%w\" FROM \"%w\"",
+ " WHERE \"%w\">=?1 AND \"%w\"=?2"
+ " ORDER BY 1",
+ p->zVocabWord, p->zVocabTab,
+ p->zVocabWord, p->zVocabLang
+ );
+ }else{
+ zSql = sqlite3_mprintf(
+ "SELECT \"%w\" FROM \"%w\""
+ " WHERE \"%w\">=?1"
+ " ORDER BY 1",
+ p->zVocabWord, p->zVocabTab,
+ p->zVocabWord
+ );
+ }
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &p->pVCheck, 0);
+ sqlite3_free(zSql);
+ if( rc ) return rc;
+ }
+ sqlite3_bind_int(p->pVCheck, 2, pCur->iLang);
+
+ do{
+ pNode = amatchAvlFirst(pCur->pCost);
+ if( pNode==0 ){
+ pWord = 0;
+ break;
+ }
+ pWord = pNode->pWord;
+ amatchAvlRemove(&pCur->pCost, &pWord->sCost);
+
+#ifdef AMATCH_TRACE_1
+ printf("PROCESS [%s][%.*s^%s] %d (\"%s\" \"%s\")\n",
+ pWord->zWord+2, pWord->nMatch, pCur->zInput, pCur->zInput+pWord->nMatch,
+ pWord->rCost, pWord->zWord, pWord->zCost);
+#endif
+ nWord = (int)strlen(pWord->zWord+2);
+ if( nWord+20>nBuf ){
+ nBuf = (char)(nWord+100);
+ zBuf = sqlite3_realloc(zBuf, nBuf);
+ if( zBuf==0 ) return SQLITE_NOMEM;
+ }
+ amatchStrcpy(zBuf, pWord->zWord+2);
+ zNext[0] = 0;
+ zNextIn[0] = pCur->zInput[pWord->nMatch];
+ if( zNextIn[0] ){
+ for(i=1; i<=4 && (pCur->zInput[pWord->nMatch+i]&0xc0)==0x80; i++){
+ zNextIn[i] = pCur->zInput[pWord->nMatch+i];
+ }
+ zNextIn[i] = 0;
+ nNextIn = i;
+ }else{
+ nNextIn = 0;
+ }
+
+ if( zNextIn[0] && zNextIn[0]!='*' ){
+ sqlite3_reset(p->pVCheck);
+ amatchStrcat(zBuf, zNextIn);
+ sqlite3_bind_text(p->pVCheck, 1, zBuf, nWord+nNextIn, SQLITE_STATIC);
+ rc = sqlite3_step(p->pVCheck);
+ if( rc==SQLITE_ROW ){
+ zW = (const char*)sqlite3_column_text(p->pVCheck, 0);
+ if( strncmp(zBuf, zW, nWord+nNextIn)==0 ){
+ amatchAddWord(pCur, pWord->rCost, pWord->nMatch+nNextIn, zBuf, "");
+ }
+ }
+ zBuf[nWord] = 0;
+ }
+
+ while( 1 ){
+ amatchStrcpy(zBuf+nWord, zNext);
+ sqlite3_reset(p->pVCheck);
+ sqlite3_bind_text(p->pVCheck, 1, zBuf, -1, SQLITE_TRANSIENT);
+ rc = sqlite3_step(p->pVCheck);
+ if( rc!=SQLITE_ROW ) break;
+ zW = (const char*)sqlite3_column_text(p->pVCheck, 0);
+ amatchStrcpy(zBuf+nWord, zNext);
+ if( strncmp(zW, zBuf, nWord)!=0 ) break;
+ if( (zNextIn[0]=='*' && zNextIn[1]==0)
+ || (zNextIn[0]==0 && zW[nWord]==0)
+ ){
+ isMatch = 1;
+ zNextIn[0] = 0;
+ nNextIn = 0;
+ break;
+ }
+ zNext[0] = zW[nWord];
+ for(i=1; i<=4 && (zW[nWord+i]&0xc0)==0x80; i++){
+ zNext[i] = zW[nWord+i];
+ }
+ zNext[i] = 0;
+ zBuf[nWord] = 0;
+ if( p->rIns>0 ){
+ amatchAddWord(pCur, pWord->rCost+p->rIns, pWord->nMatch,
+ zBuf, zNext);
+ }
+ if( p->rSub>0 ){
+ amatchAddWord(pCur, pWord->rCost+p->rSub, pWord->nMatch+nNextIn,
+ zBuf, zNext);
+ }
+ if( p->rIns<0 && p->rSub<0 ) break;
+ zNext[i-1]++; /* FIX ME */
+ }
+ sqlite3_reset(p->pVCheck);
+
+ if( p->rDel>0 ){
+ zBuf[nWord] = 0;
+ amatchAddWord(pCur, pWord->rCost+p->rDel, pWord->nMatch+nNextIn,
+ zBuf, "");
+ }
+
+ for(pRule=p->pRule; pRule; pRule=pRule->pNext){
+ if( pRule->iLang!=pCur->iLang ) continue;
+ if( strncmp(pRule->zFrom, pCur->zInput+pWord->nMatch, pRule->nFrom)==0 ){
+ amatchAddWord(pCur, pWord->rCost+pRule->rCost,
+ pWord->nMatch+pRule->nFrom, pWord->zWord+2, pRule->zTo);
+ }
+ }
+ }while( !isMatch );
+ pCur->pCurrent = pWord;
+ sqlite3_free(zBuf);
+ return SQLITE_OK;
+}
+
+/*
+** Called to "rewind" a cursor back to the beginning so that
+** it starts its output over again. Always called at least once
+** prior to any amatchColumn, amatchRowid, or amatchEof call.
+*/
+static int amatchFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ amatch_cursor *pCur = (amatch_cursor *)pVtabCursor;
+ const char *zWord = "*";
+ int idx;
+
+ amatchClearCursor(pCur);
+ idx = 0;
+ if( idxNum & 1 ){
+ zWord = (const char*)sqlite3_value_text(argv[0]);
+ idx++;
+ }
+ if( idxNum & 2 ){
+ pCur->rLimit = (amatch_cost)sqlite3_value_int(argv[idx]);
+ idx++;
+ }
+ if( idxNum & 4 ){
+ pCur->iLang = (amatch_cost)sqlite3_value_int(argv[idx]);
+ idx++;
+ }
+ pCur->zInput = sqlite3_mprintf("%s", zWord);
+ if( pCur->zInput==0 ) return SQLITE_NOMEM;
+ amatchAddWord(pCur, 0, 0, "", "");
+ amatchNext(pVtabCursor);
+
+ return SQLITE_OK;
+}
+
+/*
+** Only the word and distance columns have values. All other columns
+** return NULL
+*/
+static int amatchColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
+ amatch_cursor *pCur = (amatch_cursor*)cur;
+ switch( i ){
+ case AMATCH_COL_WORD: {
+ sqlite3_result_text(ctx, pCur->pCurrent->zWord+2, -1, SQLITE_STATIC);
+ break;
+ }
+ case AMATCH_COL_DISTANCE: {
+ sqlite3_result_int(ctx, pCur->pCurrent->rCost);
+ break;
+ }
+ case AMATCH_COL_LANGUAGE: {
+ sqlite3_result_int(ctx, pCur->iLang);
+ break;
+ }
+ case AMATCH_COL_NWORD: {
+ sqlite3_result_int(ctx, pCur->nWord);
+ break;
+ }
+ default: {
+ sqlite3_result_null(ctx);
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** The rowid.
+*/
+static int amatchRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ amatch_cursor *pCur = (amatch_cursor*)cur;
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** EOF indicator
+*/
+static int amatchEof(sqlite3_vtab_cursor *cur){
+ amatch_cursor *pCur = (amatch_cursor*)cur;
+ return pCur->pCurrent==0;
+}
+
+/*
+** Search for terms of these forms:
+**
+** (A) word MATCH $str
+** (B1) distance < $value
+** (B2) distance <= $value
+** (C) language == $language
+**
+** The distance< and distance<= are both treated as distance<=.
+** The query plan number is a bit vector:
+**
+** bit 1: Term of the form (A) found
+** bit 2: Term like (B1) or (B2) found
+** bit 3: Term like (C) found
+**
+** If bit-1 is set, $str is always in filter.argv[0]. If bit-2 is set
+** then $value is in filter.argv[0] if bit-1 is clear and is in
+** filter.argv[1] if bit-1 is set. If bit-3 is set, then $ruleid is
+** in filter.argv[0] if bit-1 and bit-2 are both zero, is in
+** filter.argv[1] if exactly one of bit-1 and bit-2 are set, and is in
+** filter.argv[2] if both bit-1 and bit-2 are set.
+*/
+static int amatchBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int iPlan = 0;
+ int iDistTerm = -1;
+ int iLangTerm = -1;
+ int i;
+ const struct sqlite3_index_constraint *pConstraint;
+
+ (void)tab;
+ pConstraint = pIdxInfo->aConstraint;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
+ if( pConstraint->usable==0 ) continue;
+ if( (iPlan & 1)==0
+ && pConstraint->iColumn==0
+ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH
+ ){
+ iPlan |= 1;
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ }
+ if( (iPlan & 2)==0
+ && pConstraint->iColumn==1
+ && (pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT
+ || pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE)
+ ){
+ iPlan |= 2;
+ iDistTerm = i;
+ }
+ if( (iPlan & 4)==0
+ && pConstraint->iColumn==2
+ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
+ ){
+ iPlan |= 4;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ iLangTerm = i;
+ }
+ }
+ if( iPlan & 2 ){
+ pIdxInfo->aConstraintUsage[iDistTerm].argvIndex = 1+((iPlan&1)!=0);
+ }
+ if( iPlan & 4 ){
+ int idx = 1;
+ if( iPlan & 1 ) idx++;
+ if( iPlan & 2 ) idx++;
+ pIdxInfo->aConstraintUsage[iLangTerm].argvIndex = idx;
+ }
+ pIdxInfo->idxNum = iPlan;
+ if( pIdxInfo->nOrderBy==1
+ && pIdxInfo->aOrderBy[0].iColumn==1
+ && pIdxInfo->aOrderBy[0].desc==0
+ ){
+ pIdxInfo->orderByConsumed = 1;
+ }
+ pIdxInfo->estimatedCost = (double)10000;
+
+ return SQLITE_OK;
+}
+
+/*
+** The xUpdate() method.
+**
+** This implementation disallows DELETE and UPDATE. The only thing
+** allowed is INSERT into the "command" column.
+*/
+static int amatchUpdate(
+ sqlite3_vtab *pVTab,
+ int argc,
+ sqlite3_value **argv,
+ sqlite_int64 *pRowid
+){
+ amatch_vtab *p = (amatch_vtab*)pVTab;
+ const unsigned char *zCmd;
+ (void)pRowid;
+ if( argc==1 ){
+ pVTab->zErrMsg = sqlite3_mprintf("DELETE from %s is not allowed",
+ p->zSelf);
+ return SQLITE_ERROR;
+ }
+ if( sqlite3_value_type(argv[0])!=SQLITE_NULL ){
+ pVTab->zErrMsg = sqlite3_mprintf("UPDATE of %s is not allowed",
+ p->zSelf);
+ return SQLITE_ERROR;
+ }
+ if( sqlite3_value_type(argv[2+AMATCH_COL_WORD])!=SQLITE_NULL
+ || sqlite3_value_type(argv[2+AMATCH_COL_DISTANCE])!=SQLITE_NULL
+ || sqlite3_value_type(argv[2+AMATCH_COL_LANGUAGE])!=SQLITE_NULL
+ ){
+ pVTab->zErrMsg = sqlite3_mprintf(
+ "INSERT INTO %s allowed for column [command] only", p->zSelf);
+ return SQLITE_ERROR;
+ }
+ zCmd = sqlite3_value_text(argv[2+AMATCH_COL_COMMAND]);
+ if( zCmd==0 ) return SQLITE_OK;
+
+ return SQLITE_OK;
+}
+
+/*
+** A virtual table module that implements the "approximate_match".
+*/
+static const sqlite3_module amatchModule = {
+ 0, /* iVersion */
+ amatchConnect, /* xCreate */
+ amatchConnect, /* xConnect */
+ amatchBestIndex, /* xBestIndex */
+ amatchDisconnect, /* xDisconnect */
+ amatchDisconnect, /* xDestroy */
+ amatchOpen, /* xOpen - open a cursor */
+ amatchClose, /* xClose - close a cursor */
+ amatchFilter, /* xFilter - configure scan constraints */
+ amatchNext, /* xNext - advance a cursor */
+ amatchEof, /* xEof - check for end of scan */
+ amatchColumn, /* xColumn - read data */
+ amatchRowid, /* xRowid - read data */
+ amatchUpdate, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
+};
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+/*
+** Register the amatch virtual table
+*/
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_amatch_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Not used */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3_create_module(db, "approximate_match", &amatchModule, 0);
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Not used */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3_create_module(db, "approximate_match", &amatchModule, 0);
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+ return rc;
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/anycollseq.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/anycollseq.c 2019-10-08 13:42:19.074406600 +0200
@@ -0,0 +1,70 @@
+/*
+** 2017-04-16
+**
+** 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 implements a run-time loadable extension to SQLite that
+** registers a sqlite3_collation_needed() callback to register a fake
+** collating function for any unknown collating sequence. The fake
+** collating function works like BINARY.
+**
+** This extension can be used to load schemas that contain one or more
+** unknown collating sequences.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <string.h>
+
+static int anyCollFunc(
+ void *NotUsed,
+ int nKey1, const void *pKey1,
+ int nKey2, const void *pKey2
+){
+ int rc, n;
+ n = nKey1<nKey2 ? nKey1 : nKey2;
+ rc = memcmp(pKey1, pKey2, n);
+ if( rc==0 ) rc = nKey1 - nKey2;
+ return rc;
+}
+
+static void anyCollNeeded(
+ void *NotUsed,
+ sqlite3 *db,
+ int eTextRep,
+ const char *zCollName
+){
+ sqlite3_create_collation(db, zCollName, eTextRep, 0, anyCollFunc);
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_anycollseq_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ rc = sqlite3_collation_needed(db, 0, anyCollNeeded);
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ rc = sqlite3_collation_needed(db, 0, anyCollNeeded);
+ return rc;
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/appendvfs.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/appendvfs.c 2019-10-08 13:42:19.076373500 +0200
@@ -0,0 +1,565 @@
+/*
+** 2017-10-20
+**
+** 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 implements a VFS shim that allows an SQLite database to be
+** appended onto the end of some other file, such as an executable.
+**
+** A special record must appear at the end of the file that identifies the
+** file as an appended database and provides an offset to page 1. For
+** best performance page 1 should be located at a disk page boundary, though
+** that is not required.
+**
+** When opening a database using this VFS, the connection might treat
+** the file as an ordinary SQLite database, or it might treat is as a
+** database appended onto some other file. Here are the rules:
+**
+** (1) When opening a new empty file, that file is treated as an ordinary
+** database.
+**
+** (2) When opening a file that begins with the standard SQLite prefix
+** string "SQLite format 3", that file is treated as an ordinary
+** database.
+**
+** (3) When opening a file that ends with the appendvfs trailer string
+** "Start-Of-SQLite3-NNNNNNNN" that file is treated as an appended
+** database.
+**
+** (4) If none of the above apply and the SQLITE_OPEN_CREATE flag is
+** set, then a new database is appended to the already existing file.
+**
+** (5) Otherwise, SQLITE_CANTOPEN is returned.
+**
+** To avoid unnecessary complications with the PENDING_BYTE, the size of
+** the file containing the database is limited to 1GB. This VFS will refuse
+** to read or write past the 1GB mark. This restriction might be lifted in
+** future versions. For now, if you need a large database, then keep the
+** database in a separate file.
+**
+** If the file being opened is not an appended database, then this shim is
+** a pass-through into the default underlying VFS.
+**/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <string.h>
+#include <assert.h>
+
+/* The append mark at the end of the database is:
+**
+** Start-Of-SQLite3-NNNNNNNN
+** 123456789 123456789 12345
+**
+** The NNNNNNNN represents a 64-bit big-endian unsigned integer which is
+** the offset to page 1.
+*/
+#define APND_MARK_PREFIX "Start-Of-SQLite3-"
+#define APND_MARK_PREFIX_SZ 17
+#define APND_MARK_SIZE 25
+
+/*
+** Maximum size of the combined prefix + database + append-mark. This
+** must be less than 0x40000000 to avoid locking issues on Windows.
+*/
+#define APND_MAX_SIZE (65536*15259)
+
+/*
+** Forward declaration of objects used by this utility
+*/
+typedef struct sqlite3_vfs ApndVfs;
+typedef struct ApndFile ApndFile;
+
+/* Access to a lower-level VFS that (might) implement dynamic loading,
+** access to randomness, etc.
+*/
+#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
+#define ORIGFILE(p) ((sqlite3_file*)(((ApndFile*)(p))+1))
+
+/* An open file */
+struct ApndFile {
+ sqlite3_file base; /* IO methods */
+ sqlite3_int64 iPgOne; /* File offset to page 1 */
+ sqlite3_int64 iMark; /* Start of the append-mark */
+};
+
+/*
+** Methods for ApndFile
+*/
+static int apndClose(sqlite3_file*);
+static int apndRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
+static int apndWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
+static int apndTruncate(sqlite3_file*, sqlite3_int64 size);
+static int apndSync(sqlite3_file*, int flags);
+static int apndFileSize(sqlite3_file*, sqlite3_int64 *pSize);
+static int apndLock(sqlite3_file*, int);
+static int apndUnlock(sqlite3_file*, int);
+static int apndCheckReservedLock(sqlite3_file*, int *pResOut);
+static int apndFileControl(sqlite3_file*, int op, void *pArg);
+static int apndSectorSize(sqlite3_file*);
+static int apndDeviceCharacteristics(sqlite3_file*);
+static int apndShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
+static int apndShmLock(sqlite3_file*, int offset, int n, int flags);
+static void apndShmBarrier(sqlite3_file*);
+static int apndShmUnmap(sqlite3_file*, int deleteFlag);
+static int apndFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
+static int apndUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
+
+/*
+** Methods for ApndVfs
+*/
+static int apndOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
+static int apndDelete(sqlite3_vfs*, const char *zName, int syncDir);
+static int apndAccess(sqlite3_vfs*, const char *zName, int flags, int *);
+static int apndFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
+static void *apndDlOpen(sqlite3_vfs*, const char *zFilename);
+static void apndDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
+static void (*apndDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
+static void apndDlClose(sqlite3_vfs*, void*);
+static int apndRandomness(sqlite3_vfs*, int nByte, char *zOut);
+static int apndSleep(sqlite3_vfs*, int microseconds);
+static int apndCurrentTime(sqlite3_vfs*, double*);
+static int apndGetLastError(sqlite3_vfs*, int, char *);
+static int apndCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
+static int apndSetSystemCall(sqlite3_vfs*, const char*,sqlite3_syscall_ptr);
+static sqlite3_syscall_ptr apndGetSystemCall(sqlite3_vfs*, const char *z);
+static const char *apndNextSystemCall(sqlite3_vfs*, const char *zName);
+
+static sqlite3_vfs apnd_vfs = {
+ 3, /* iVersion (set when registered) */
+ 0, /* szOsFile (set when registered) */
+ 1024, /* mxPathname */
+ 0, /* pNext */
+ "apndvfs", /* zName */
+ 0, /* pAppData (set when registered) */
+ apndOpen, /* xOpen */
+ apndDelete, /* xDelete */
+ apndAccess, /* xAccess */
+ apndFullPathname, /* xFullPathname */
+ apndDlOpen, /* xDlOpen */
+ apndDlError, /* xDlError */
+ apndDlSym, /* xDlSym */
+ apndDlClose, /* xDlClose */
+ apndRandomness, /* xRandomness */
+ apndSleep, /* xSleep */
+ apndCurrentTime, /* xCurrentTime */
+ apndGetLastError, /* xGetLastError */
+ apndCurrentTimeInt64, /* xCurrentTimeInt64 */
+ apndSetSystemCall, /* xSetSystemCall */
+ apndGetSystemCall, /* xGetSystemCall */
+ apndNextSystemCall /* xNextSystemCall */
+};
+
+static const sqlite3_io_methods apnd_io_methods = {
+ 3, /* iVersion */
+ apndClose, /* xClose */
+ apndRead, /* xRead */
+ apndWrite, /* xWrite */
+ apndTruncate, /* xTruncate */
+ apndSync, /* xSync */
+ apndFileSize, /* xFileSize */
+ apndLock, /* xLock */
+ apndUnlock, /* xUnlock */
+ apndCheckReservedLock, /* xCheckReservedLock */
+ apndFileControl, /* xFileControl */
+ apndSectorSize, /* xSectorSize */
+ apndDeviceCharacteristics, /* xDeviceCharacteristics */
+ apndShmMap, /* xShmMap */
+ apndShmLock, /* xShmLock */
+ apndShmBarrier, /* xShmBarrier */
+ apndShmUnmap, /* xShmUnmap */
+ apndFetch, /* xFetch */
+ apndUnfetch /* xUnfetch */
+};
+
+
+
+/*
+** Close an apnd-file.
+*/
+static int apndClose(sqlite3_file *pFile){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xClose(pFile);
+}
+
+/*
+** Read data from an apnd-file.
+*/
+static int apndRead(
+ sqlite3_file *pFile,
+ void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ ApndFile *p = (ApndFile *)pFile;
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst+p->iPgOne);
+}
+
+/*
+** Add the append-mark onto the end of the file.
+*/
+static int apndWriteMark(ApndFile *p, sqlite3_file *pFile){
+ int i;
+ unsigned char a[APND_MARK_SIZE];
+ memcpy(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ);
+ for(i=0; i<8; i++){
+ a[APND_MARK_PREFIX_SZ+i] = (p->iPgOne >> (56 - i*8)) & 0xff;
+ }
+ return pFile->pMethods->xWrite(pFile, a, APND_MARK_SIZE, p->iMark);
+}
+
+/*
+** Write data to an apnd-file.
+*/
+static int apndWrite(
+ sqlite3_file *pFile,
+ const void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ int rc;
+ ApndFile *p = (ApndFile *)pFile;
+ pFile = ORIGFILE(pFile);
+ if( iOfst+iAmt>=APND_MAX_SIZE ) return SQLITE_FULL;
+ rc = pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst+p->iPgOne);
+ if( rc==SQLITE_OK && iOfst + iAmt + p->iPgOne > p->iMark ){
+ sqlite3_int64 sz = 0;
+ rc = pFile->pMethods->xFileSize(pFile, &sz);
+ if( rc==SQLITE_OK ){
+ p->iMark = sz - APND_MARK_SIZE;
+ if( iOfst + iAmt + p->iPgOne > p->iMark ){
+ p->iMark = p->iPgOne + iOfst + iAmt;
+ rc = apndWriteMark(p, pFile);
+ }
+ }
+ }
+ return rc;
+}
+
+/*
+** Truncate an apnd-file.
+*/
+static int apndTruncate(sqlite3_file *pFile, sqlite_int64 size){
+ int rc;
+ ApndFile *p = (ApndFile *)pFile;
+ pFile = ORIGFILE(pFile);
+ rc = pFile->pMethods->xTruncate(pFile, size+p->iPgOne+APND_MARK_SIZE);
+ if( rc==SQLITE_OK ){
+ p->iMark = p->iPgOne+size;
+ rc = apndWriteMark(p, pFile);
+ }
+ return rc;
+}
+
+/*
+** Sync an apnd-file.
+*/
+static int apndSync(sqlite3_file *pFile, int flags){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xSync(pFile, flags);
+}
+
+/*
+** Return the current file-size of an apnd-file.
+*/
+static int apndFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
+ ApndFile *p = (ApndFile *)pFile;
+ int rc;
+ pFile = ORIGFILE(p);
+ rc = pFile->pMethods->xFileSize(pFile, pSize);
+ if( rc==SQLITE_OK && p->iPgOne ){
+ *pSize -= p->iPgOne + APND_MARK_SIZE;
+ }
+ return rc;
+}
+
+/*
+** Lock an apnd-file.
+*/
+static int apndLock(sqlite3_file *pFile, int eLock){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xLock(pFile, eLock);
+}
+
+/*
+** Unlock an apnd-file.
+*/
+static int apndUnlock(sqlite3_file *pFile, int eLock){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xUnlock(pFile, eLock);
+}
+
+/*
+** Check if another file-handle holds a RESERVED lock on an apnd-file.
+*/
+static int apndCheckReservedLock(sqlite3_file *pFile, int *pResOut){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xCheckReservedLock(pFile, pResOut);
+}
+
+/*
+** File control method. For custom operations on an apnd-file.
+*/
+static int apndFileControl(sqlite3_file *pFile, int op, void *pArg){
+ ApndFile *p = (ApndFile *)pFile;
+ int rc;
+ pFile = ORIGFILE(pFile);
+ rc = pFile->pMethods->xFileControl(pFile, op, pArg);
+ if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
+ *(char**)pArg = sqlite3_mprintf("apnd(%lld)/%z", p->iPgOne, *(char**)pArg);
+ }
+ return rc;
+}
+
+/*
+** Return the sector-size in bytes for an apnd-file.
+*/
+static int apndSectorSize(sqlite3_file *pFile){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xSectorSize(pFile);
+}
+
+/*
+** Return the device characteristic flags supported by an apnd-file.
+*/
+static int apndDeviceCharacteristics(sqlite3_file *pFile){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xDeviceCharacteristics(pFile);
+}
+
+/* Create a shared memory file mapping */
+static int apndShmMap(
+ sqlite3_file *pFile,
+ int iPg,
+ int pgsz,
+ int bExtend,
+ void volatile **pp
+){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp);
+}
+
+/* Perform locking on a shared-memory segment */
+static int apndShmLock(sqlite3_file *pFile, int offset, int n, int flags){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xShmLock(pFile,offset,n,flags);
+}
+
+/* Memory barrier operation on shared memory */
+static void apndShmBarrier(sqlite3_file *pFile){
+ pFile = ORIGFILE(pFile);
+ pFile->pMethods->xShmBarrier(pFile);
+}
+
+/* Unmap a shared memory segment */
+static int apndShmUnmap(sqlite3_file *pFile, int deleteFlag){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xShmUnmap(pFile,deleteFlag);
+}
+
+/* Fetch a page of a memory-mapped file */
+static int apndFetch(
+ sqlite3_file *pFile,
+ sqlite3_int64 iOfst,
+ int iAmt,
+ void **pp
+){
+ ApndFile *p = (ApndFile *)pFile;
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xFetch(pFile, iOfst+p->iPgOne, iAmt, pp);
+}
+
+/* Release a memory-mapped page */
+static int apndUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
+ ApndFile *p = (ApndFile *)pFile;
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xUnfetch(pFile, iOfst+p->iPgOne, pPage);
+}
+
+/*
+** Check to see if the file is an ordinary SQLite database file.
+*/
+static int apndIsOrdinaryDatabaseFile(sqlite3_int64 sz, sqlite3_file *pFile){
+ int rc;
+ char zHdr[16];
+ static const char aSqliteHdr[] = "SQLite format 3";
+ if( sz<512 ) return 0;
+ rc = pFile->pMethods->xRead(pFile, zHdr, sizeof(zHdr), 0);
+ if( rc ) return 0;
+ return memcmp(zHdr, aSqliteHdr, sizeof(zHdr))==0;
+}
+
+/*
+** Try to read the append-mark off the end of a file. Return the
+** start of the appended database if the append-mark is present. If
+** there is no append-mark, return -1;
+*/
+static sqlite3_int64 apndReadMark(sqlite3_int64 sz, sqlite3_file *pFile){
+ int rc, i;
+ sqlite3_int64 iMark;
+ unsigned char a[APND_MARK_SIZE];
+
+ if( sz<=APND_MARK_SIZE ) return -1;
+ rc = pFile->pMethods->xRead(pFile, a, APND_MARK_SIZE, sz-APND_MARK_SIZE);
+ if( rc ) return -1;
+ if( memcmp(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ)!=0 ) return -1;
+ iMark = ((sqlite3_int64)(a[APND_MARK_PREFIX_SZ]&0x7f))<<56;
+ for(i=1; i<8; i++){
+ iMark += (sqlite3_int64)a[APND_MARK_PREFIX_SZ+i]<<(56-8*i);
+ }
+ return iMark;
+}
+
+/*
+** Open an apnd file handle.
+*/
+static int apndOpen(
+ sqlite3_vfs *pVfs,
+ const char *zName,
+ sqlite3_file *pFile,
+ int flags,
+ int *pOutFlags
+){
+ ApndFile *p;
+ sqlite3_file *pSubFile;
+ sqlite3_vfs *pSubVfs;
+ int rc;
+ sqlite3_int64 sz;
+ pSubVfs = ORIGVFS(pVfs);
+ if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){
+ return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags);
+ }
+ p = (ApndFile*)pFile;
+ memset(p, 0, sizeof(*p));
+ pSubFile = ORIGFILE(pFile);
+ p->base.pMethods = &apnd_io_methods;
+ rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
+ if( rc ) goto apnd_open_done;
+ rc = pSubFile->pMethods->xFileSize(pSubFile, &sz);
+ if( rc ){
+ pSubFile->pMethods->xClose(pSubFile);
+ goto apnd_open_done;
+ }
+ if( apndIsOrdinaryDatabaseFile(sz, pSubFile) ){
+ memmove(pFile, pSubFile, pSubVfs->szOsFile);
+ return SQLITE_OK;
+ }
+ p->iMark = 0;
+ p->iPgOne = apndReadMark(sz, pFile);
+ if( p->iPgOne>0 ){
+ return SQLITE_OK;
+ }
+ if( (flags & SQLITE_OPEN_CREATE)==0 ){
+ pSubFile->pMethods->xClose(pSubFile);
+ rc = SQLITE_CANTOPEN;
+ }
+ p->iPgOne = (sz+0xfff) & ~(sqlite3_int64)0xfff;
+apnd_open_done:
+ if( rc ) pFile->pMethods = 0;
+ return rc;
+}
+
+/*
+** All other VFS methods are pass-thrus.
+*/
+static int apndDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+ return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync);
+}
+static int apndAccess(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int flags,
+ int *pResOut
+){
+ return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut);
+}
+static int apndFullPathname(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int nOut,
+ char *zOut
+){
+ return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut);
+}
+static void *apndDlOpen(sqlite3_vfs *pVfs, const char *zPath){
+ return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
+}
+static void apndDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
+ ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
+}
+static void (*apndDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
+ return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
+}
+static void apndDlClose(sqlite3_vfs *pVfs, void *pHandle){
+ ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
+}
+static int apndRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
+ return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
+}
+static int apndSleep(sqlite3_vfs *pVfs, int nMicro){
+ return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
+}
+static int apndCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
+ return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
+}
+static int apndGetLastError(sqlite3_vfs *pVfs, int a, char *b){
+ return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
+}
+static int apndCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
+ return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);
+}
+static int apndSetSystemCall(
+ sqlite3_vfs *pVfs,
+ const char *zName,
+ sqlite3_syscall_ptr pCall
+){
+ return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall);
+}
+static sqlite3_syscall_ptr apndGetSystemCall(
+ sqlite3_vfs *pVfs,
+ const char *zName
+){
+ return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName);
+}
+static const char *apndNextSystemCall(sqlite3_vfs *pVfs, const char *zName){
+ return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName);
+}
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+/*
+** This routine is called when the extension is loaded.
+** Register the new VFS.
+*/
+int sqlite3_appendvfs_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ sqlite3_vfs *pOrig;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg;
+ (void)db;
+ pOrig = sqlite3_vfs_find(0);
+ apnd_vfs.iVersion = pOrig->iVersion;
+ apnd_vfs.pAppData = pOrig;
+ apnd_vfs.szOsFile = pOrig->szOsFile + sizeof(ApndFile);
+ rc = sqlite3_vfs_register(&apnd_vfs, 0);
+#ifdef APPENDVFS_TEST
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_auto_extension((void(*)(void))apndvfsRegister);
+ }
+#endif
+ if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
+ return rc;
+}
--- origsrc/sqlite-autoconf-3300000/blobio.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/blobio.c 2019-10-08 13:42:19.080263400 +0200
@@ -0,0 +1,170 @@
+/*
+** 2019-03-30
+**
+** 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.
+**
+******************************************************************************
+**
+** An SQL function that uses the incremental BLOB I/O mechanism of SQLite
+** to read or write part of a blob. This is intended for debugging use
+** in the CLI.
+**
+** readblob(SCHEMA,TABLE,COLUMN,ROWID,OFFSET,N)
+**
+** Returns N bytes of the blob starting at OFFSET.
+**
+** writeblob(SCHEMA,TABLE,COLUMN,ROWID,OFFSET,NEWDATA)
+**
+** NEWDATA must be a blob. The content of NEWDATA overwrites the
+** existing BLOB data at SCHEMA.TABLE.COLUMN for row ROWID beginning
+** at OFFSET bytes into the blob.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+
+static void readblobFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3_blob *pBlob = 0;
+ const char *zSchema;
+ const char *zTable;
+ const char *zColumn;
+ sqlite3_int64 iRowid;
+ int iOfst;
+ unsigned char *aData;
+ int nData;
+ sqlite3 *db;
+ int rc;
+
+ zSchema = (const char*)sqlite3_value_text(argv[0]);
+ zTable = (const char*)sqlite3_value_text(argv[1]);
+ if( zTable==0 ){
+ sqlite3_result_error(context, "bad table name", -1);
+ return;
+ }
+ zColumn = (const char*)sqlite3_value_text(argv[2]);
+ if( zTable==0 ){
+ sqlite3_result_error(context, "bad column name", -1);
+ return;
+ }
+ iRowid = sqlite3_value_int64(argv[3]);
+ iOfst = sqlite3_value_int(argv[4]);
+ nData = sqlite3_value_int(argv[5]);
+ if( nData<=0 ) return;
+ aData = sqlite3_malloc64( nData+1 );
+ if( aData==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+ db = sqlite3_context_db_handle(context);
+ rc = sqlite3_blob_open(db, zSchema, zTable, zColumn, iRowid, 0, &pBlob);
+ if( rc ){
+ sqlite3_free(aData);
+ sqlite3_result_error(context, "cannot open BLOB pointer", -1);
+ return;
+ }
+ rc = sqlite3_blob_read(pBlob, aData, nData, iOfst);
+ sqlite3_blob_close(pBlob);
+ if( rc ){
+ sqlite3_free(aData);
+ sqlite3_result_error(context, "BLOB read failed", -1);
+ }else{
+ sqlite3_result_blob(context, aData, nData, sqlite3_free);
+ }
+}
+
+static void writeblobFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3_blob *pBlob = 0;
+ const char *zSchema;
+ const char *zTable;
+ const char *zColumn;
+ sqlite3_int64 iRowid;
+ int iOfst;
+ unsigned char *aData;
+ int nData;
+ sqlite3 *db;
+ int rc;
+
+ zSchema = (const char*)sqlite3_value_text(argv[0]);
+ zTable = (const char*)sqlite3_value_text(argv[1]);
+ if( zTable==0 ){
+ sqlite3_result_error(context, "bad table name", -1);
+ return;
+ }
+ zColumn = (const char*)sqlite3_value_text(argv[2]);
+ if( zTable==0 ){
+ sqlite3_result_error(context, "bad column name", -1);
+ return;
+ }
+ iRowid = sqlite3_value_int64(argv[3]);
+ iOfst = sqlite3_value_int(argv[4]);
+ if( sqlite3_value_type(argv[5])!=SQLITE_BLOB ){
+ sqlite3_result_error(context, "6th argument must be a BLOB", -1);
+ return;
+ }
+ nData = sqlite3_value_bytes(argv[5]);
+ aData = (unsigned char *)sqlite3_value_blob(argv[5]);
+ db = sqlite3_context_db_handle(context);
+ rc = sqlite3_blob_open(db, zSchema, zTable, zColumn, iRowid, 1, &pBlob);
+ if( rc ){
+ sqlite3_result_error(context, "cannot open BLOB pointer", -1);
+ return;
+ }
+ rc = sqlite3_blob_write(pBlob, aData, nData, iOfst);
+ sqlite3_blob_close(pBlob);
+ if( rc ){
+ sqlite3_result_error(context, "BLOB write failed", -1);
+ }
+}
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_blobio_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "readblob", 6, SQLITE_UTF8, 0,
+ readblobFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "writeblob", 6, SQLITE_UTF8, 0,
+ writeblobFunc, 0, 0);
+ }
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "readblob", 6, SQLITE_UTF8, 0,
+ readblobFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "writeblob", 6, SQLITE_UTF8, 0,
+ writeblobFunc, 0, 0);
+ }
+ return rc;
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/btreeinfo.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/btreeinfo.c 2019-10-08 13:42:19.082230400 +0200
@@ -0,0 +1,429 @@
+/*
+** 2017-10-24
+**
+** 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 an implementation of the "sqlite_btreeinfo" virtual table.
+**
+** The sqlite_btreeinfo virtual table is a read-only eponymous-only virtual
+** table that shows information about all btrees in an SQLite database file.
+** The schema is like this:
+**
+** CREATE TABLE sqlite_btreeinfo(
+** type TEXT, -- "table" or "index"
+** name TEXT, -- Name of table or index for this btree.
+** tbl_name TEXT, -- Associated table
+** rootpage INT, -- The root page of the btree
+** sql TEXT, -- SQL for this btree - from sqlite_master
+** hasRowid BOOLEAN, -- True if the btree has a rowid
+** nEntry INT, -- Estimated number of enteries
+** nPage INT, -- Estimated number of pages
+** depth INT, -- Depth of the btree
+** szPage INT, -- Size of each page in bytes
+** zSchema TEXT HIDDEN -- The schema to which this btree belongs
+** );
+**
+** The first 5 fields are taken directly from the sqlite_master table.
+** Considering only the first 5 fields, the only difference between
+** this virtual table and the sqlite_master table is that this virtual
+** table omits all entries that have a 0 or NULL rowid - in other words
+** it omits triggers and views.
+**
+** The value added by this table comes in the next 5 fields.
+**
+** Note that nEntry and nPage are *estimated*. They are computed doing
+** a single search from the root to a leaf, counting the number of cells
+** at each level, and assuming that unvisited pages have a similar number
+** of cells.
+**
+** The sqlite_dbpage virtual table must be available for this virtual table
+** to operate.
+**
+** USAGE EXAMPLES:
+**
+** Show the table btrees in a schema order with the tables with the most
+** rows occuring first:
+**
+** SELECT name, nEntry
+** FROM sqlite_btreeinfo
+** WHERE type='table'
+** ORDER BY nEntry DESC, name;
+**
+** Show the names of all WITHOUT ROWID tables:
+**
+** SELECT name FROM sqlite_btreeinfo
+** WHERE type='table' AND NOT hasRowid;
+*/
+#if !defined(SQLITEINT_H)
+#include "sqlite3ext.h"
+#endif
+SQLITE_EXTENSION_INIT1
+#include <string.h>
+#include <assert.h>
+
+/* Columns available in this virtual table */
+#define BINFO_COLUMN_TYPE 0
+#define BINFO_COLUMN_NAME 1
+#define BINFO_COLUMN_TBL_NAME 2
+#define BINFO_COLUMN_ROOTPAGE 3
+#define BINFO_COLUMN_SQL 4
+#define BINFO_COLUMN_HASROWID 5
+#define BINFO_COLUMN_NENTRY 6
+#define BINFO_COLUMN_NPAGE 7
+#define BINFO_COLUMN_DEPTH 8
+#define BINFO_COLUMN_SZPAGE 9
+#define BINFO_COLUMN_SCHEMA 10
+
+/* Forward declarations */
+typedef struct BinfoTable BinfoTable;
+typedef struct BinfoCursor BinfoCursor;
+
+/* A cursor for the sqlite_btreeinfo table */
+struct BinfoCursor {
+ sqlite3_vtab_cursor base; /* Base class. Must be first */
+ sqlite3_stmt *pStmt; /* Query against sqlite_master */
+ int rc; /* Result of previous sqlite_step() call */
+ int hasRowid; /* hasRowid value. Negative if unknown. */
+ sqlite3_int64 nEntry; /* nEntry value */
+ int nPage; /* nPage value */
+ int depth; /* depth value */
+ int szPage; /* size of a btree page. 0 if unknown */
+ char *zSchema; /* Schema being interrogated */
+};
+
+/* The sqlite_btreeinfo table */
+struct BinfoTable {
+ sqlite3_vtab base; /* Base class. Must be first */
+ sqlite3 *db; /* The databse connection */
+};
+
+/*
+** Connect to the sqlite_btreeinfo virtual table.
+*/
+static int binfoConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ BinfoTable *pTab = 0;
+ int rc = SQLITE_OK;
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x(\n"
+ " type TEXT,\n"
+ " name TEXT,\n"
+ " tbl_name TEXT,\n"
+ " rootpage INT,\n"
+ " sql TEXT,\n"
+ " hasRowid BOOLEAN,\n"
+ " nEntry INT,\n"
+ " nPage INT,\n"
+ " depth INT,\n"
+ " szPage INT,\n"
+ " zSchema TEXT HIDDEN\n"
+ ")");
+ if( rc==SQLITE_OK ){
+ pTab = (BinfoTable *)sqlite3_malloc(sizeof(BinfoTable));
+ if( pTab==0 ) rc = SQLITE_NOMEM;
+ }
+ assert( rc==SQLITE_OK || pTab==0 );
+ if( pTab ){
+ pTab->db = db;
+ }
+ *ppVtab = (sqlite3_vtab*)pTab;
+ return rc;
+}
+
+/*
+** Disconnect from or destroy a btreeinfo virtual table.
+*/
+static int binfoDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** idxNum:
+**
+** 0 Use "main" for the schema
+** 1 Schema identified by parameter ?1
+*/
+static int binfoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+ int i;
+ pIdxInfo->estimatedCost = 10000.0; /* Cost estimate */
+ pIdxInfo->estimatedRows = 100;
+ for(i=0; i<pIdxInfo->nConstraint; i++){
+ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
+ if( p->usable
+ && p->iColumn==BINFO_COLUMN_SCHEMA
+ && p->op==SQLITE_INDEX_CONSTRAINT_EQ
+ ){
+ pIdxInfo->estimatedCost = 1000.0;
+ pIdxInfo->idxNum = 1;
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Open a new btreeinfo cursor.
+*/
+static int binfoOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+ BinfoCursor *pCsr;
+
+ pCsr = (BinfoCursor *)sqlite3_malloc(sizeof(BinfoCursor));
+ if( pCsr==0 ){
+ return SQLITE_NOMEM;
+ }else{
+ memset(pCsr, 0, sizeof(BinfoCursor));
+ pCsr->base.pVtab = pVTab;
+ }
+
+ *ppCursor = (sqlite3_vtab_cursor *)pCsr;
+ return SQLITE_OK;
+}
+
+/*
+** Close a btreeinfo cursor.
+*/
+static int binfoClose(sqlite3_vtab_cursor *pCursor){
+ BinfoCursor *pCsr = (BinfoCursor *)pCursor;
+ sqlite3_finalize(pCsr->pStmt);
+ sqlite3_free(pCsr->zSchema);
+ sqlite3_free(pCsr);
+ return SQLITE_OK;
+}
+
+/*
+** Move a btreeinfo cursor to the next entry in the file.
+*/
+static int binfoNext(sqlite3_vtab_cursor *pCursor){
+ BinfoCursor *pCsr = (BinfoCursor *)pCursor;
+ pCsr->rc = sqlite3_step(pCsr->pStmt);
+ pCsr->hasRowid = -1;
+ return pCsr->rc==SQLITE_ERROR ? SQLITE_ERROR : SQLITE_OK;
+}
+
+/* We have reached EOF if previous sqlite3_step() returned
+** anything other than SQLITE_ROW;
+*/
+static int binfoEof(sqlite3_vtab_cursor *pCursor){
+ BinfoCursor *pCsr = (BinfoCursor *)pCursor;
+ return pCsr->rc!=SQLITE_ROW;
+}
+
+/* Position a cursor back to the beginning.
+*/
+static int binfoFilter(
+ sqlite3_vtab_cursor *pCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ BinfoCursor *pCsr = (BinfoCursor *)pCursor;
+ BinfoTable *pTab = (BinfoTable *)pCursor->pVtab;
+ char *zSql;
+ int rc;
+
+ sqlite3_free(pCsr->zSchema);
+ if( idxNum==1 && sqlite3_value_type(argv[0])!=SQLITE_NULL ){
+ pCsr->zSchema = sqlite3_mprintf("%s", sqlite3_value_text(argv[0]));
+ }else{
+ pCsr->zSchema = sqlite3_mprintf("main");
+ }
+ zSql = sqlite3_mprintf(
+ "SELECT 0, 'table','sqlite_master','sqlite_master',1,NULL "
+ "UNION ALL "
+ "SELECT rowid, type, name, tbl_name, rootpage, sql"
+ " FROM \"%w\".sqlite_master WHERE rootpage>=1",
+ pCsr->zSchema);
+ sqlite3_finalize(pCsr->pStmt);
+ pCsr->pStmt = 0;
+ pCsr->hasRowid = -1;
+ rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
+ sqlite3_free(zSql);
+ if( rc==SQLITE_OK ){
+ rc = binfoNext(pCursor);
+ }
+ return rc;
+}
+
+/* Decode big-endian integers */
+static unsigned int get_uint16(unsigned char *a){
+ return (a[0]<<8)|a[1];
+}
+static unsigned int get_uint32(unsigned char *a){
+ return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|a[3];
+}
+
+/* Examine the b-tree rooted at pgno and estimate its size.
+** Return non-zero if anything goes wrong.
+*/
+static int binfoCompute(sqlite3 *db, int pgno, BinfoCursor *pCsr){
+ sqlite3_int64 nEntry = 1;
+ int nPage = 1;
+ unsigned char *aData;
+ sqlite3_stmt *pStmt = 0;
+ int rc = SQLITE_OK;
+ int pgsz = 0;
+ int nCell;
+ int iCell;
+
+ rc = sqlite3_prepare_v2(db,
+ "SELECT data FROM sqlite_dbpage('main') WHERE pgno=?1", -1,
+ &pStmt, 0);
+ if( rc ) return rc;
+ pCsr->depth = 1;
+ while(1){
+ sqlite3_bind_int(pStmt, 1, pgno);
+ rc = sqlite3_step(pStmt);
+ if( rc!=SQLITE_ROW ){
+ rc = SQLITE_ERROR;
+ break;
+ }
+ pCsr->szPage = pgsz = sqlite3_column_bytes(pStmt, 0);
+ aData = (unsigned char*)sqlite3_column_blob(pStmt, 0);
+ if( aData==0 ){
+ rc = SQLITE_NOMEM;
+ break;
+ }
+ if( pgno==1 ){
+ aData += 100;
+ pgsz -= 100;
+ }
+ pCsr->hasRowid = aData[0]!=2 && aData[0]!=10;
+ nCell = get_uint16(aData+3);
+ nEntry *= (nCell+1);
+ if( aData[0]==10 || aData[0]==13 ) break;
+ nPage *= (nCell+1);
+ if( nCell<=1 ){
+ pgno = get_uint32(aData+8);
+ }else{
+ iCell = get_uint16(aData+12+2*(nCell/2));
+ if( pgno==1 ) iCell -= 100;
+ if( iCell<=12 || iCell>=pgsz-4 ){
+ rc = SQLITE_CORRUPT;
+ break;
+ }
+ pgno = get_uint32(aData+iCell);
+ }
+ pCsr->depth++;
+ sqlite3_reset(pStmt);
+ }
+ sqlite3_finalize(pStmt);
+ pCsr->nPage = nPage;
+ pCsr->nEntry = nEntry;
+ if( rc==SQLITE_ROW ) rc = SQLITE_OK;
+ return rc;
+}
+
+/* Return a column for the sqlite_btreeinfo table */
+static int binfoColumn(
+ sqlite3_vtab_cursor *pCursor,
+ sqlite3_context *ctx,
+ int i
+){
+ BinfoCursor *pCsr = (BinfoCursor *)pCursor;
+ if( i>=BINFO_COLUMN_HASROWID && i<=BINFO_COLUMN_SZPAGE && pCsr->hasRowid<0 ){
+ int pgno = sqlite3_column_int(pCsr->pStmt, BINFO_COLUMN_ROOTPAGE+1);
+ sqlite3 *db = sqlite3_context_db_handle(ctx);
+ int rc = binfoCompute(db, pgno, pCsr);
+ if( rc ){
+ pCursor->pVtab->zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ return SQLITE_ERROR;
+ }
+ }
+ switch( i ){
+ case BINFO_COLUMN_NAME:
+ case BINFO_COLUMN_TYPE:
+ case BINFO_COLUMN_TBL_NAME:
+ case BINFO_COLUMN_ROOTPAGE:
+ case BINFO_COLUMN_SQL: {
+ sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pStmt, i+1));
+ break;
+ }
+ case BINFO_COLUMN_HASROWID: {
+ sqlite3_result_int(ctx, pCsr->hasRowid);
+ break;
+ }
+ case BINFO_COLUMN_NENTRY: {
+ sqlite3_result_int64(ctx, pCsr->nEntry);
+ break;
+ }
+ case BINFO_COLUMN_NPAGE: {
+ sqlite3_result_int(ctx, pCsr->nPage);
+ break;
+ }
+ case BINFO_COLUMN_DEPTH: {
+ sqlite3_result_int(ctx, pCsr->depth);
+ break;
+ }
+ case BINFO_COLUMN_SCHEMA: {
+ sqlite3_result_text(ctx, pCsr->zSchema, -1, SQLITE_STATIC);
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/* Return the ROWID for the sqlite_btreeinfo table */
+static int binfoRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
+ BinfoCursor *pCsr = (BinfoCursor *)pCursor;
+ *pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
+ return SQLITE_OK;
+}
+
+/*
+** Invoke this routine to register the "sqlite_btreeinfo" virtual table module
+*/
+int sqlite3BinfoRegister(sqlite3 *db){
+ static const sqlite3_module binfo_module = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ binfoConnect, /* xConnect */
+ binfoBestIndex, /* xBestIndex */
+ binfoDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ binfoOpen, /* xOpen - open a cursor */
+ binfoClose, /* xClose - close a cursor */
+ binfoFilter, /* xFilter - configure scan constraints */
+ binfoNext, /* xNext - advance a cursor */
+ binfoEof, /* xEof - check for end of scan */
+ binfoColumn, /* xColumn - read data */
+ binfoRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
+ };
+ return sqlite3_create_module(db, "sqlite_btreeinfo", &binfo_module, 0);
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_btreeinfo_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi);
+ return sqlite3BinfoRegister(db);
+}
--- origsrc/sqlite-autoconf-3300000/carray.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/carray.c 2019-10-08 13:42:19.086121500 +0200
@@ -0,0 +1,420 @@
+/*
+** 2016-06-29
+**
+** 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 demonstrates how to create a table-valued-function that
+** returns the values in a C-language array.
+** Examples:
+**
+** SELECT * FROM carray($ptr,5)
+**
+** The query above returns 5 integers contained in a C-language array
+** at the address $ptr. $ptr is a pointer to the array of integers.
+** The pointer value must be assigned to $ptr using the
+** sqlite3_bind_pointer() interface with a pointer type of "carray".
+** For example:
+**
+** static int aX[] = { 53, 9, 17, 2231, 4, 99 };
+** int i = sqlite3_bind_parameter_index(pStmt, "$ptr");
+** sqlite3_bind_pointer(pStmt, i, aX, "carray", 0);
+**
+** There is an optional third parameter to determine the datatype of
+** the C-language array. Allowed values of the third parameter are
+** 'int32', 'int64', 'double', 'char*'. Example:
+**
+** SELECT * FROM carray($ptr,10,'char*');
+**
+** The default value of the third parameter is 'int32'.
+**
+** HOW IT WORKS
+**
+** The carray "function" is really a virtual table with the
+** following schema:
+**
+** CREATE TABLE carray(
+** value,
+** pointer HIDDEN,
+** count HIDDEN,
+** ctype TEXT HIDDEN
+** );
+**
+** If the hidden columns "pointer" and "count" are unconstrained, then
+** the virtual table has no rows. Otherwise, the virtual table interprets
+** the integer value of "pointer" as a pointer to the array and "count"
+** as the number of elements in the array. The virtual table steps through
+** the array, element by element.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/*
+** Allowed datatypes
+*/
+#define CARRAY_INT32 0
+#define CARRAY_INT64 1
+#define CARRAY_DOUBLE 2
+#define CARRAY_TEXT 3
+
+/*
+** Names of types
+*/
+static const char *const azType[] = { "int32", "int64", "double", "char*" };
+
+
+/* carray_cursor is a subclass of sqlite3_vtab_cursor which will
+** serve as the underlying representation of a cursor that scans
+** over rows of the result
+*/
+typedef struct carray_cursor carray_cursor;
+struct carray_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3_int64 iRowid; /* The rowid */
+ void *pPtr; /* Pointer to the array of values */
+ size_t iCnt; /* Number of integers in the array */
+ unsigned char eType; /* One of the CARRAY_type values */
+};
+
+/*
+** The carrayConnect() method is invoked to create a new
+** carray_vtab that describes the carray virtual table.
+**
+** Think of this routine as the constructor for carray_vtab objects.
+**
+** All this routine needs to do is:
+**
+** (1) Allocate the carray_vtab object and initialize all fields.
+**
+** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
+** result set of queries against carray will look like.
+*/
+static int carrayConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ sqlite3_vtab *pNew;
+ int rc;
+
+/* Column numbers */
+#define CARRAY_COLUMN_VALUE 0
+#define CARRAY_COLUMN_POINTER 1
+#define CARRAY_COLUMN_COUNT 2
+#define CARRAY_COLUMN_CTYPE 3
+
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x(value,pointer hidden,count hidden,ctype hidden)");
+ if( rc==SQLITE_OK ){
+ pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for carray_cursor objects.
+*/
+static int carrayDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new carray_cursor object.
+*/
+static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ carray_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Destructor for a carray_cursor.
+*/
+static int carrayClose(sqlite3_vtab_cursor *cur){
+ sqlite3_free(cur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a carray_cursor to its next row of output.
+*/
+static int carrayNext(sqlite3_vtab_cursor *cur){
+ carray_cursor *pCur = (carray_cursor*)cur;
+ pCur->iRowid++;
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the carray_cursor
+** is currently pointing.
+*/
+static int carrayColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ carray_cursor *pCur = (carray_cursor*)cur;
+ sqlite3_int64 x = 0;
+ switch( i ){
+ case CARRAY_COLUMN_POINTER: return SQLITE_OK;
+ case CARRAY_COLUMN_COUNT: x = pCur->iCnt; break;
+ case CARRAY_COLUMN_CTYPE: {
+ sqlite3_result_text(ctx, azType[pCur->eType], -1, SQLITE_STATIC);
+ return SQLITE_OK;
+ }
+ default: {
+ switch( pCur->eType ){
+ case CARRAY_INT32: {
+ int *p = (int*)pCur->pPtr;
+ sqlite3_result_int(ctx, p[pCur->iRowid-1]);
+ return SQLITE_OK;
+ }
+ case CARRAY_INT64: {
+ sqlite3_int64 *p = (sqlite3_int64*)pCur->pPtr;
+ sqlite3_result_int64(ctx, p[pCur->iRowid-1]);
+ return SQLITE_OK;
+ }
+ case CARRAY_DOUBLE: {
+ double *p = (double*)pCur->pPtr;
+ sqlite3_result_double(ctx, p[pCur->iRowid-1]);
+ return SQLITE_OK;
+ }
+ case CARRAY_TEXT: {
+ const char **p = (const char**)pCur->pPtr;
+ sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT);
+ return SQLITE_OK;
+ }
+ }
+ }
+ }
+ sqlite3_result_int64(ctx, x);
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** rowid is the same as the output value.
+*/
+static int carrayRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ carray_cursor *pCur = (carray_cursor*)cur;
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int carrayEof(sqlite3_vtab_cursor *cur){
+ carray_cursor *pCur = (carray_cursor*)cur;
+ return pCur->iRowid>pCur->iCnt;
+}
+
+/*
+** This method is called to "rewind" the carray_cursor object back
+** to the first row of output.
+*/
+static int carrayFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ carray_cursor *pCur = (carray_cursor *)pVtabCursor;
+ if( idxNum ){
+ pCur->pPtr = sqlite3_value_pointer(argv[0], "carray");
+ pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0;
+ if( idxNum<3 ){
+ pCur->eType = CARRAY_INT32;
+ }else{
+ unsigned char i;
+ const char *zType = (const char*)sqlite3_value_text(argv[2]);
+ for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
+ if( sqlite3_stricmp(zType, azType[i])==0 ) break;
+ }
+ if( i>=sizeof(azType)/sizeof(azType[0]) ){
+ pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
+ "unknown datatype: %Q", zType);
+ return SQLITE_ERROR;
+ }else{
+ pCur->eType = i;
+ }
+ }
+ }else{
+ pCur->pPtr = 0;
+ pCur->iCnt = 0;
+ }
+ pCur->iRowid = 1;
+ return SQLITE_OK;
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the carray virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+**
+** In this implementation idxNum is used to represent the
+** query plan. idxStr is unused.
+**
+** idxNum is 2 if the pointer= and count= constraints exist,
+** 3 if the ctype= constraint also exists, and is 0 otherwise.
+** If idxNum is 0, then carray becomes an empty table.
+*/
+static int carrayBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int i; /* Loop over constraints */
+ int ptrIdx = -1; /* Index of the pointer= constraint, or -1 if none */
+ int cntIdx = -1; /* Index of the count= constraint, or -1 if none */
+ int ctypeIdx = -1; /* Index of the ctype= constraint, or -1 if none */
+
+ const struct sqlite3_index_constraint *pConstraint;
+ pConstraint = pIdxInfo->aConstraint;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
+ if( pConstraint->usable==0 ) continue;
+ if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+ switch( pConstraint->iColumn ){
+ case CARRAY_COLUMN_POINTER:
+ ptrIdx = i;
+ break;
+ case CARRAY_COLUMN_COUNT:
+ cntIdx = i;
+ break;
+ case CARRAY_COLUMN_CTYPE:
+ ctypeIdx = i;
+ break;
+ }
+ }
+ if( ptrIdx>=0 && cntIdx>=0 ){
+ pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[ptrIdx].omit = 1;
+ pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
+ pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
+ pIdxInfo->estimatedCost = (double)1;
+ pIdxInfo->estimatedRows = 100;
+ pIdxInfo->idxNum = 2;
+ if( ctypeIdx>=0 ){
+ pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
+ pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
+ pIdxInfo->idxNum = 3;
+ }
+ }else{
+ pIdxInfo->estimatedCost = (double)2147483647;
+ pIdxInfo->estimatedRows = 2147483647;
+ pIdxInfo->idxNum = 0;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** This following structure defines all the methods for the
+** carray virtual table.
+*/
+static const sqlite3_module carrayModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ carrayConnect, /* xConnect */
+ carrayBestIndex, /* xBestIndex */
+ carrayDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ carrayOpen, /* xOpen - open a cursor */
+ carrayClose, /* xClose - close a cursor */
+ carrayFilter, /* xFilter - configure scan constraints */
+ carrayNext, /* xNext - advance a cursor */
+ carrayEof, /* xEof - check for end of scan */
+ carrayColumn, /* xColumn - read data */
+ carrayRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+};
+
+/*
+** For testing purpose in the TCL test harness, we need a method for
+** setting the pointer value. The inttoptr(X) SQL function accomplishes
+** this. Tcl script will bind an integer to X and the inttoptr() SQL
+** function will use sqlite3_result_pointer() to convert that integer into
+** a pointer.
+**
+** This is for testing on TCL only.
+*/
+#ifdef SQLITE_TEST
+static void inttoptrFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ void *p;
+ sqlite3_int64 i64;
+ i64 = sqlite3_value_int64(argv[0]);
+ if( sizeof(i64)==sizeof(p) ){
+ memcpy(&p, &i64, sizeof(p));
+ }else{
+ int i32 = i64 & 0xffffffff;
+ memcpy(&p, &i32, sizeof(p));
+ }
+ sqlite3_result_pointer(context, p, "carray", 0);
+}
+#endif /* SQLITE_TEST */
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_carray_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3_create_module(db, "carray", &carrayModule, 0);
+#ifdef SQLITE_TEST
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "inttoptr", 1, SQLITE_UTF8, 0,
+ inttoptrFunc, 0, 0);
+ }
+#endif /* SQLITE_TEST */
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3_create_module(db, "carray", &carrayModule, 0);
+#endif
+ return rc;
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/closure.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/closure.c 2019-10-08 13:42:19.091003100 +0200
@@ -0,0 +1,980 @@
+/*
+** 2013-04-16
+**
+** 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 code for a virtual table that finds the transitive
+** closure of a parent/child relationship in a real table. The virtual
+** table is called "transitive_closure".
+**
+** A transitive_closure virtual table is created like this:
+**
+** CREATE VIRTUAL TABLE x USING transitive_closure(
+** tablename=<tablename>, -- T
+** idcolumn=<columnname>, -- X
+** parentcolumn=<columnname> -- P
+** );
+**
+** When it is created, the new transitive_closure table may be supplied
+** with default values for the name of a table T and columns T.X and T.P.
+** The T.X and T.P columns must contain integers. The ideal case is for
+** T.X to be the INTEGER PRIMARY KEY. The T.P column should reference
+** the T.X column. The row referenced by T.P is the parent of the current row.
+**
+** The tablename, idcolumn, and parentcolumn supplied by the CREATE VIRTUAL
+** TABLE statement may be overridden in individual queries by including
+** terms like tablename='newtable', idcolumn='id2', or
+** parentcolumn='parent3' in the WHERE clause of the query.
+**
+** For efficiency, it is essential that there be an index on the P column:
+**
+** CREATE Tidx1 ON T(P)
+**
+** Suppose a specific instance of the closure table is as follows:
+**
+** CREATE VIRTUAL TABLE ct1 USING transitive_closure(
+** tablename='group',
+** idcolumn='groupId',
+** parentcolumn='parentId'
+** );
+**
+** Such an instance of the transitive_closure virtual table would be
+** appropriate for walking a tree defined using a table like this, for example:
+**
+** CREATE TABLE group(
+** groupId INTEGER PRIMARY KEY,
+** parentId INTEGER REFERENCES group
+** );
+** CREATE INDEX group_idx1 ON group(parentId);
+**
+** The group table above would presumably have other application-specific
+** fields. The key point here is that rows of the group table form a
+** tree. The purpose of the ct1 virtual table is to easily extract
+** branches of that tree.
+**
+** Once it has been created, the ct1 virtual table can be queried
+** as follows:
+**
+** SELECT * FROM element
+** WHERE element.groupId IN (SELECT id FROM ct1 WHERE root=?1);
+**
+** The above query will return all elements that are part of group ?1
+** or children of group ?1 or grand-children of ?1 and so forth for all
+** descendents of group ?1. The same query can be formulated as a join:
+**
+** SELECT element.* FROM element, ct1
+** WHERE element.groupid=ct1.id
+** AND ct1.root=?1;
+**
+** The depth of the transitive_closure (the number of generations of
+** parent/child relations to follow) can be limited by setting "depth"
+** column in the WHERE clause. So, for example, the following query
+** finds only children and grandchildren but no further descendents:
+**
+** SELECT element.* FROM element, ct1
+** WHERE element.groupid=ct1.id
+** AND ct1.root=?1
+** AND ct1.depth<=2;
+**
+** The "ct1.depth<=2" term could be a strict equality "ct1.depth=2" in
+** order to find only the grandchildren of ?1, not ?1 itself or the
+** children of ?1.
+**
+** The root=?1 term must be supplied in WHERE clause or else the query
+** of the ct1 virtual table will return an empty set. The tablename,
+** idcolumn, and parentcolumn attributes can be overridden in the WHERE
+** clause if desired. So, for example, the ct1 table could be repurposed
+** to find ancestors rather than descendents by inverting the roles of
+** the idcolumn and parentcolumn:
+**
+** SELECT element.* FROM element, ct1
+** WHERE element.groupid=ct1.id
+** AND ct1.root=?1
+** AND ct1.idcolumn='parentId'
+** AND ct1.parentcolumn='groupId';
+**
+** Multiple calls to ct1 could be combined. For example, the following
+** query finds all elements that "cousins" of groupId ?1. That is to say
+** elements where the groupId is a grandchild of the grandparent of ?1.
+** (This definition of "cousins" also includes siblings and self.)
+**
+** SELECT element.* FROM element, ct1
+** WHERE element.groupId=ct1.id
+** AND ct1.depth=2
+** AND ct1.root IN (SELECT id FROM ct1
+** WHERE root=?1
+** AND depth=2
+** AND idcolumn='parentId'
+** AND parentcolumn='groupId');
+**
+** In our example, the group.groupId column is unique and thus the
+** subquery will return exactly one row. For that reason, the IN
+** operator could be replaced by "=" to get the same result. But
+** in the general case where the idcolumn is not unique, an IN operator
+** would be required for this kind of query.
+**
+** Note that because the tablename, idcolumn, and parentcolumn can
+** all be specified in the query, it is possible for an application
+** to define a single transitive_closure virtual table for use on lots
+** of different hierarchy tables. One might say:
+**
+** CREATE VIRTUAL TABLE temp.closure USING transitive_closure;
+**
+** As each database connection is being opened. Then the application
+** would always have a "closure" virtual table handy to use for querying.
+**
+** SELECT element.* FROM element, closure
+** WHERE element.groupid=ct1.id
+** AND closure.root=?1
+** AND closure.tablename='group'
+** AND closure.idname='groupId'
+** AND closure.parentname='parentId';
+**
+** See the documentation at http://www.sqlite.org/loadext.html for information
+** on how to compile and use loadable extensions such as this one.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/*
+** Forward declaration of objects used by this implementation
+*/
+typedef struct closure_vtab closure_vtab;
+typedef struct closure_cursor closure_cursor;
+typedef struct closure_queue closure_queue;
+typedef struct closure_avl closure_avl;
+
+/*****************************************************************************
+** AVL Tree implementation
+*/
+/*
+** Objects that want to be members of the AVL tree should embedded an
+** instance of this structure.
+*/
+struct closure_avl {
+ sqlite3_int64 id; /* Id of this entry in the table */
+ int iGeneration; /* Which generation is this entry part of */
+ closure_avl *pList; /* A linked list of nodes */
+ closure_avl *pBefore; /* Other elements less than id */
+ closure_avl *pAfter; /* Other elements greater than id */
+ closure_avl *pUp; /* Parent element */
+ short int height; /* Height of this node. Leaf==1 */
+ short int imbalance; /* Height difference between pBefore and pAfter */
+};
+
+/* Recompute the closure_avl.height and closure_avl.imbalance fields for p.
+** Assume that the children of p have correct heights.
+*/
+static void closureAvlRecomputeHeight(closure_avl *p){
+ short int hBefore = p->pBefore ? p->pBefore->height : 0;
+ short int hAfter = p->pAfter ? p->pAfter->height : 0;
+ p->imbalance = hBefore - hAfter; /* -: pAfter higher. +: pBefore higher */
+ p->height = (hBefore>hAfter ? hBefore : hAfter)+1;
+}
+
+/*
+** P B
+** / \ / \
+** B Z ==> X P
+** / \ / \
+** X Y Y Z
+**
+*/
+static closure_avl *closureAvlRotateBefore(closure_avl *pP){
+ closure_avl *pB = pP->pBefore;
+ closure_avl *pY = pB->pAfter;
+ pB->pUp = pP->pUp;
+ pB->pAfter = pP;
+ pP->pUp = pB;
+ pP->pBefore = pY;
+ if( pY ) pY->pUp = pP;
+ closureAvlRecomputeHeight(pP);
+ closureAvlRecomputeHeight(pB);
+ return pB;
+}
+
+/*
+** P A
+** / \ / \
+** X A ==> P Z
+** / \ / \
+** Y Z X Y
+**
+*/
+static closure_avl *closureAvlRotateAfter(closure_avl *pP){
+ closure_avl *pA = pP->pAfter;
+ closure_avl *pY = pA->pBefore;
+ pA->pUp = pP->pUp;
+ pA->pBefore = pP;
+ pP->pUp = pA;
+ pP->pAfter = pY;
+ if( pY ) pY->pUp = pP;
+ closureAvlRecomputeHeight(pP);
+ closureAvlRecomputeHeight(pA);
+ return pA;
+}
+
+/*
+** Return a pointer to the pBefore or pAfter pointer in the parent
+** of p that points to p. Or if p is the root node, return pp.
+*/
+static closure_avl **closureAvlFromPtr(closure_avl *p, closure_avl **pp){
+ closure_avl *pUp = p->pUp;
+ if( pUp==0 ) return pp;
+ if( pUp->pAfter==p ) return &pUp->pAfter;
+ return &pUp->pBefore;
+}
+
+/*
+** Rebalance all nodes starting with p and working up to the root.
+** Return the new root.
+*/
+static closure_avl *closureAvlBalance(closure_avl *p){
+ closure_avl *pTop = p;
+ closure_avl **pp;
+ while( p ){
+ closureAvlRecomputeHeight(p);
+ if( p->imbalance>=2 ){
+ closure_avl *pB = p->pBefore;
+ if( pB->imbalance<0 ) p->pBefore = closureAvlRotateAfter(pB);
+ pp = closureAvlFromPtr(p,&p);
+ p = *pp = closureAvlRotateBefore(p);
+ }else if( p->imbalance<=(-2) ){
+ closure_avl *pA = p->pAfter;
+ if( pA->imbalance>0 ) p->pAfter = closureAvlRotateBefore(pA);
+ pp = closureAvlFromPtr(p,&p);
+ p = *pp = closureAvlRotateAfter(p);
+ }
+ pTop = p;
+ p = p->pUp;
+ }
+ return pTop;
+}
+
+/* Search the tree rooted at p for an entry with id. Return a pointer
+** to the entry or return NULL.
+*/
+static closure_avl *closureAvlSearch(closure_avl *p, sqlite3_int64 id){
+ while( p && id!=p->id ){
+ p = (id<p->id) ? p->pBefore : p->pAfter;
+ }
+ return p;
+}
+
+/* Find the first node (the one with the smallest key).
+*/
+static closure_avl *closureAvlFirst(closure_avl *p){
+ if( p ) while( p->pBefore ) p = p->pBefore;
+ return p;
+}
+
+/* Return the node with the next larger key after p.
+*/
+closure_avl *closureAvlNext(closure_avl *p){
+ closure_avl *pPrev = 0;
+ while( p && p->pAfter==pPrev ){
+ pPrev = p;
+ p = p->pUp;
+ }
+ if( p && pPrev==0 ){
+ p = closureAvlFirst(p->pAfter);
+ }
+ return p;
+}
+
+/* Insert a new node pNew. Return NULL on success. If the key is not
+** unique, then do not perform the insert but instead leave pNew unchanged
+** and return a pointer to an existing node with the same key.
+*/
+static closure_avl *closureAvlInsert(
+ closure_avl **ppHead, /* Head of the tree */
+ closure_avl *pNew /* New node to be inserted */
+){
+ closure_avl *p = *ppHead;
+ if( p==0 ){
+ p = pNew;
+ pNew->pUp = 0;
+ }else{
+ while( p ){
+ if( pNew->id<p->id ){
+ if( p->pBefore ){
+ p = p->pBefore;
+ }else{
+ p->pBefore = pNew;
+ pNew->pUp = p;
+ break;
+ }
+ }else if( pNew->id>p->id ){
+ if( p->pAfter ){
+ p = p->pAfter;
+ }else{
+ p->pAfter = pNew;
+ pNew->pUp = p;
+ break;
+ }
+ }else{
+ return p;
+ }
+ }
+ }
+ pNew->pBefore = 0;
+ pNew->pAfter = 0;
+ pNew->height = 1;
+ pNew->imbalance = 0;
+ *ppHead = closureAvlBalance(p);
+ return 0;
+}
+
+/* Walk the tree can call xDestroy on each node
+*/
+static void closureAvlDestroy(closure_avl *p, void (*xDestroy)(closure_avl*)){
+ if( p ){
+ closureAvlDestroy(p->pBefore, xDestroy);
+ closureAvlDestroy(p->pAfter, xDestroy);
+ xDestroy(p);
+ }
+}
+/*
+** End of the AVL Tree implementation
+******************************************************************************/
+
+/*
+** A closure virtual-table object
+*/
+struct closure_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ char *zDb; /* Name of database. (ex: "main") */
+ char *zSelf; /* Name of this virtual table */
+ char *zTableName; /* Name of table holding parent/child relation */
+ char *zIdColumn; /* Name of ID column of zTableName */
+ char *zParentColumn; /* Name of PARENT column in zTableName */
+ sqlite3 *db; /* The database connection */
+ int nCursor; /* Number of pending cursors */
+};
+
+/* A closure cursor object */
+struct closure_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ closure_vtab *pVtab; /* The virtual table this cursor belongs to */
+ char *zTableName; /* Name of table holding parent/child relation */
+ char *zIdColumn; /* Name of ID column of zTableName */
+ char *zParentColumn; /* Name of PARENT column in zTableName */
+ closure_avl *pCurrent; /* Current element of output */
+ closure_avl *pClosure; /* The complete closure tree */
+};
+
+/* A queue of AVL nodes */
+struct closure_queue {
+ closure_avl *pFirst; /* Oldest node on the queue */
+ closure_avl *pLast; /* Youngest node on the queue */
+};
+
+/*
+** Add a node to the end of the queue
+*/
+static void queuePush(closure_queue *pQueue, closure_avl *pNode){
+ pNode->pList = 0;
+ if( pQueue->pLast ){
+ pQueue->pLast->pList = pNode;
+ }else{
+ pQueue->pFirst = pNode;
+ }
+ pQueue->pLast = pNode;
+}
+
+/*
+** Extract the oldest element (the front element) from the queue.
+*/
+static closure_avl *queuePull(closure_queue *pQueue){
+ closure_avl *p = pQueue->pFirst;
+ if( p ){
+ pQueue->pFirst = p->pList;
+ if( pQueue->pFirst==0 ) pQueue->pLast = 0;
+ }
+ return p;
+}
+
+/*
+** This function converts an SQL quoted string into an unquoted string
+** and returns a pointer to a buffer allocated using sqlite3_malloc()
+** containing the result. The caller should eventually free this buffer
+** using sqlite3_free.
+**
+** Examples:
+**
+** "abc" becomes abc
+** 'xyz' becomes xyz
+** [pqr] becomes pqr
+** `mno` becomes mno
+*/
+static char *closureDequote(const char *zIn){
+ size_t nIn; /* Size of input string, in bytes */
+ char *zOut; /* Output (dequoted) string */
+
+ nIn = strlen(zIn);
+ zOut = sqlite3_malloc(nIn+1);
+ if( zOut ){
+ char q = zIn[0]; /* Quote character (if any ) */
+
+ if( q!='[' && q!= '\'' && q!='"' && q!='`' ){
+ memcpy(zOut, zIn, (size_t)(nIn+1));
+ }else{
+ size_t iOut = 0; /* Index of next byte to write to output */
+ size_t iIn; /* Index of next byte to read from input */
+
+ if( q=='[' ) q = ']';
+ for(iIn=1; iIn<nIn; iIn++){
+ if( zIn[iIn]==q ) iIn++;
+ zOut[iOut++] = zIn[iIn];
+ }
+ }
+ assert( strlen(zOut)<=nIn );
+ }
+ return zOut;
+}
+
+/*
+** Deallocate an closure_vtab object
+*/
+static void closureFree(closure_vtab *p){
+ if( p ){
+ sqlite3_free(p->zDb);
+ sqlite3_free(p->zSelf);
+ sqlite3_free(p->zTableName);
+ sqlite3_free(p->zIdColumn);
+ sqlite3_free(p->zParentColumn);
+ memset(p, 0, sizeof(*p));
+ sqlite3_free(p);
+ }
+}
+
+/*
+** xDisconnect/xDestroy method for the closure module.
+*/
+static int closureDisconnect(sqlite3_vtab *pVtab){
+ closure_vtab *p = (closure_vtab*)pVtab;
+ assert( p->nCursor==0 );
+ closureFree(p);
+ return SQLITE_OK;
+}
+
+/*
+** Check to see if the argument is of the form:
+**
+** KEY = VALUE
+**
+** If it is, return a pointer to the first character of VALUE.
+** If not, return NULL. Spaces around the = are ignored.
+*/
+static const char *closureValueOfKey(const char *zKey, const char *zStr){
+ int nKey = (int)strlen(zKey);
+ int nStr = (int)strlen(zStr);
+ int i;
+ if( nStr<nKey+1 ) return 0;
+ if( memcmp(zStr, zKey, nKey)!=0 ) return 0;
+ for(i=nKey; isspace((unsigned char)zStr[i]); i++){}
+ if( zStr[i]!='=' ) return 0;
+ i++;
+ while( isspace((unsigned char)zStr[i]) ){ i++; }
+ return zStr+i;
+}
+
+/*
+** xConnect/xCreate method for the closure module. Arguments are:
+**
+** argv[0] -> module name ("transitive_closure")
+** argv[1] -> database name
+** argv[2] -> table name
+** argv[3...] -> arguments
+*/
+static int closureConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ int rc = SQLITE_OK; /* Return code */
+ closure_vtab *pNew = 0; /* New virtual table */
+ const char *zDb = argv[1];
+ const char *zVal;
+ int i;
+
+ (void)pAux;
+ *ppVtab = 0;
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ if( pNew==0 ) return SQLITE_NOMEM;
+ rc = SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->db = db;
+ pNew->zDb = sqlite3_mprintf("%s", zDb);
+ if( pNew->zDb==0 ) goto closureConnectError;
+ pNew->zSelf = sqlite3_mprintf("%s", argv[2]);
+ if( pNew->zSelf==0 ) goto closureConnectError;
+ for(i=3; i<argc; i++){
+ zVal = closureValueOfKey("tablename", argv[i]);
+ if( zVal ){
+ sqlite3_free(pNew->zTableName);
+ pNew->zTableName = closureDequote(zVal);
+ if( pNew->zTableName==0 ) goto closureConnectError;
+ continue;
+ }
+ zVal = closureValueOfKey("idcolumn", argv[i]);
+ if( zVal ){
+ sqlite3_free(pNew->zIdColumn);
+ pNew->zIdColumn = closureDequote(zVal);
+ if( pNew->zIdColumn==0 ) goto closureConnectError;
+ continue;
+ }
+ zVal = closureValueOfKey("parentcolumn", argv[i]);
+ if( zVal ){
+ sqlite3_free(pNew->zParentColumn);
+ pNew->zParentColumn = closureDequote(zVal);
+ if( pNew->zParentColumn==0 ) goto closureConnectError;
+ continue;
+ }
+ *pzErr = sqlite3_mprintf("unrecognized argument: [%s]\n", argv[i]);
+ closureFree(pNew);
+ *ppVtab = 0;
+ return SQLITE_ERROR;
+ }
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x(id,depth,root HIDDEN,tablename HIDDEN,"
+ "idcolumn HIDDEN,parentcolumn HIDDEN)"
+ );
+#define CLOSURE_COL_ID 0
+#define CLOSURE_COL_DEPTH 1
+#define CLOSURE_COL_ROOT 2
+#define CLOSURE_COL_TABLENAME 3
+#define CLOSURE_COL_IDCOLUMN 4
+#define CLOSURE_COL_PARENTCOLUMN 5
+ if( rc!=SQLITE_OK ){
+ closureFree(pNew);
+ }
+ *ppVtab = &pNew->base;
+ return rc;
+
+closureConnectError:
+ closureFree(pNew);
+ return rc;
+}
+
+/*
+** Open a new closure cursor.
+*/
+static int closureOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+ closure_vtab *p = (closure_vtab*)pVTab;
+ closure_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ pCur->pVtab = p;
+ *ppCursor = &pCur->base;
+ p->nCursor++;
+ return SQLITE_OK;
+}
+
+/*
+** Free up all the memory allocated by a cursor. Set it rLimit to 0
+** to indicate that it is at EOF.
+*/
+static void closureClearCursor(closure_cursor *pCur){
+ closureAvlDestroy(pCur->pClosure, (void(*)(closure_avl*))sqlite3_free);
+ sqlite3_free(pCur->zTableName);
+ sqlite3_free(pCur->zIdColumn);
+ sqlite3_free(pCur->zParentColumn);
+ pCur->zTableName = 0;
+ pCur->zIdColumn = 0;
+ pCur->zParentColumn = 0;
+ pCur->pCurrent = 0;
+ pCur->pClosure = 0;
+}
+
+/*
+** Close a closure cursor.
+*/
+static int closureClose(sqlite3_vtab_cursor *cur){
+ closure_cursor *pCur = (closure_cursor *)cur;
+ closureClearCursor(pCur);
+ pCur->pVtab->nCursor--;
+ sqlite3_free(pCur);
+ return SQLITE_OK;
+}
+
+/*
+** Advance a cursor to its next row of output
+*/
+static int closureNext(sqlite3_vtab_cursor *cur){
+ closure_cursor *pCur = (closure_cursor*)cur;
+ pCur->pCurrent = closureAvlNext(pCur->pCurrent);
+ return SQLITE_OK;
+}
+
+/*
+** Allocate and insert a node
+*/
+static int closureInsertNode(
+ closure_queue *pQueue, /* Add new node to this queue */
+ closure_cursor *pCur, /* The cursor into which to add the node */
+ sqlite3_int64 id, /* The node ID */
+ int iGeneration /* The generation number for this node */
+){
+ closure_avl *pNew = sqlite3_malloc( sizeof(*pNew) );
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->id = id;
+ pNew->iGeneration = iGeneration;
+ closureAvlInsert(&pCur->pClosure, pNew);
+ queuePush(pQueue, pNew);
+ return SQLITE_OK;
+}
+
+/*
+** Called to "rewind" a cursor back to the beginning so that
+** it starts its output over again. Always called at least once
+** prior to any closureColumn, closureRowid, or closureEof call.
+**
+** This routine actually computes the closure.
+**
+** See the comment at the beginning of closureBestIndex() for a
+** description of the meaning of idxNum. The idxStr parameter is
+** not used.
+*/
+static int closureFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ closure_cursor *pCur = (closure_cursor *)pVtabCursor;
+ closure_vtab *pVtab = pCur->pVtab;
+ sqlite3_int64 iRoot;
+ int mxGen = 999999999;
+ char *zSql;
+ sqlite3_stmt *pStmt;
+ closure_avl *pAvl;
+ int rc = SQLITE_OK;
+ const char *zTableName = pVtab->zTableName;
+ const char *zIdColumn = pVtab->zIdColumn;
+ const char *zParentColumn = pVtab->zParentColumn;
+ closure_queue sQueue;
+
+ (void)idxStr; /* Unused parameter */
+ (void)argc; /* Unused parameter */
+ closureClearCursor(pCur);
+ memset(&sQueue, 0, sizeof(sQueue));
+ if( (idxNum & 1)==0 ){
+ /* No root=$root in the WHERE clause. Return an empty set */
+ return SQLITE_OK;
+ }
+ iRoot = sqlite3_value_int64(argv[0]);
+ if( (idxNum & 0x000f0)!=0 ){
+ mxGen = sqlite3_value_int(argv[(idxNum>>4)&0x0f]);
+ if( (idxNum & 0x00002)!=0 ) mxGen--;
+ }
+ if( (idxNum & 0x00f00)!=0 ){
+ zTableName = (const char*)sqlite3_value_text(argv[(idxNum>>8)&0x0f]);
+ pCur->zTableName = sqlite3_mprintf("%s", zTableName);
+ }
+ if( (idxNum & 0x0f000)!=0 ){
+ zIdColumn = (const char*)sqlite3_value_text(argv[(idxNum>>12)&0x0f]);
+ pCur->zIdColumn = sqlite3_mprintf("%s", zIdColumn);
+ }
+ if( (idxNum & 0x0f0000)!=0 ){
+ zParentColumn = (const char*)sqlite3_value_text(argv[(idxNum>>16)&0x0f]);
+ pCur->zParentColumn = sqlite3_mprintf("%s", zParentColumn);
+ }
+
+ zSql = sqlite3_mprintf(
+ "SELECT \"%w\".\"%w\" FROM \"%w\" WHERE \"%w\".\"%w\"=?1",
+ zTableName, zIdColumn, zTableName, zTableName, zParentColumn);
+ if( zSql==0 ){
+ return SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_prepare_v2(pVtab->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ if( rc ){
+ sqlite3_free(pVtab->base.zErrMsg);
+ pVtab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pVtab->db));
+ return rc;
+ }
+ }
+ if( rc==SQLITE_OK ){
+ rc = closureInsertNode(&sQueue, pCur, iRoot, 0);
+ }
+ while( (pAvl = queuePull(&sQueue))!=0 ){
+ if( pAvl->iGeneration>=mxGen ) continue;
+ sqlite3_bind_int64(pStmt, 1, pAvl->id);
+ while( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
+ if( sqlite3_column_type(pStmt,0)==SQLITE_INTEGER ){
+ sqlite3_int64 iNew = sqlite3_column_int64(pStmt, 0);
+ if( closureAvlSearch(pCur->pClosure, iNew)==0 ){
+ rc = closureInsertNode(&sQueue, pCur, iNew, pAvl->iGeneration+1);
+ }
+ }
+ }
+ sqlite3_reset(pStmt);
+ }
+ sqlite3_finalize(pStmt);
+ if( rc==SQLITE_OK ){
+ pCur->pCurrent = closureAvlFirst(pCur->pClosure);
+ }
+
+ return rc;
+}
+
+/*
+** Only the word and distance columns have values. All other columns
+** return NULL
+*/
+static int closureColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
+ closure_cursor *pCur = (closure_cursor*)cur;
+ switch( i ){
+ case CLOSURE_COL_ID: {
+ sqlite3_result_int64(ctx, pCur->pCurrent->id);
+ break;
+ }
+ case CLOSURE_COL_DEPTH: {
+ sqlite3_result_int(ctx, pCur->pCurrent->iGeneration);
+ break;
+ }
+ case CLOSURE_COL_ROOT: {
+ sqlite3_result_null(ctx);
+ break;
+ }
+ case CLOSURE_COL_TABLENAME: {
+ sqlite3_result_text(ctx,
+ pCur->zTableName ? pCur->zTableName : pCur->pVtab->zTableName,
+ -1, SQLITE_TRANSIENT);
+ break;
+ }
+ case CLOSURE_COL_IDCOLUMN: {
+ sqlite3_result_text(ctx,
+ pCur->zIdColumn ? pCur->zIdColumn : pCur->pVtab->zIdColumn,
+ -1, SQLITE_TRANSIENT);
+ break;
+ }
+ case CLOSURE_COL_PARENTCOLUMN: {
+ sqlite3_result_text(ctx,
+ pCur->zParentColumn ? pCur->zParentColumn : pCur->pVtab->zParentColumn,
+ -1, SQLITE_TRANSIENT);
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** The rowid. For the closure table, this is the same as the "id" column.
+*/
+static int closureRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ closure_cursor *pCur = (closure_cursor*)cur;
+ *pRowid = pCur->pCurrent->id;
+ return SQLITE_OK;
+}
+
+/*
+** EOF indicator
+*/
+static int closureEof(sqlite3_vtab_cursor *cur){
+ closure_cursor *pCur = (closure_cursor*)cur;
+ return pCur->pCurrent==0;
+}
+
+/*
+** Search for terms of these forms:
+**
+** (A) root = $root
+** (B1) depth < $depth
+** (B2) depth <= $depth
+** (B3) depth = $depth
+** (C) tablename = $tablename
+** (D) idcolumn = $idcolumn
+** (E) parentcolumn = $parentcolumn
+**
+**
+**
+** idxNum meaning
+** ---------- ------------------------------------------------------
+** 0x00000001 Term of the form (A) found
+** 0x00000002 The term of bit-2 is like (B1)
+** 0x000000f0 Index in filter.argv[] of $depth. 0 if not used.
+** 0x00000f00 Index in filter.argv[] of $tablename. 0 if not used.
+** 0x0000f000 Index in filter.argv[] of $idcolumn. 0 if not used
+** 0x000f0000 Index in filter.argv[] of $parentcolumn. 0 if not used.
+**
+** There must be a term of type (A). If there is not, then the index type
+** is 0 and the query will return an empty set.
+*/
+static int closureBestIndex(
+ sqlite3_vtab *pTab, /* The virtual table */
+ sqlite3_index_info *pIdxInfo /* Information about the query */
+){
+ int iPlan = 0;
+ int i;
+ int idx = 1;
+ const struct sqlite3_index_constraint *pConstraint;
+ closure_vtab *pVtab = (closure_vtab*)pTab;
+ double rCost = 10000000.0;
+
+ pConstraint = pIdxInfo->aConstraint;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
+ if( pConstraint->usable==0 ) continue;
+ if( (iPlan & 1)==0
+ && pConstraint->iColumn==CLOSURE_COL_ROOT
+ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
+ ){
+ iPlan |= 1;
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ rCost /= 100.0;
+ }
+ if( (iPlan & 0x0000f0)==0
+ && pConstraint->iColumn==CLOSURE_COL_DEPTH
+ && (pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT
+ || pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE
+ || pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ)
+ ){
+ iPlan |= idx<<4;
+ pIdxInfo->aConstraintUsage[i].argvIndex = ++idx;
+ if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ) iPlan |= 0x000002;
+ rCost /= 5.0;
+ }
+ if( (iPlan & 0x000f00)==0
+ && pConstraint->iColumn==CLOSURE_COL_TABLENAME
+ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
+ ){
+ iPlan |= idx<<8;
+ pIdxInfo->aConstraintUsage[i].argvIndex = ++idx;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ rCost /= 5.0;
+ }
+ if( (iPlan & 0x00f000)==0
+ && pConstraint->iColumn==CLOSURE_COL_IDCOLUMN
+ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
+ ){
+ iPlan |= idx<<12;
+ pIdxInfo->aConstraintUsage[i].argvIndex = ++idx;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ }
+ if( (iPlan & 0x0f0000)==0
+ && pConstraint->iColumn==CLOSURE_COL_PARENTCOLUMN
+ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
+ ){
+ iPlan |= idx<<16;
+ pIdxInfo->aConstraintUsage[i].argvIndex = ++idx;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ }
+ }
+ if( (pVtab->zTableName==0 && (iPlan & 0x000f00)==0)
+ || (pVtab->zIdColumn==0 && (iPlan & 0x00f000)==0)
+ || (pVtab->zParentColumn==0 && (iPlan & 0x0f0000)==0)
+ ){
+ /* All of tablename, idcolumn, and parentcolumn must be specified
+ ** in either the CREATE VIRTUAL TABLE or in the WHERE clause constraints
+ ** or else the result is an empty set. */
+ iPlan = 0;
+ }
+ if( (iPlan&1)==0 ){
+ /* If there is no usable "root=?" term, then set the index-type to 0.
+ ** Also clear any argvIndex variables already set. This is necessary
+ ** to prevent the core from throwing an "xBestIndex malfunction error"
+ ** error (because the argvIndex values are not contiguously assigned
+ ** starting from 1). */
+ rCost *= 1e30;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
+ pIdxInfo->aConstraintUsage[i].argvIndex = 0;
+ }
+ iPlan = 0;
+ }
+ pIdxInfo->idxNum = iPlan;
+ if( pIdxInfo->nOrderBy==1
+ && pIdxInfo->aOrderBy[0].iColumn==CLOSURE_COL_ID
+ && pIdxInfo->aOrderBy[0].desc==0
+ ){
+ pIdxInfo->orderByConsumed = 1;
+ }
+ pIdxInfo->estimatedCost = rCost;
+
+ return SQLITE_OK;
+}
+
+/*
+** A virtual table module that implements the "transitive_closure".
+*/
+static const sqlite3_module closureModule = {
+ 0, /* iVersion */
+ closureConnect, /* xCreate */
+ closureConnect, /* xConnect */
+ closureBestIndex, /* xBestIndex */
+ closureDisconnect, /* xDisconnect */
+ closureDisconnect, /* xDestroy */
+ closureOpen, /* xOpen - open a cursor */
+ closureClose, /* xClose - close a cursor */
+ closureFilter, /* xFilter - configure scan constraints */
+ closureNext, /* xNext - advance a cursor */
+ closureEof, /* xEof - check for end of scan */
+ closureColumn, /* xColumn - read data */
+ closureRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
+};
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+/*
+** Register the closure virtual table
+*/
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_closure_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3_create_module(db, "transitive_closure", &closureModule, 0);
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3_create_module(db, "transitive_closure", &closureModule, 0);
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+ return rc;
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/completion.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/completion.c 2019-10-08 13:42:19.095885700 +0200
@@ -0,0 +1,515 @@
+/*
+** 2017-07-10
+**
+** 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 implements an eponymous virtual table that returns suggested
+** completions for a partial SQL input.
+**
+** Suggested usage:
+**
+** SELECT DISTINCT candidate COLLATE nocase
+** FROM completion($prefix,$wholeline)
+** ORDER BY 1;
+**
+** The two query parameters are optional. $prefix is the text of the
+** current word being typed and that is to be completed. $wholeline is
+** the complete input line, used for context.
+**
+** The raw completion() table might return the same candidate multiple
+** times, for example if the same column name is used to two or more
+** tables. And the candidates are returned in an arbitrary order. Hence,
+** the DISTINCT and ORDER BY are recommended.
+**
+** This virtual table operates at the speed of human typing, and so there
+** is no attempt to make it fast. Even a slow implementation will be much
+** faster than any human can type.
+**
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/* completion_vtab is a subclass of sqlite3_vtab which will
+** serve as the underlying representation of a completion virtual table
+*/
+typedef struct completion_vtab completion_vtab;
+struct completion_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this completion vtab */
+};
+
+/* completion_cursor is a subclass of sqlite3_vtab_cursor which will
+** serve as the underlying representation of a cursor that scans
+** over rows of the result
+*/
+typedef struct completion_cursor completion_cursor;
+struct completion_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this cursor */
+ int nPrefix, nLine; /* Number of bytes in zPrefix and zLine */
+ char *zPrefix; /* The prefix for the word we want to complete */
+ char *zLine; /* The whole that we want to complete */
+ const char *zCurrentRow; /* Current output row */
+ int szRow; /* Length of the zCurrentRow string */
+ sqlite3_stmt *pStmt; /* Current statement */
+ sqlite3_int64 iRowid; /* The rowid */
+ int ePhase; /* Current phase */
+ int j; /* inter-phase counter */
+};
+
+/* Values for ePhase:
+*/
+#define COMPLETION_FIRST_PHASE 1
+#define COMPLETION_KEYWORDS 1
+#define COMPLETION_PRAGMAS 2
+#define COMPLETION_FUNCTIONS 3
+#define COMPLETION_COLLATIONS 4
+#define COMPLETION_INDEXES 5
+#define COMPLETION_TRIGGERS 6
+#define COMPLETION_DATABASES 7
+#define COMPLETION_TABLES 8 /* Also VIEWs and TRIGGERs */
+#define COMPLETION_COLUMNS 9
+#define COMPLETION_MODULES 10
+#define COMPLETION_EOF 11
+
+/*
+** The completionConnect() method is invoked to create a new
+** completion_vtab that describes the completion virtual table.
+**
+** Think of this routine as the constructor for completion_vtab objects.
+**
+** All this routine needs to do is:
+**
+** (1) Allocate the completion_vtab object and initialize all fields.
+**
+** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
+** result set of queries against completion will look like.
+*/
+static int completionConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ completion_vtab *pNew;
+ int rc;
+
+ (void)(pAux); /* Unused parameter */
+ (void)(argc); /* Unused parameter */
+ (void)(argv); /* Unused parameter */
+ (void)(pzErr); /* Unused parameter */
+
+/* Column numbers */
+#define COMPLETION_COLUMN_CANDIDATE 0 /* Suggested completion of the input */
+#define COMPLETION_COLUMN_PREFIX 1 /* Prefix of the word to be completed */
+#define COMPLETION_COLUMN_WHOLELINE 2 /* Entire line seen so far */
+#define COMPLETION_COLUMN_PHASE 3 /* ePhase - used for debugging only */
+
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x("
+ " candidate TEXT,"
+ " prefix TEXT HIDDEN,"
+ " wholeline TEXT HIDDEN,"
+ " phase INT HIDDEN" /* Used for debugging only */
+ ")");
+ if( rc==SQLITE_OK ){
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->db = db;
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for completion_cursor objects.
+*/
+static int completionDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new completion_cursor object.
+*/
+static int completionOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ completion_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ pCur->db = ((completion_vtab*)p)->db;
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Reset the completion_cursor.
+*/
+static void completionCursorReset(completion_cursor *pCur){
+ sqlite3_free(pCur->zPrefix); pCur->zPrefix = 0; pCur->nPrefix = 0;
+ sqlite3_free(pCur->zLine); pCur->zLine = 0; pCur->nLine = 0;
+ sqlite3_finalize(pCur->pStmt); pCur->pStmt = 0;
+ pCur->j = 0;
+}
+
+/*
+** Destructor for a completion_cursor.
+*/
+static int completionClose(sqlite3_vtab_cursor *cur){
+ completionCursorReset((completion_cursor*)cur);
+ sqlite3_free(cur);
+ return SQLITE_OK;
+}
+
+/*
+** Advance a completion_cursor to its next row of output.
+**
+** The ->ePhase, ->j, and ->pStmt fields of the completion_cursor object
+** record the current state of the scan. This routine sets ->zCurrentRow
+** to the current row of output and then returns. If no more rows remain,
+** then ->ePhase is set to COMPLETION_EOF which will signal the virtual
+** table that has reached the end of its scan.
+**
+** The current implementation just lists potential identifiers and
+** keywords and filters them by zPrefix. Future enhancements should
+** take zLine into account to try to restrict the set of identifiers and
+** keywords based on what would be legal at the current point of input.
+*/
+static int completionNext(sqlite3_vtab_cursor *cur){
+ completion_cursor *pCur = (completion_cursor*)cur;
+ int eNextPhase = 0; /* Next phase to try if current phase reaches end */
+ int iCol = -1; /* If >=0, step pCur->pStmt and use the i-th column */
+ pCur->iRowid++;
+ while( pCur->ePhase!=COMPLETION_EOF ){
+ switch( pCur->ePhase ){
+ case COMPLETION_KEYWORDS: {
+ if( pCur->j >= sqlite3_keyword_count() ){
+ pCur->zCurrentRow = 0;
+ pCur->ePhase = COMPLETION_DATABASES;
+ }else{
+ sqlite3_keyword_name(pCur->j++, &pCur->zCurrentRow, &pCur->szRow);
+ }
+ iCol = -1;
+ break;
+ }
+ case COMPLETION_DATABASES: {
+ if( pCur->pStmt==0 ){
+ sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1,
+ &pCur->pStmt, 0);
+ }
+ iCol = 1;
+ eNextPhase = COMPLETION_TABLES;
+ break;
+ }
+ case COMPLETION_TABLES: {
+ if( pCur->pStmt==0 ){
+ sqlite3_stmt *pS2;
+ char *zSql = 0;
+ const char *zSep = "";
+ sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0);
+ while( sqlite3_step(pS2)==SQLITE_ROW ){
+ const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
+ zSql = sqlite3_mprintf(
+ "%z%s"
+ "SELECT name FROM \"%w\".sqlite_master",
+ zSql, zSep, zDb
+ );
+ if( zSql==0 ) return SQLITE_NOMEM;
+ zSep = " UNION ";
+ }
+ sqlite3_finalize(pS2);
+ sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
+ sqlite3_free(zSql);
+ }
+ iCol = 0;
+ eNextPhase = COMPLETION_COLUMNS;
+ break;
+ }
+ case COMPLETION_COLUMNS: {
+ if( pCur->pStmt==0 ){
+ sqlite3_stmt *pS2;
+ char *zSql = 0;
+ const char *zSep = "";
+ sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0);
+ while( sqlite3_step(pS2)==SQLITE_ROW ){
+ const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
+ zSql = sqlite3_mprintf(
+ "%z%s"
+ "SELECT pti.name FROM \"%w\".sqlite_master AS sm"
+ " JOIN pragma_table_info(sm.name,%Q) AS pti"
+ " WHERE sm.type='table'",
+ zSql, zSep, zDb, zDb
+ );
+ if( zSql==0 ) return SQLITE_NOMEM;
+ zSep = " UNION ";
+ }
+ sqlite3_finalize(pS2);
+ sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
+ sqlite3_free(zSql);
+ }
+ iCol = 0;
+ eNextPhase = COMPLETION_EOF;
+ break;
+ }
+ }
+ if( iCol<0 ){
+ /* This case is when the phase presets zCurrentRow */
+ if( pCur->zCurrentRow==0 ) continue;
+ }else{
+ if( sqlite3_step(pCur->pStmt)==SQLITE_ROW ){
+ /* Extract the next row of content */
+ pCur->zCurrentRow = (const char*)sqlite3_column_text(pCur->pStmt, iCol);
+ pCur->szRow = sqlite3_column_bytes(pCur->pStmt, iCol);
+ }else{
+ /* When all rows are finished, advance to the next phase */
+ sqlite3_finalize(pCur->pStmt);
+ pCur->pStmt = 0;
+ pCur->ePhase = eNextPhase;
+ continue;
+ }
+ }
+ if( pCur->nPrefix==0 ) break;
+ if( pCur->nPrefix<=pCur->szRow
+ && sqlite3_strnicmp(pCur->zPrefix, pCur->zCurrentRow, pCur->nPrefix)==0
+ ){
+ break;
+ }
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the completion_cursor
+** is currently pointing.
+*/
+static int completionColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ completion_cursor *pCur = (completion_cursor*)cur;
+ switch( i ){
+ case COMPLETION_COLUMN_CANDIDATE: {
+ sqlite3_result_text(ctx, pCur->zCurrentRow, pCur->szRow,SQLITE_TRANSIENT);
+ break;
+ }
+ case COMPLETION_COLUMN_PREFIX: {
+ sqlite3_result_text(ctx, pCur->zPrefix, -1, SQLITE_TRANSIENT);
+ break;
+ }
+ case COMPLETION_COLUMN_WHOLELINE: {
+ sqlite3_result_text(ctx, pCur->zLine, -1, SQLITE_TRANSIENT);
+ break;
+ }
+ case COMPLETION_COLUMN_PHASE: {
+ sqlite3_result_int(ctx, pCur->ePhase);
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** rowid is the same as the output value.
+*/
+static int completionRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ completion_cursor *pCur = (completion_cursor*)cur;
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int completionEof(sqlite3_vtab_cursor *cur){
+ completion_cursor *pCur = (completion_cursor*)cur;
+ return pCur->ePhase >= COMPLETION_EOF;
+}
+
+/*
+** This method is called to "rewind" the completion_cursor object back
+** to the first row of output. This method is always called at least
+** once prior to any call to completionColumn() or completionRowid() or
+** completionEof().
+*/
+static int completionFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ completion_cursor *pCur = (completion_cursor *)pVtabCursor;
+ int iArg = 0;
+ (void)(idxStr); /* Unused parameter */
+ (void)(argc); /* Unused parameter */
+ completionCursorReset(pCur);
+ if( idxNum & 1 ){
+ pCur->nPrefix = sqlite3_value_bytes(argv[iArg]);
+ if( pCur->nPrefix>0 ){
+ pCur->zPrefix = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg]));
+ if( pCur->zPrefix==0 ) return SQLITE_NOMEM;
+ }
+ iArg = 1;
+ }
+ if( idxNum & 2 ){
+ pCur->nLine = sqlite3_value_bytes(argv[iArg]);
+ if( pCur->nLine>0 ){
+ pCur->zLine = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg]));
+ if( pCur->zLine==0 ) return SQLITE_NOMEM;
+ }
+ }
+ if( pCur->zLine!=0 && pCur->zPrefix==0 ){
+ int i = pCur->nLine;
+ while( i>0 && (isalnum(pCur->zLine[i-1]) || pCur->zLine[i-1]=='_') ){
+ i--;
+ }
+ pCur->nPrefix = pCur->nLine - i;
+ if( pCur->nPrefix>0 ){
+ pCur->zPrefix = sqlite3_mprintf("%.*s", pCur->nPrefix, pCur->zLine + i);
+ if( pCur->zPrefix==0 ) return SQLITE_NOMEM;
+ }
+ }
+ pCur->iRowid = 0;
+ pCur->ePhase = COMPLETION_FIRST_PHASE;
+ return completionNext(pVtabCursor);
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the completion virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+**
+** There are two hidden parameters that act as arguments to the table-valued
+** function: "prefix" and "wholeline". Bit 0 of idxNum is set if "prefix"
+** is available and bit 1 is set if "wholeline" is available.
+*/
+static int completionBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int i; /* Loop over constraints */
+ int idxNum = 0; /* The query plan bitmask */
+ int prefixIdx = -1; /* Index of the start= constraint, or -1 if none */
+ int wholelineIdx = -1; /* Index of the stop= constraint, or -1 if none */
+ int nArg = 0; /* Number of arguments that completeFilter() expects */
+ const struct sqlite3_index_constraint *pConstraint;
+
+ (void)(tab); /* Unused parameter */
+ pConstraint = pIdxInfo->aConstraint;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
+ if( pConstraint->usable==0 ) continue;
+ if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+ switch( pConstraint->iColumn ){
+ case COMPLETION_COLUMN_PREFIX:
+ prefixIdx = i;
+ idxNum |= 1;
+ break;
+ case COMPLETION_COLUMN_WHOLELINE:
+ wholelineIdx = i;
+ idxNum |= 2;
+ break;
+ }
+ }
+ if( prefixIdx>=0 ){
+ pIdxInfo->aConstraintUsage[prefixIdx].argvIndex = ++nArg;
+ pIdxInfo->aConstraintUsage[prefixIdx].omit = 1;
+ }
+ if( wholelineIdx>=0 ){
+ pIdxInfo->aConstraintUsage[wholelineIdx].argvIndex = ++nArg;
+ pIdxInfo->aConstraintUsage[wholelineIdx].omit = 1;
+ }
+ pIdxInfo->idxNum = idxNum;
+ pIdxInfo->estimatedCost = (double)5000 - 1000*nArg;
+ pIdxInfo->estimatedRows = 500 - 100*nArg;
+ return SQLITE_OK;
+}
+
+/*
+** This following structure defines all the methods for the
+** completion virtual table.
+*/
+static const sqlite3_module completionModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ completionConnect, /* xConnect */
+ completionBestIndex, /* xBestIndex */
+ completionDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ completionOpen, /* xOpen - open a cursor */
+ completionClose, /* xClose - close a cursor */
+ completionFilter, /* xFilter - configure scan constraints */
+ completionNext, /* xNext - advance a cursor */
+ completionEof, /* xEof - check for end of scan */
+ completionColumn, /* xColumn - read data */
+ completionRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
+};
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+int sqlite3CompletionVtabInit(sqlite3 *db){
+ int rc = SQLITE_OK;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3_create_module(db, "completion", &completionModule, 0);
+#endif
+ return rc;
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_completion_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)(pzErrMsg); /* Unused parameter */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3CompletionVtabInit(db);
+#endif
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)(pzErrMsg); /* Unused parameter */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3CompletionVtabInit(db);
+#endif
+ return rc;
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/compress.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/compress.c 2019-10-08 13:42:19.101744500 +0200
@@ -0,0 +1,193 @@
+/*
+** 2014-06-13
+**
+** 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 SQLite extension implements SQL compression functions
+** compress() and uncompress() using ZLIB.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <zlib.h>
+
+/*
+** Implementation of the "compress(X)" SQL function. The input X is
+** compressed using zLib and the output is returned.
+**
+** The output is a BLOB that begins with an integer that forming the
+** input size in bytes (the size of X before compression). The variable-
+** length integer is implemented as 1 to 5 bytes. If the first byte is 0,
+** 4 bytes are used, the most significant bits first. Otherwise there are
+** seven bits per integer stored in the lower seven bits of each byte.
+** More significant bits occur first. The most significant bit (0x80)
+** is a flag to indicate the end of the integer.
+**
+** This function, SQLAR, and ZIP all use the same "deflate" compression
+** algorithm, but each is subtly different:
+**
+** * ZIP uses raw deflate.
+**
+** * SQLAR uses the "zlib format" which is raw deflate with a two-byte
+** algorithm-identification header and a four-byte checksum at the end.
+**
+** * This utility uses the "zlib format" like SQLAR, but adds the variable-
+** length integer uncompressed size value at the beginning.
+**
+** This function might be extended in the future to support compression
+** formats other than deflate, by providing a different algorithm-id
+** mark following the variable-length integer size parameter.
+*/
+static void compressFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const unsigned char *pIn;
+ unsigned char *pOut;
+ size_t nIn;
+ unsigned long int nOut;
+ int j, rc;
+
+ pIn = sqlite3_value_blob(argv[0]);
+ nIn = sqlite3_value_bytes(argv[0]);
+ nOut = 13 + nIn + (nIn+999)/1000;
+ pOut = sqlite3_malloc( nOut+5 );
+ if( (nIn<=0xffffff) || (!(nIn&0x80)&&!(nIn&0x8000)&&!(nIn&0x800000))) {
+ pOut[0] = nIn>>24 & 0xff;
+ pOut[1] = nIn>>16 & 0xff;
+ pOut[2] = nIn>>8 & 0xff;
+ pOut[3] = nIn & 0xff;
+ j = 4;
+ }else{
+ int i;
+ unsigned char x[8];
+ for(i=4; i>=0; i--){
+ x[i] = (nIn >> (7*(4-i)))&0x7f;
+ }
+ for(i=0; i<4 && x[i]==0; i++){}
+ for(j=0; i<=4; i++, j++) pOut[j] = x[i];
+ pOut[j-1] |= 0x80;
+ }
+ rc = compress(&pOut[j], &nOut, pIn, nIn);
+ if( rc==Z_OK ){
+ sqlite3_result_blob(context, pOut, nOut+j, sqlite3_free);
+ }else{
+ sqlite3_free(pOut);
+ sqlite3_result_error(context, "input cannot be zlib compressed", -1);
+ }
+}
+
+/*
+** Implementation of the "uncompress(X)" SQL function. The argument X
+** is a blob which was obtained from compress(Y). The output will be
+** the value Y.
+*/
+static void uncompressFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const unsigned char *pIn;
+ unsigned char *pOut;
+ unsigned int nIn;
+ unsigned long nOut;
+ int rc;
+
+ pIn = sqlite3_value_blob(argv[0]);
+ nIn = sqlite3_value_bytes(argv[0]);
+ nOut = (pIn[0]<<24) + (pIn[1]<<16) + (pIn[2]<<8) + pIn[3];
+ if( pIn[0] ){
+ unsigned long nOut2 = 0;
+ int i;
+
+ /*
+ ** If the high-byte of the blob length > 0, there are actually
+ ** two possibilities:
+ ** 1) The blob is > 16MByte, possible but unlikely as most blobs
+ ** are not that big.
+ ** 2) The content was compressed with SQLite's ext/misc/compress.c
+ **
+ ** Just try both possibilities (smallest first), if the decompression
+ ** fails (either by Z_BUF_ERROR or Z_DATA_ERROR) we will find out quick
+ ** enough which one was correct.
+ */
+ for(i=0; i<nIn && i<5; i++){
+ nOut2 = (nOut2<<7) | (pIn[i]&0x7f);
+ if( (pIn[i]&0x80)!=0 ){ i++; break; }
+ }
+ if( (nOut < nOut2) || (i==5 && (pIn[4]^0x80)&0xf0) ){
+ pOut = sqlite3_malloc( nOut+1 );
+ rc = uncompress(pOut, &nOut, &pIn[4], nIn-4);
+ if( rc==Z_OK ){
+ sqlite3_result_blob(context, pOut, nOut, sqlite3_free);
+ return;
+ }
+ sqlite3_free(pOut);
+ }
+ pOut = sqlite3_malloc( nOut2+1 );
+ rc = uncompress(pOut, &nOut2, &pIn[i], nIn-i);
+ if( rc==Z_OK ){
+ sqlite3_result_blob(context, pOut, nOut2, sqlite3_free);
+ return;
+ }
+ if( nOut < nOut2 ){
+ goto error;
+ }
+ sqlite3_free(pOut);
+ }
+ pOut = sqlite3_malloc( nOut+1 );
+ rc = uncompress(pOut, &nOut, &pIn[4], nIn-4);
+ if( rc==Z_OK ){
+ sqlite3_result_blob(context, pOut, nOut, sqlite3_free);
+ }else{
+ error:
+ sqlite3_free(pOut);
+ sqlite3_result_error(context, "input is not zlib compressed", -1);
+ }
+}
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_compress_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
+ compressFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "uncompress", 1, SQLITE_UTF8, 0,
+ uncompressFunc, 0, 0);
+ }
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
+ compressFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "uncompress", 1, SQLITE_UTF8, 0,
+ uncompressFunc, 0, 0);
+ }
+ return rc;
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/configure.ac 2019-10-04 18:28:13.000000000 +0200
+++ src/sqlite-autoconf-3300000/configure.ac 2019-10-08 13:01:03.774513500 +0200
@@ -25,7 +25,8 @@ AC_PROG_LIBTOOL
AC_PROG_MKDIR_P
# Check for library functions that SQLite can optionally use.
-AC_CHECK_FUNCS([fdatasync usleep fullfsync localtime_r gmtime_r])
+AC_CHECK_HEADERS([malloc.h])
+AC_CHECK_FUNCS([fdatasync usleep strchrnul localtime_r gmtime_r localtime_s malloc_usable_size utime flock readlink lstat pread pread64 pwrite pwrite64])
AC_FUNC_STRERROR_R
AC_CONFIG_FILES([Makefile sqlite3.pc])
--- origsrc/sqlite-autoconf-3300000/csv.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/csv.c 2019-10-08 13:42:19.106625800 +0200
@@ -0,0 +1,958 @@
+/*
+** 2016-05-28
+**
+** 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 the implementation of an SQLite virtual table for
+** reading CSV files.
+**
+** Usage:
+**
+** .load ./csv
+** CREATE VIRTUAL TABLE temp.csv USING csv(filename=FILENAME);
+** SELECT * FROM csv;
+**
+** The columns are named "c1", "c2", "c3", ... by default. Or the
+** application can define its own CREATE TABLE statement using the
+** schema= parameter, like this:
+**
+** CREATE VIRTUAL TABLE temp.csv2 USING csv(
+** filename = "../http.log",
+** schema = "CREATE TABLE x(date,ipaddr,url,referrer,userAgent)"
+** );
+**
+** Instead of specifying a file, the text of the CSV can be loaded using
+** the data= parameter.
+**
+** If the columns=N parameter is supplied, then the CSV file is assumed to have
+** N columns. If both the columns= and schema= parameters are omitted, then
+** the number and names of the columns is determined by the first line of
+** the CSV input.
+**
+** Some extra debugging features (used for testing virtual tables) are available
+** if this module is compiled with -DSQLITE_TEST.
+*/
+#include <sqlite3ext.h>
+SQLITE_EXTENSION_INIT1
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/*
+** A macro to hint to the compiler that a function should not be
+** inlined.
+*/
+#if defined(__GNUC__)
+# define CSV_NOINLINE __attribute__((noinline))
+#elif defined(_MSC_VER) && _MSC_VER>=1310
+# define CSV_NOINLINE __declspec(noinline)
+#else
+# define CSV_NOINLINE
+#endif
+
+
+/* Max size of the error message in a CsvReader */
+#define CSV_MXERR 200
+
+/* Size of the CsvReader input buffer */
+#define CSV_INBUFSZ 1024
+
+/* A context object used when read a CSV file. */
+typedef struct CsvReader CsvReader;
+struct CsvReader {
+ FILE *in; /* Read the CSV text from this input stream */
+ char *z; /* Accumulated text for a field */
+ int n; /* Number of bytes in z */
+ int nAlloc; /* Space allocated for z[] */
+ int nLine; /* Current line number */
+ int bNotFirst; /* True if prior text has been seen */
+ int cTerm; /* Character that terminated the most recent field */
+ size_t iIn; /* Next unread character in the input buffer */
+ size_t nIn; /* Number of characters in the input buffer */
+ char *zIn; /* The input buffer */
+ char zErr[CSV_MXERR]; /* Error message */
+};
+
+/* Initialize a CsvReader object */
+static void csv_reader_init(CsvReader *p){
+ p->in = 0;
+ p->z = 0;
+ p->n = 0;
+ p->nAlloc = 0;
+ p->nLine = 0;
+ p->bNotFirst = 0;
+ p->nIn = 0;
+ p->zIn = 0;
+ p->zErr[0] = 0;
+}
+
+/* Close and reset a CsvReader object */
+static void csv_reader_reset(CsvReader *p){
+ if( p->in ){
+ fclose(p->in);
+ sqlite3_free(p->zIn);
+ }
+ sqlite3_free(p->z);
+ csv_reader_init(p);
+}
+
+/* Report an error on a CsvReader */
+static void csv_errmsg(CsvReader *p, const char *zFormat, ...){
+ va_list ap;
+ va_start(ap, zFormat);
+ sqlite3_vsnprintf(CSV_MXERR, p->zErr, zFormat, ap);
+ va_end(ap);
+}
+
+/* Open the file associated with a CsvReader
+** Return the number of errors.
+*/
+static int csv_reader_open(
+ CsvReader *p, /* The reader to open */
+ const char *zFilename, /* Read from this filename */
+ const char *zData /* ... or use this data */
+){
+ if( zFilename ){
+ p->zIn = sqlite3_malloc( CSV_INBUFSZ );
+ if( p->zIn==0 ){
+ csv_errmsg(p, "out of memory");
+ return 1;
+ }
+ p->in = fopen(zFilename, "rb");
+ if( p->in==0 ){
+ sqlite3_free(p->zIn);
+ csv_reader_reset(p);
+ csv_errmsg(p, "cannot open '%s' for reading", zFilename);
+ return 1;
+ }
+ }else{
+ assert( p->in==0 );
+ p->zIn = (char*)zData;
+ p->nIn = strlen(zData);
+ }
+ return 0;
+}
+
+/* The input buffer has overflowed. Refill the input buffer, then
+** return the next character
+*/
+static CSV_NOINLINE int csv_getc_refill(CsvReader *p){
+ size_t got;
+
+ assert( p->iIn>=p->nIn ); /* Only called on an empty input buffer */
+ assert( p->in!=0 ); /* Only called if reading froma file */
+
+ got = fread(p->zIn, 1, CSV_INBUFSZ, p->in);
+ if( got==0 ) return EOF;
+ p->nIn = got;
+ p->iIn = 1;
+ return p->zIn[0];
+}
+
+/* Return the next character of input. Return EOF at end of input. */
+static int csv_getc(CsvReader *p){
+ if( p->iIn >= p->nIn ){
+ if( p->in!=0 ) return csv_getc_refill(p);
+ return EOF;
+ }
+ return ((unsigned char*)p->zIn)[p->iIn++];
+}
+
+/* Increase the size of p->z and append character c to the end.
+** Return 0 on success and non-zero if there is an OOM error */
+static CSV_NOINLINE int csv_resize_and_append(CsvReader *p, char c){
+ char *zNew;
+ int nNew = p->nAlloc*2 + 100;
+ zNew = sqlite3_realloc(p->z, nNew);
+ if( zNew ){
+ p->z = zNew;
+ p->nAlloc = nNew;
+ p->z[p->n++] = c;
+ return 0;
+ }else{
+ csv_errmsg(p, "out of memory");
+ return 1;
+ }
+}
+
+/* Append a single character to the CsvReader.z[] array.
+** Return 0 on success and non-zero if there is an OOM error */
+static int csv_append(CsvReader *p, char c){
+ if( p->n>=p->nAlloc-1 ) return csv_resize_and_append(p, c);
+ p->z[p->n++] = c;
+ return 0;
+}
+
+/* Read a single field of CSV text. Compatible with rfc4180 and extended
+** with the option of having a separator other than ",".
+**
+** + Input comes from p->in.
+** + Store results in p->z of length p->n. Space to hold p->z comes
+** from sqlite3_malloc64().
+** + Keep track of the line number in p->nLine.
+** + Store the character that terminates the field in p->cTerm. Store
+** EOF on end-of-file.
+**
+** Return 0 at EOF or on OOM. On EOF, the p->cTerm character will have
+** been set to EOF.
+*/
+static const char *csv_read_one_field(CsvReader *p){
+ int c;
+ p->n = 0;
+ c = csv_getc(p);
+ if( c==EOF ){
+ p->cTerm = EOF;
+ return 0;
+ }
+ if( c=='"' ){
+ int pc, ppc;
+ int startLine = p->nLine;
+ pc = ppc = 0;
+ while( 1 ){
+ c = csv_getc(p);
+ if( c<='"' || pc=='"' ){
+ if( c=='\n' ) p->nLine++;
+ if( c=='"' ){
+ if( pc=='"' ){
+ pc = 0;
+ continue;
+ }
+ }
+ if( (c==',' && pc=='"')
+ || (c=='\n' && pc=='"')
+ || (c=='\n' && pc=='\r' && ppc=='"')
+ || (c==EOF && pc=='"')
+ ){
+ do{ p->n--; }while( p->z[p->n]!='"' );
+ p->cTerm = (char)c;
+ break;
+ }
+ if( pc=='"' && c!='\r' ){
+ csv_errmsg(p, "line %d: unescaped %c character", p->nLine, '"');
+ break;
+ }
+ if( c==EOF ){
+ csv_errmsg(p, "line %d: unterminated %c-quoted field\n",
+ startLine, '"');
+ p->cTerm = (char)c;
+ break;
+ }
+ }
+ if( csv_append(p, (char)c) ) return 0;
+ ppc = pc;
+ pc = c;
+ }
+ }else{
+ /* If this is the first field being parsed and it begins with the
+ ** UTF-8 BOM (0xEF BB BF) then skip the BOM */
+ if( (c&0xff)==0xef && p->bNotFirst==0 ){
+ csv_append(p, (char)c);
+ c = csv_getc(p);
+ if( (c&0xff)==0xbb ){
+ csv_append(p, (char)c);
+ c = csv_getc(p);
+ if( (c&0xff)==0xbf ){
+ p->bNotFirst = 1;
+ p->n = 0;
+ return csv_read_one_field(p);
+ }
+ }
+ }
+ while( c>',' || (c!=EOF && c!=',' && c!='\n') ){
+ if( csv_append(p, (char)c) ) return 0;
+ c = csv_getc(p);
+ }
+ if( c=='\n' ){
+ p->nLine++;
+ if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
+ }
+ p->cTerm = (char)c;
+ }
+ if( p->z ) p->z[p->n] = 0;
+ p->bNotFirst = 1;
+ return p->z;
+}
+
+
+/* Forward references to the various virtual table methods implemented
+** in this file. */
+static int csvtabCreate(sqlite3*, void*, int, const char*const*,
+ sqlite3_vtab**,char**);
+static int csvtabConnect(sqlite3*, void*, int, const char*const*,
+ sqlite3_vtab**,char**);
+static int csvtabBestIndex(sqlite3_vtab*,sqlite3_index_info*);
+static int csvtabDisconnect(sqlite3_vtab*);
+static int csvtabOpen(sqlite3_vtab*, sqlite3_vtab_cursor**);
+static int csvtabClose(sqlite3_vtab_cursor*);
+static int csvtabFilter(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv);
+static int csvtabNext(sqlite3_vtab_cursor*);
+static int csvtabEof(sqlite3_vtab_cursor*);
+static int csvtabColumn(sqlite3_vtab_cursor*,sqlite3_context*,int);
+static int csvtabRowid(sqlite3_vtab_cursor*,sqlite3_int64*);
+
+/* An instance of the CSV virtual table */
+typedef struct CsvTable {
+ sqlite3_vtab base; /* Base class. Must be first */
+ char *zFilename; /* Name of the CSV file */
+ char *zData; /* Raw CSV data in lieu of zFilename */
+ long iStart; /* Offset to start of data in zFilename */
+ int nCol; /* Number of columns in the CSV file */
+ unsigned int tstFlags; /* Bit values used for testing */
+} CsvTable;
+
+/* Allowed values for tstFlags */
+#define CSVTEST_FIDX 0x0001 /* Pretend that constrained searchs cost less*/
+
+/* A cursor for the CSV virtual table */
+typedef struct CsvCursor {
+ sqlite3_vtab_cursor base; /* Base class. Must be first */
+ CsvReader rdr; /* The CsvReader object */
+ char **azVal; /* Value of the current row */
+ int *aLen; /* Length of each entry */
+ sqlite3_int64 iRowid; /* The current rowid. Negative for EOF */
+} CsvCursor;
+
+/* Transfer error message text from a reader into a CsvTable */
+static void csv_xfer_error(CsvTable *pTab, CsvReader *pRdr){
+ sqlite3_free(pTab->base.zErrMsg);
+ pTab->base.zErrMsg = sqlite3_mprintf("%s", pRdr->zErr);
+}
+
+/*
+** This method is the destructor fo a CsvTable object.
+*/
+static int csvtabDisconnect(sqlite3_vtab *pVtab){
+ CsvTable *p = (CsvTable*)pVtab;
+ sqlite3_free(p->zFilename);
+ sqlite3_free(p->zData);
+ sqlite3_free(p);
+ return SQLITE_OK;
+}
+
+/* Skip leading whitespace. Return a pointer to the first non-whitespace
+** character, or to the zero terminator if the string has only whitespace */
+static const char *csv_skip_whitespace(const char *z){
+ while( isspace((unsigned char)z[0]) ) z++;
+ return z;
+}
+
+/* Remove trailing whitespace from the end of string z[] */
+static void csv_trim_whitespace(char *z){
+ size_t n = strlen(z);
+ while( n>0 && isspace((unsigned char)z[n]) ) n--;
+ z[n] = 0;
+}
+
+/* Dequote the string */
+static void csv_dequote(char *z){
+ int j;
+ char cQuote = z[0];
+ size_t i, n;
+
+ if( cQuote!='\'' && cQuote!='"' ) return;
+ n = strlen(z);
+ if( n<2 || z[n-1]!=z[0] ) return;
+ for(i=1, j=0; i<n-1; i++){
+ if( z[i]==cQuote && z[i+1]==cQuote ) i++;
+ z[j++] = z[i];
+ }
+ z[j] = 0;
+}
+
+/* Check to see if the string is of the form: "TAG = VALUE" with optional
+** whitespace before and around tokens. If it is, return a pointer to the
+** first character of VALUE. If it is not, return NULL.
+*/
+static const char *csv_parameter(const char *zTag, int nTag, const char *z){
+ z = csv_skip_whitespace(z);
+ if( strncmp(zTag, z, nTag)!=0 ) return 0;
+ z = csv_skip_whitespace(z+nTag);
+ if( z[0]!='=' ) return 0;
+ return csv_skip_whitespace(z+1);
+}
+
+/* Decode a parameter that requires a dequoted string.
+**
+** Return 1 if the parameter is seen, or 0 if not. 1 is returned
+** even if there is an error. If an error occurs, then an error message
+** is left in p->zErr. If there are no errors, p->zErr[0]==0.
+*/
+static int csv_string_parameter(
+ CsvReader *p, /* Leave the error message here, if there is one */
+ const char *zParam, /* Parameter we are checking for */
+ const char *zArg, /* Raw text of the virtual table argment */
+ char **pzVal /* Write the dequoted string value here */
+){
+ const char *zValue;
+ zValue = csv_parameter(zParam,(int)strlen(zParam),zArg);
+ if( zValue==0 ) return 0;
+ p->zErr[0] = 0;
+ if( *pzVal ){
+ csv_errmsg(p, "more than one '%s' parameter", zParam);
+ return 1;
+ }
+ *pzVal = sqlite3_mprintf("%s", zValue);
+ if( *pzVal==0 ){
+ csv_errmsg(p, "out of memory");
+ return 1;
+ }
+ csv_trim_whitespace(*pzVal);
+ csv_dequote(*pzVal);
+ return 1;
+}
+
+
+/* Return 0 if the argument is false and 1 if it is true. Return -1 if
+** we cannot really tell.
+*/
+static int csv_boolean(const char *z){
+ if( sqlite3_stricmp("yes",z)==0
+ || sqlite3_stricmp("on",z)==0
+ || sqlite3_stricmp("true",z)==0
+ || (z[0]=='1' && z[1]==0)
+ ){
+ return 1;
+ }
+ if( sqlite3_stricmp("no",z)==0
+ || sqlite3_stricmp("off",z)==0
+ || sqlite3_stricmp("false",z)==0
+ || (z[0]=='0' && z[1]==0)
+ ){
+ return 0;
+ }
+ return -1;
+}
+
+/* Check to see if the string is of the form: "TAG = BOOLEAN" or just "TAG".
+** If it is, set *pValue to be the value of the boolean ("true" if there is
+** not "= BOOLEAN" component) and return non-zero. If the input string
+** does not begin with TAG, return zero.
+*/
+static int csv_boolean_parameter(
+ const char *zTag, /* Tag we are looking for */
+ int nTag, /* Size of the tag in bytes */
+ const char *z, /* Input parameter */
+ int *pValue /* Write boolean value here */
+){
+ int b;
+ z = csv_skip_whitespace(z);
+ if( strncmp(zTag, z, nTag)!=0 ) return 0;
+ z = csv_skip_whitespace(z + nTag);
+ if( z[0]==0 ){
+ *pValue = 1;
+ return 1;
+ }
+ if( z[0]!='=' ) return 0;
+ z = csv_skip_whitespace(z+1);
+ b = csv_boolean(z);
+ if( b>=0 ){
+ *pValue = b;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+** Parameters:
+** filename=FILENAME Name of file containing CSV content
+** data=TEXT Direct CSV content.
+** schema=SCHEMA Alternative CSV schema.
+** header=YES|NO First row of CSV defines the names of
+** columns if "yes". Default "no".
+** columns=N Assume the CSV file contains N columns.
+**
+** Only available if compiled with SQLITE_TEST:
+**
+** testflags=N Bitmask of test flags. Optional
+**
+** If schema= is omitted, then the columns are named "c0", "c1", "c2",
+** and so forth. If columns=N is omitted, then the file is opened and
+** the number of columns in the first row is counted to determine the
+** column count. If header=YES, then the first row is skipped.
+*/
+static int csvtabConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ CsvTable *pNew = 0; /* The CsvTable object to construct */
+ int bHeader = -1; /* header= flags. -1 means not seen yet */
+ int rc = SQLITE_OK; /* Result code from this routine */
+ int i, j; /* Loop counters */
+#ifdef SQLITE_TEST
+ int tstFlags = 0; /* Value for testflags=N parameter */
+#endif
+ int b; /* Value of a boolean parameter */
+ int nCol = -99; /* Value of the columns= parameter */
+ CsvReader sRdr; /* A CSV file reader used to store an error
+ ** message and/or to count the number of columns */
+ static const char *const azParam[] = {
+ "filename", "data", "schema",
+ };
+ char *azPValue[3]; /* Parameter values */
+# define CSV_FILENAME (azPValue[0])
+# define CSV_DATA (azPValue[1])
+# define CSV_SCHEMA (azPValue[2])
+
+
+ assert( sizeof(azPValue)==sizeof(azParam) );
+ memset(&sRdr, 0, sizeof(sRdr));
+ memset(azPValue, 0, sizeof(azPValue));
+ for(i=3; i<argc; i++){
+ const char *z = argv[i];
+ const char *zValue;
+ for(j=0; j<sizeof(azParam)/sizeof(azParam[0]); j++){
+ if( csv_string_parameter(&sRdr, azParam[j], z, &azPValue[j]) ) break;
+ }
+ if( j<sizeof(azParam)/sizeof(azParam[0]) ){
+ if( sRdr.zErr[0] ) goto csvtab_connect_error;
+ }else
+ if( csv_boolean_parameter("header",6,z,&b) ){
+ if( bHeader>=0 ){
+ csv_errmsg(&sRdr, "more than one 'header' parameter");
+ goto csvtab_connect_error;
+ }
+ bHeader = b;
+ }else
+#ifdef SQLITE_TEST
+ if( (zValue = csv_parameter("testflags",9,z))!=0 ){
+ tstFlags = (unsigned int)atoi(zValue);
+ }else
+#endif
+ if( (zValue = csv_parameter("columns",7,z))!=0 ){
+ if( nCol>0 ){
+ csv_errmsg(&sRdr, "more than one 'columns' parameter");
+ goto csvtab_connect_error;
+ }
+ nCol = atoi(zValue);
+ if( nCol<=0 ){
+ csv_errmsg(&sRdr, "column= value must be positive");
+ goto csvtab_connect_error;
+ }
+ }else
+ {
+ csv_errmsg(&sRdr, "bad parameter: '%s'", z);
+ goto csvtab_connect_error;
+ }
+ }
+ if( (CSV_FILENAME==0)==(CSV_DATA==0) ){
+ csv_errmsg(&sRdr, "must specify either filename= or data= but not both");
+ goto csvtab_connect_error;
+ }
+
+ if( (nCol<=0 || bHeader==1)
+ && csv_reader_open(&sRdr, CSV_FILENAME, CSV_DATA)
+ ){
+ goto csvtab_connect_error;
+ }
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) goto csvtab_connect_oom;
+ memset(pNew, 0, sizeof(*pNew));
+ if( CSV_SCHEMA==0 ){
+ sqlite3_str *pStr = sqlite3_str_new(0);
+ char *zSep = "";
+ int iCol = 0;
+ sqlite3_str_appendf(pStr, "CREATE TABLE x(");
+ if( nCol<0 && bHeader<1 ){
+ nCol = 0;
+ do{
+ csv_read_one_field(&sRdr);
+ nCol++;
+ }while( sRdr.cTerm==',' );
+ }
+ if( nCol>0 && bHeader<1 ){
+ for(iCol=0; iCol<nCol; iCol++){
+ sqlite3_str_appendf(pStr, "%sc%d TEXT", zSep, iCol);
+ zSep = ",";
+ }
+ }else{
+ do{
+ const char *z = csv_read_one_field(&sRdr);
+ if( (nCol>0 && iCol<nCol) || (nCol<0 && bHeader) ){
+ sqlite3_str_appendf(pStr,"%s\"%w\" TEXT", zSep, z);
+ zSep = ",";
+ iCol++;
+ }
+ }while( sRdr.cTerm==',' );
+ if( nCol<0 ){
+ nCol = iCol;
+ }else{
+ while( iCol<nCol ){
+ sqlite3_str_appendf(pStr,"%sc%d TEXT", zSep, ++iCol);
+ zSep = ",";
+ }
+ }
+ }
+ pNew->nCol = nCol;
+ sqlite3_str_appendf(pStr, ")");
+ CSV_SCHEMA = sqlite3_str_finish(pStr);
+ if( CSV_SCHEMA==0 ) goto csvtab_connect_oom;
+ }else if( nCol<0 ){
+ do{
+ csv_read_one_field(&sRdr);
+ pNew->nCol++;
+ }while( sRdr.cTerm==',' );
+ }else{
+ pNew->nCol = nCol;
+ }
+ pNew->zFilename = CSV_FILENAME; CSV_FILENAME = 0;
+ pNew->zData = CSV_DATA; CSV_DATA = 0;
+#ifdef SQLITE_TEST
+ pNew->tstFlags = tstFlags;
+#endif
+ if( bHeader!=1 ){
+ pNew->iStart = 0;
+ }else if( pNew->zData ){
+ pNew->iStart = (int)sRdr.iIn;
+ }else{
+ pNew->iStart = (int)(ftell(sRdr.in) - sRdr.nIn + sRdr.iIn);
+ }
+ csv_reader_reset(&sRdr);
+ rc = sqlite3_declare_vtab(db, CSV_SCHEMA);
+ if( rc ){
+ csv_errmsg(&sRdr, "bad schema: '%s' - %s", CSV_SCHEMA, sqlite3_errmsg(db));
+ goto csvtab_connect_error;
+ }
+ for(i=0; i<sizeof(azPValue)/sizeof(azPValue[0]); i++){
+ sqlite3_free(azPValue[i]);
+ }
+ return SQLITE_OK;
+
+csvtab_connect_oom:
+ rc = SQLITE_NOMEM;
+ csv_errmsg(&sRdr, "out of memory");
+
+csvtab_connect_error:
+ if( pNew ) csvtabDisconnect(&pNew->base);
+ for(i=0; i<sizeof(azPValue)/sizeof(azPValue[0]); i++){
+ sqlite3_free(azPValue[i]);
+ }
+ if( sRdr.zErr[0] ){
+ sqlite3_free(*pzErr);
+ *pzErr = sqlite3_mprintf("%s", sRdr.zErr);
+ }
+ csv_reader_reset(&sRdr);
+ if( rc==SQLITE_OK ) rc = SQLITE_ERROR;
+ return rc;
+}
+
+/*
+** Reset the current row content held by a CsvCursor.
+*/
+static void csvtabCursorRowReset(CsvCursor *pCur){
+ CsvTable *pTab = (CsvTable*)pCur->base.pVtab;
+ int i;
+ for(i=0; i<pTab->nCol; i++){
+ sqlite3_free(pCur->azVal[i]);
+ pCur->azVal[i] = 0;
+ pCur->aLen[i] = 0;
+ }
+}
+
+/*
+** The xConnect and xCreate methods do the same thing, but they must be
+** different so that the virtual table is not an eponymous virtual table.
+*/
+static int csvtabCreate(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ return csvtabConnect(db, pAux, argc, argv, ppVtab, pzErr);
+}
+
+/*
+** Destructor for a CsvCursor.
+*/
+static int csvtabClose(sqlite3_vtab_cursor *cur){
+ CsvCursor *pCur = (CsvCursor*)cur;
+ csvtabCursorRowReset(pCur);
+ csv_reader_reset(&pCur->rdr);
+ sqlite3_free(cur);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new CsvTable cursor object.
+*/
+static int csvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ CsvTable *pTab = (CsvTable*)p;
+ CsvCursor *pCur;
+ size_t nByte;
+ nByte = sizeof(*pCur) + (sizeof(char*)+sizeof(int))*pTab->nCol;
+ pCur = sqlite3_malloc( nByte );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, nByte);
+ pCur->azVal = (char**)&pCur[1];
+ pCur->aLen = (int*)&pCur->azVal[pTab->nCol];
+ *ppCursor = &pCur->base;
+ if( csv_reader_open(&pCur->rdr, pTab->zFilename, pTab->zData) ){
+ csv_xfer_error(pTab, &pCur->rdr);
+ return SQLITE_ERROR;
+ }
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a CsvCursor to its next row of input.
+** Set the EOF marker if we reach the end of input.
+*/
+static int csvtabNext(sqlite3_vtab_cursor *cur){
+ CsvCursor *pCur = (CsvCursor*)cur;
+ CsvTable *pTab = (CsvTable*)cur->pVtab;
+ int i = 0;
+ const char *z;
+ do{
+ z = csv_read_one_field(&pCur->rdr);
+ if( z==0 ){
+ break;
+ }
+ if( i<pTab->nCol ){
+ if( pCur->aLen[i] < pCur->rdr.n+1 ){
+ char *zNew = sqlite3_realloc(pCur->azVal[i], pCur->rdr.n+1);
+ if( zNew==0 ){
+ csv_errmsg(&pCur->rdr, "out of memory");
+ csv_xfer_error(pTab, &pCur->rdr);
+ break;
+ }
+ pCur->azVal[i] = zNew;
+ pCur->aLen[i] = pCur->rdr.n+1;
+ }
+ memcpy(pCur->azVal[i], z, pCur->rdr.n+1);
+ i++;
+ }
+ }while( pCur->rdr.cTerm==',' );
+ if( z==0 || (pCur->rdr.cTerm==EOF && i<pTab->nCol) ){
+ pCur->iRowid = -1;
+ }else{
+ pCur->iRowid++;
+ while( i<pTab->nCol ){
+ sqlite3_free(pCur->azVal[i]);
+ pCur->azVal[i] = 0;
+ pCur->aLen[i] = 0;
+ i++;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the CsvCursor
+** is currently pointing.
+*/
+static int csvtabColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ CsvCursor *pCur = (CsvCursor*)cur;
+ CsvTable *pTab = (CsvTable*)cur->pVtab;
+ if( i>=0 && i<pTab->nCol && pCur->azVal[i]!=0 ){
+ sqlite3_result_text(ctx, pCur->azVal[i], -1, SQLITE_STATIC);
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row.
+*/
+static int csvtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ CsvCursor *pCur = (CsvCursor*)cur;
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int csvtabEof(sqlite3_vtab_cursor *cur){
+ CsvCursor *pCur = (CsvCursor*)cur;
+ return pCur->iRowid<0;
+}
+
+/*
+** Only a full table scan is supported. So xFilter simply rewinds to
+** the beginning.
+*/
+static int csvtabFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ CsvCursor *pCur = (CsvCursor*)pVtabCursor;
+ CsvTable *pTab = (CsvTable*)pVtabCursor->pVtab;
+ pCur->iRowid = 0;
+ if( pCur->rdr.in==0 ){
+ assert( pCur->rdr.zIn==pTab->zData );
+ assert( pTab->iStart>=0 );
+ assert( (size_t)pTab->iStart<=pCur->rdr.nIn );
+ pCur->rdr.iIn = pTab->iStart;
+ }else{
+ fseek(pCur->rdr.in, pTab->iStart, SEEK_SET);
+ pCur->rdr.iIn = 0;
+ pCur->rdr.nIn = 0;
+ }
+ return csvtabNext(pVtabCursor);
+}
+
+/*
+** Only a forward full table scan is supported. xBestIndex is mostly
+** a no-op. If CSVTEST_FIDX is set, then the presence of equality
+** constraints lowers the estimated cost, which is fiction, but is useful
+** for testing certain kinds of virtual table behavior.
+*/
+static int csvtabBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ pIdxInfo->estimatedCost = 1000000;
+#ifdef SQLITE_TEST
+ if( (((CsvTable*)tab)->tstFlags & CSVTEST_FIDX)!=0 ){
+ /* The usual (and sensible) case is to always do a full table scan.
+ ** The code in this branch only runs when testflags=1. This code
+ ** generates an artifical and unrealistic plan which is useful
+ ** for testing virtual table logic but is not helpful to real applications.
+ **
+ ** Any ==, LIKE, or GLOB constraint is marked as usable by the virtual
+ ** table (even though it is not) and the cost of running the virtual table
+ ** is reduced from 1 million to just 10. The constraints are *not* marked
+ ** as omittable, however, so the query planner should still generate a
+ ** plan that gives a correct answer, even if they plan is not optimal.
+ */
+ int i;
+ int nConst = 0;
+ for(i=0; i<pIdxInfo->nConstraint; i++){
+ unsigned char op;
+ if( pIdxInfo->aConstraint[i].usable==0 ) continue;
+ op = pIdxInfo->aConstraint[i].op;
+ if( op==SQLITE_INDEX_CONSTRAINT_EQ
+ || op==SQLITE_INDEX_CONSTRAINT_LIKE
+ || op==SQLITE_INDEX_CONSTRAINT_GLOB
+ ){
+ pIdxInfo->estimatedCost = 10;
+ pIdxInfo->aConstraintUsage[nConst].argvIndex = nConst+1;
+ nConst++;
+ }
+ }
+ }
+#endif
+ return SQLITE_OK;
+}
+
+
+static const sqlite3_module CsvModule = {
+ 0, /* iVersion */
+ csvtabCreate, /* xCreate */
+ csvtabConnect, /* xConnect */
+ csvtabBestIndex, /* xBestIndex */
+ csvtabDisconnect, /* xDisconnect */
+ csvtabDisconnect, /* xDestroy */
+ csvtabOpen, /* xOpen - open a cursor */
+ csvtabClose, /* xClose - close a cursor */
+ csvtabFilter, /* xFilter - configure scan constraints */
+ csvtabNext, /* xNext - advance a cursor */
+ csvtabEof, /* xEof - check for end of scan */
+ csvtabColumn, /* xColumn - read data */
+ csvtabRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+};
+
+#ifdef SQLITE_TEST
+/*
+** For virtual table testing, make a version of the CSV virtual table
+** available that has an xUpdate function. But the xUpdate always returns
+** SQLITE_READONLY since the CSV file is not really writable.
+*/
+static int csvtabUpdate(sqlite3_vtab *p,int n,sqlite3_value**v,sqlite3_int64*x){
+ return SQLITE_READONLY;
+}
+static const sqlite3_module CsvModuleFauxWrite = {
+ 0, /* iVersion */
+ csvtabCreate, /* xCreate */
+ csvtabConnect, /* xConnect */
+ csvtabBestIndex, /* xBestIndex */
+ csvtabDisconnect, /* xDisconnect */
+ csvtabDisconnect, /* xDestroy */
+ csvtabOpen, /* xOpen - open a cursor */
+ csvtabClose, /* xClose - close a cursor */
+ csvtabFilter, /* xFilter - configure scan constraints */
+ csvtabNext, /* xNext - advance a cursor */
+ csvtabEof, /* xEof - check for end of scan */
+ csvtabColumn, /* xColumn - read data */
+ csvtabRowid, /* xRowid - read data */
+ csvtabUpdate, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+};
+#endif /* SQLITE_TEST */
+
+#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+/*
+** This routine is called when the extension is loaded. The new
+** CSV virtual table module is registered with the calling database
+** connection.
+*/
+int sqlite3_csv_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ int rc;
+ SQLITE_EXTENSION_INIT2(pApi);
+ rc = sqlite3_create_module(db, "csv", &CsvModule, 0);
+#ifdef SQLITE_TEST
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_module(db, "csv_wr", &CsvModuleFauxWrite, 0);
+ }
+#endif
+ return rc;
+#else
+ return SQLITE_OK;
+#endif
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi);
+ return sqlite3_create_module(db, "csv", &CsvModule, 0);
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/dbdata.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/dbdata.c 2019-10-08 13:42:19.111507500 +0200
@@ -0,0 +1,861 @@
+/*
+** 2019-04-17
+**
+** 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 an implementation of two eponymous virtual tables,
+** "sqlite_dbdata" and "sqlite_dbptr". Both modules require that the
+** "sqlite_dbpage" eponymous virtual table be available.
+**
+** SQLITE_DBDATA:
+** sqlite_dbdata is used to extract data directly from a database b-tree
+** page and its associated overflow pages, bypassing the b-tree layer.
+** The table schema is equivalent to:
+**
+** CREATE TABLE sqlite_dbdata(
+** pgno INTEGER,
+** cell INTEGER,
+** field INTEGER,
+** value ANY,
+** schema TEXT HIDDEN
+** );
+**
+** IMPORTANT: THE VIRTUAL TABLE SCHEMA ABOVE IS SUBJECT TO CHANGE. IN THE
+** FUTURE NEW NON-HIDDEN COLUMNS MAY BE ADDED BETWEEN "value" AND
+** "schema".
+**
+** Each page of the database is inspected. If it cannot be interpreted as
+** a b-tree page, or if it is a b-tree page containing 0 entries, the
+** sqlite_dbdata table contains no rows for that page. Otherwise, the
+** table contains one row for each field in the record associated with
+** each cell on the page. For intkey b-trees, the key value is stored in
+** field -1.
+**
+** For example, for the database:
+**
+** CREATE TABLE t1(a, b); -- root page is page 2
+** INSERT INTO t1(rowid, a, b) VALUES(5, 'v', 'five');
+** INSERT INTO t1(rowid, a, b) VALUES(10, 'x', 'ten');
+**
+** the sqlite_dbdata table contains, as well as from entries related to
+** page 1, content equivalent to:
+**
+** INSERT INTO sqlite_dbdata(pgno, cell, field, value) VALUES
+** (2, 0, -1, 5 ),
+** (2, 0, 0, 'v' ),
+** (2, 0, 1, 'five'),
+** (2, 1, -1, 10 ),
+** (2, 1, 0, 'x' ),
+** (2, 1, 1, 'ten' );
+**
+** If database corruption is encountered, this module does not report an
+** error. Instead, it attempts to extract as much data as possible and
+** ignores the corruption.
+**
+** SQLITE_DBPTR:
+** The sqlite_dbptr table has the following schema:
+**
+** CREATE TABLE sqlite_dbptr(
+** pgno INTEGER,
+** child INTEGER,
+** schema TEXT HIDDEN
+** );
+**
+** It contains one entry for each b-tree pointer between a parent and
+** child page in the database.
+*/
+#if !defined(SQLITEINT_H)
+#include "sqlite3ext.h"
+
+typedef unsigned char u8;
+
+#endif
+SQLITE_EXTENSION_INIT1
+#include <string.h>
+#include <assert.h>
+
+#define DBDATA_PADDING_BYTES 100
+
+typedef struct DbdataTable DbdataTable;
+typedef struct DbdataCursor DbdataCursor;
+
+/* Cursor object */
+struct DbdataCursor {
+ sqlite3_vtab_cursor base; /* Base class. Must be first */
+ sqlite3_stmt *pStmt; /* For fetching database pages */
+
+ int iPgno; /* Current page number */
+ u8 *aPage; /* Buffer containing page */
+ int nPage; /* Size of aPage[] in bytes */
+ int nCell; /* Number of cells on aPage[] */
+ int iCell; /* Current cell number */
+ int bOnePage; /* True to stop after one page */
+ int szDb;
+ sqlite3_int64 iRowid;
+
+ /* Only for the sqlite_dbdata table */
+ u8 *pRec; /* Buffer containing current record */
+ int nRec; /* Size of pRec[] in bytes */
+ int nHdr; /* Size of header in bytes */
+ int iField; /* Current field number */
+ u8 *pHdrPtr;
+ u8 *pPtr;
+
+ sqlite3_int64 iIntkey; /* Integer key value */
+};
+
+/* Table object */
+struct DbdataTable {
+ sqlite3_vtab base; /* Base class. Must be first */
+ sqlite3 *db; /* The database connection */
+ sqlite3_stmt *pStmt; /* For fetching database pages */
+ int bPtr; /* True for sqlite3_dbptr table */
+};
+
+/* Column and schema definitions for sqlite_dbdata */
+#define DBDATA_COLUMN_PGNO 0
+#define DBDATA_COLUMN_CELL 1
+#define DBDATA_COLUMN_FIELD 2
+#define DBDATA_COLUMN_VALUE 3
+#define DBDATA_COLUMN_SCHEMA 4
+#define DBDATA_SCHEMA \
+ "CREATE TABLE x(" \
+ " pgno INTEGER," \
+ " cell INTEGER," \
+ " field INTEGER," \
+ " value ANY," \
+ " schema TEXT HIDDEN" \
+ ")"
+
+/* Column and schema definitions for sqlite_dbptr */
+#define DBPTR_COLUMN_PGNO 0
+#define DBPTR_COLUMN_CHILD 1
+#define DBPTR_COLUMN_SCHEMA 2
+#define DBPTR_SCHEMA \
+ "CREATE TABLE x(" \
+ " pgno INTEGER," \
+ " child INTEGER," \
+ " schema TEXT HIDDEN" \
+ ")"
+
+/*
+** Connect to an sqlite_dbdata (pAux==0) or sqlite_dbptr (pAux!=0) virtual
+** table.
+*/
+static int dbdataConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ DbdataTable *pTab = 0;
+ int rc = sqlite3_declare_vtab(db, pAux ? DBPTR_SCHEMA : DBDATA_SCHEMA);
+
+ if( rc==SQLITE_OK ){
+ pTab = (DbdataTable*)sqlite3_malloc64(sizeof(DbdataTable));
+ if( pTab==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(pTab, 0, sizeof(DbdataTable));
+ pTab->db = db;
+ pTab->bPtr = (pAux!=0);
+ }
+ }
+
+ *ppVtab = (sqlite3_vtab*)pTab;
+ return rc;
+}
+
+/*
+** Disconnect from or destroy a sqlite_dbdata or sqlite_dbptr virtual table.
+*/
+static int dbdataDisconnect(sqlite3_vtab *pVtab){
+ DbdataTable *pTab = (DbdataTable*)pVtab;
+ if( pTab ){
+ sqlite3_finalize(pTab->pStmt);
+ sqlite3_free(pVtab);
+ }
+ return SQLITE_OK;
+}
+
+/*
+** This function interprets two types of constraints:
+**
+** schema=?
+** pgno=?
+**
+** If neither are present, idxNum is set to 0. If schema=? is present,
+** the 0x01 bit in idxNum is set. If pgno=? is present, the 0x02 bit
+** in idxNum is set.
+**
+** If both parameters are present, schema is in position 0 and pgno in
+** position 1.
+*/
+static int dbdataBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdx){
+ DbdataTable *pTab = (DbdataTable*)tab;
+ int i;
+ int iSchema = -1;
+ int iPgno = -1;
+ int colSchema = (pTab->bPtr ? DBPTR_COLUMN_SCHEMA : DBDATA_COLUMN_SCHEMA);
+
+ for(i=0; i<pIdx->nConstraint; i++){
+ struct sqlite3_index_constraint *p = &pIdx->aConstraint[i];
+ if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ if( p->iColumn==colSchema ){
+ if( p->usable==0 ) return SQLITE_CONSTRAINT;
+ iSchema = i;
+ }
+ if( p->iColumn==DBDATA_COLUMN_PGNO && p->usable ){
+ iPgno = i;
+ }
+ }
+ }
+
+ if( iSchema>=0 ){
+ pIdx->aConstraintUsage[iSchema].argvIndex = 1;
+ pIdx->aConstraintUsage[iSchema].omit = 1;
+ }
+ if( iPgno>=0 ){
+ pIdx->aConstraintUsage[iPgno].argvIndex = 1 + (iSchema>=0);
+ pIdx->aConstraintUsage[iPgno].omit = 1;
+ pIdx->estimatedCost = 100;
+ pIdx->estimatedRows = 50;
+
+ if( pTab->bPtr==0 && pIdx->nOrderBy && pIdx->aOrderBy[0].desc==0 ){
+ int iCol = pIdx->aOrderBy[0].iColumn;
+ if( pIdx->nOrderBy==1 ){
+ pIdx->orderByConsumed = (iCol==0 || iCol==1);
+ }else if( pIdx->nOrderBy==2 && pIdx->aOrderBy[1].desc==0 && iCol==0 ){
+ pIdx->orderByConsumed = (pIdx->aOrderBy[1].iColumn==1);
+ }
+ }
+
+ }else{
+ pIdx->estimatedCost = 100000000;
+ pIdx->estimatedRows = 1000000000;
+ }
+ pIdx->idxNum = (iSchema>=0 ? 0x01 : 0x00) | (iPgno>=0 ? 0x02 : 0x00);
+ return SQLITE_OK;
+}
+
+/*
+** Open a new sqlite_dbdata or sqlite_dbptr cursor.
+*/
+static int dbdataOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+ DbdataCursor *pCsr;
+
+ pCsr = (DbdataCursor*)sqlite3_malloc64(sizeof(DbdataCursor));
+ if( pCsr==0 ){
+ return SQLITE_NOMEM;
+ }else{
+ memset(pCsr, 0, sizeof(DbdataCursor));
+ pCsr->base.pVtab = pVTab;
+ }
+
+ *ppCursor = (sqlite3_vtab_cursor *)pCsr;
+ return SQLITE_OK;
+}
+
+/*
+** Restore a cursor object to the state it was in when first allocated
+** by dbdataOpen().
+*/
+static void dbdataResetCursor(DbdataCursor *pCsr){
+ DbdataTable *pTab = (DbdataTable*)(pCsr->base.pVtab);
+ if( pTab->pStmt==0 ){
+ pTab->pStmt = pCsr->pStmt;
+ }else{
+ sqlite3_finalize(pCsr->pStmt);
+ }
+ pCsr->pStmt = 0;
+ pCsr->iPgno = 1;
+ pCsr->iCell = 0;
+ pCsr->iField = 0;
+ pCsr->bOnePage = 0;
+ sqlite3_free(pCsr->aPage);
+ sqlite3_free(pCsr->pRec);
+ pCsr->pRec = 0;
+ pCsr->aPage = 0;
+}
+
+/*
+** Close an sqlite_dbdata or sqlite_dbptr cursor.
+*/
+static int dbdataClose(sqlite3_vtab_cursor *pCursor){
+ DbdataCursor *pCsr = (DbdataCursor*)pCursor;
+ dbdataResetCursor(pCsr);
+ sqlite3_free(pCsr);
+ return SQLITE_OK;
+}
+
+/*
+** Utility methods to decode 16 and 32-bit big-endian unsigned integers.
+*/
+static unsigned int get_uint16(unsigned char *a){
+ return (a[0]<<8)|a[1];
+}
+static unsigned int get_uint32(unsigned char *a){
+ return ((unsigned int)a[0]<<24)
+ | ((unsigned int)a[1]<<16)
+ | ((unsigned int)a[2]<<8)
+ | ((unsigned int)a[3]);
+}
+
+/*
+** Load page pgno from the database via the sqlite_dbpage virtual table.
+** If successful, set (*ppPage) to point to a buffer containing the page
+** data, (*pnPage) to the size of that buffer in bytes and return
+** SQLITE_OK. In this case it is the responsibility of the caller to
+** eventually free the buffer using sqlite3_free().
+**
+** Or, if an error occurs, set both (*ppPage) and (*pnPage) to 0 and
+** return an SQLite error code.
+*/
+static int dbdataLoadPage(
+ DbdataCursor *pCsr, /* Cursor object */
+ unsigned int pgno, /* Page number of page to load */
+ u8 **ppPage, /* OUT: pointer to page buffer */
+ int *pnPage /* OUT: Size of (*ppPage) in bytes */
+){
+ int rc2;
+ int rc = SQLITE_OK;
+ sqlite3_stmt *pStmt = pCsr->pStmt;
+
+ *ppPage = 0;
+ *pnPage = 0;
+ sqlite3_bind_int64(pStmt, 2, pgno);
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ int nCopy = sqlite3_column_bytes(pStmt, 0);
+ if( nCopy>0 ){
+ u8 *pPage;
+ pPage = (u8*)sqlite3_malloc64(nCopy + DBDATA_PADDING_BYTES);
+ if( pPage==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ const u8 *pCopy = sqlite3_column_blob(pStmt, 0);
+ memcpy(pPage, pCopy, nCopy);
+ memset(&pPage[nCopy], 0, DBDATA_PADDING_BYTES);
+ }
+ *ppPage = pPage;
+ *pnPage = nCopy;
+ }
+ }
+ rc2 = sqlite3_reset(pStmt);
+ if( rc==SQLITE_OK ) rc = rc2;
+
+ return rc;
+}
+
+/*
+** Read a varint. Put the value in *pVal and return the number of bytes.
+*/
+static int dbdataGetVarint(const u8 *z, sqlite3_int64 *pVal){
+ sqlite3_int64 v = 0;
+ int i;
+ for(i=0; i<8; i++){
+ v = (v<<7) + (z[i]&0x7f);
+ if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; }
+ }
+ v = (v<<8) + (z[i]&0xff);
+ *pVal = v;
+ return 9;
+}
+
+/*
+** Return the number of bytes of space used by an SQLite value of type
+** eType.
+*/
+static int dbdataValueBytes(int eType){
+ switch( eType ){
+ case 0: case 8: case 9:
+ case 10: case 11:
+ return 0;
+ case 1:
+ return 1;
+ case 2:
+ return 2;
+ case 3:
+ return 3;
+ case 4:
+ return 4;
+ case 5:
+ return 6;
+ case 6:
+ case 7:
+ return 8;
+ default:
+ if( eType>0 ){
+ return ((eType-12) / 2);
+ }
+ return 0;
+ }
+}
+
+/*
+** Load a value of type eType from buffer pData and use it to set the
+** result of context object pCtx.
+*/
+static void dbdataValue(
+ sqlite3_context *pCtx,
+ int eType,
+ u8 *pData,
+ int nData
+){
+ if( eType>=0 && dbdataValueBytes(eType)<=nData ){
+ switch( eType ){
+ case 0:
+ case 10:
+ case 11:
+ sqlite3_result_null(pCtx);
+ break;
+
+ case 8:
+ sqlite3_result_int(pCtx, 0);
+ break;
+ case 9:
+ sqlite3_result_int(pCtx, 1);
+ break;
+
+ case 1: case 2: case 3: case 4: case 5: case 6: case 7: {
+ sqlite3_uint64 v = (signed char)pData[0];
+ pData++;
+ switch( eType ){
+ case 7:
+ case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
+ case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
+ case 4: v = (v<<8) + pData[0]; pData++;
+ case 3: v = (v<<8) + pData[0]; pData++;
+ case 2: v = (v<<8) + pData[0]; pData++;
+ }
+
+ if( eType==7 ){
+ double r;
+ memcpy(&r, &v, sizeof(r));
+ sqlite3_result_double(pCtx, r);
+ }else{
+ sqlite3_result_int64(pCtx, (sqlite3_int64)v);
+ }
+ break;
+ }
+
+ default: {
+ int n = ((eType-12) / 2);
+ if( eType % 2 ){
+ sqlite3_result_text(pCtx, (const char*)pData, n, SQLITE_TRANSIENT);
+ }else{
+ sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT);
+ }
+ }
+ }
+ }
+}
+
+/*
+** Move an sqlite_dbdata or sqlite_dbptr cursor to the next entry.
+*/
+static int dbdataNext(sqlite3_vtab_cursor *pCursor){
+ DbdataCursor *pCsr = (DbdataCursor*)pCursor;
+ DbdataTable *pTab = (DbdataTable*)pCursor->pVtab;
+
+ pCsr->iRowid++;
+ while( 1 ){
+ int rc;
+ int iOff = (pCsr->iPgno==1 ? 100 : 0);
+ int bNextPage = 0;
+
+ if( pCsr->aPage==0 ){
+ while( 1 ){
+ if( pCsr->bOnePage==0 && pCsr->iPgno>pCsr->szDb ) return SQLITE_OK;
+ rc = dbdataLoadPage(pCsr, pCsr->iPgno, &pCsr->aPage, &pCsr->nPage);
+ if( rc!=SQLITE_OK ) return rc;
+ if( pCsr->aPage ) break;
+ pCsr->iPgno++;
+ }
+ pCsr->iCell = pTab->bPtr ? -2 : 0;
+ pCsr->nCell = get_uint16(&pCsr->aPage[iOff+3]);
+ }
+
+ if( pTab->bPtr ){
+ if( pCsr->aPage[iOff]!=0x02 && pCsr->aPage[iOff]!=0x05 ){
+ pCsr->iCell = pCsr->nCell;
+ }
+ pCsr->iCell++;
+ if( pCsr->iCell>=pCsr->nCell ){
+ sqlite3_free(pCsr->aPage);
+ pCsr->aPage = 0;
+ if( pCsr->bOnePage ) return SQLITE_OK;
+ pCsr->iPgno++;
+ }else{
+ return SQLITE_OK;
+ }
+ }else{
+ /* If there is no record loaded, load it now. */
+ if( pCsr->pRec==0 ){
+ int bHasRowid = 0;
+ int nPointer = 0;
+ sqlite3_int64 nPayload = 0;
+ sqlite3_int64 nHdr = 0;
+ int iHdr;
+ int U, X;
+ int nLocal;
+
+ switch( pCsr->aPage[iOff] ){
+ case 0x02:
+ nPointer = 4;
+ break;
+ case 0x0a:
+ break;
+ case 0x0d:
+ bHasRowid = 1;
+ break;
+ default:
+ /* This is not a b-tree page with records on it. Continue. */
+ pCsr->iCell = pCsr->nCell;
+ break;
+ }
+
+ if( pCsr->iCell>=pCsr->nCell ){
+ bNextPage = 1;
+ }else{
+
+ iOff += 8 + nPointer + pCsr->iCell*2;
+ if( iOff>pCsr->nPage ){
+ bNextPage = 1;
+ }else{
+ iOff = get_uint16(&pCsr->aPage[iOff]);
+ }
+
+ /* For an interior node cell, skip past the child-page number */
+ iOff += nPointer;
+
+ /* Load the "byte of payload including overflow" field */
+ if( bNextPage || iOff>pCsr->nPage ){
+ bNextPage = 1;
+ }else{
+ iOff += dbdataGetVarint(&pCsr->aPage[iOff], &nPayload);
+ }
+
+ /* If this is a leaf intkey cell, load the rowid */
+ if( bHasRowid && !bNextPage && iOff<pCsr->nPage ){
+ iOff += dbdataGetVarint(&pCsr->aPage[iOff], &pCsr->iIntkey);
+ }
+
+ /* Figure out how much data to read from the local page */
+ U = pCsr->nPage;
+ if( bHasRowid ){
+ X = U-35;
+ }else{
+ X = ((U-12)*64/255)-23;
+ }
+ if( nPayload<=X ){
+ nLocal = nPayload;
+ }else{
+ int M, K;
+ M = ((U-12)*32/255)-23;
+ K = M+((nPayload-M)%(U-4));
+ if( K<=X ){
+ nLocal = K;
+ }else{
+ nLocal = M;
+ }
+ }
+
+ if( bNextPage || nLocal+iOff>pCsr->nPage ){
+ bNextPage = 1;
+ }else{
+
+ /* Allocate space for payload. And a bit more to catch small buffer
+ ** overruns caused by attempting to read a varint or similar from
+ ** near the end of a corrupt record. */
+ pCsr->pRec = (u8*)sqlite3_malloc64(nPayload+DBDATA_PADDING_BYTES);
+ if( pCsr->pRec==0 ) return SQLITE_NOMEM;
+ memset(pCsr->pRec, 0, nPayload+DBDATA_PADDING_BYTES);
+ pCsr->nRec = nPayload;
+
+ /* Load the nLocal bytes of payload */
+ memcpy(pCsr->pRec, &pCsr->aPage[iOff], nLocal);
+ iOff += nLocal;
+
+ /* Load content from overflow pages */
+ if( nPayload>nLocal ){
+ sqlite3_int64 nRem = nPayload - nLocal;
+ unsigned int pgnoOvfl = get_uint32(&pCsr->aPage[iOff]);
+ while( nRem>0 ){
+ u8 *aOvfl = 0;
+ int nOvfl = 0;
+ int nCopy;
+ rc = dbdataLoadPage(pCsr, pgnoOvfl, &aOvfl, &nOvfl);
+ assert( rc!=SQLITE_OK || aOvfl==0 || nOvfl==pCsr->nPage );
+ if( rc!=SQLITE_OK ) return rc;
+ if( aOvfl==0 ) break;
+
+ nCopy = U-4;
+ if( nCopy>nRem ) nCopy = nRem;
+ memcpy(&pCsr->pRec[nPayload-nRem], &aOvfl[4], nCopy);
+ nRem -= nCopy;
+
+ pgnoOvfl = get_uint32(aOvfl);
+ sqlite3_free(aOvfl);
+ }
+ }
+
+ iHdr = dbdataGetVarint(pCsr->pRec, &nHdr);
+ pCsr->nHdr = nHdr;
+ pCsr->pHdrPtr = &pCsr->pRec[iHdr];
+ pCsr->pPtr = &pCsr->pRec[pCsr->nHdr];
+ pCsr->iField = (bHasRowid ? -1 : 0);
+ }
+ }
+ }else{
+ pCsr->iField++;
+ if( pCsr->iField>0 ){
+ sqlite3_int64 iType;
+ if( pCsr->pHdrPtr>&pCsr->pRec[pCsr->nRec] ){
+ bNextPage = 1;
+ }else{
+ pCsr->pHdrPtr += dbdataGetVarint(pCsr->pHdrPtr, &iType);
+ pCsr->pPtr += dbdataValueBytes(iType);
+ }
+ }
+ }
+
+ if( bNextPage ){
+ sqlite3_free(pCsr->aPage);
+ sqlite3_free(pCsr->pRec);
+ pCsr->aPage = 0;
+ pCsr->pRec = 0;
+ if( pCsr->bOnePage ) return SQLITE_OK;
+ pCsr->iPgno++;
+ }else{
+ if( pCsr->iField<0 || pCsr->pHdrPtr<&pCsr->pRec[pCsr->nHdr] ){
+ return SQLITE_OK;
+ }
+
+ /* Advance to the next cell. The next iteration of the loop will load
+ ** the record and so on. */
+ sqlite3_free(pCsr->pRec);
+ pCsr->pRec = 0;
+ pCsr->iCell++;
+ }
+ }
+ }
+
+ assert( !"can't get here" );
+ return SQLITE_OK;
+}
+
+/*
+** Return true if the cursor is at EOF.
+*/
+static int dbdataEof(sqlite3_vtab_cursor *pCursor){
+ DbdataCursor *pCsr = (DbdataCursor*)pCursor;
+ return pCsr->aPage==0;
+}
+
+/*
+** Determine the size in pages of database zSchema (where zSchema is
+** "main", "temp" or the name of an attached database) and set
+** pCsr->szDb accordingly. If successful, return SQLITE_OK. Otherwise,
+** an SQLite error code.
+*/
+static int dbdataDbsize(DbdataCursor *pCsr, const char *zSchema){
+ DbdataTable *pTab = (DbdataTable*)pCsr->base.pVtab;
+ char *zSql = 0;
+ int rc, rc2;
+ sqlite3_stmt *pStmt = 0;
+
+ zSql = sqlite3_mprintf("PRAGMA %Q.page_count", zSchema);
+ if( zSql==0 ) return SQLITE_NOMEM;
+ rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
+ pCsr->szDb = sqlite3_column_int(pStmt, 0);
+ }
+ rc2 = sqlite3_finalize(pStmt);
+ if( rc==SQLITE_OK ) rc = rc2;
+ return rc;
+}
+
+/*
+** xFilter method for sqlite_dbdata and sqlite_dbptr.
+*/
+static int dbdataFilter(
+ sqlite3_vtab_cursor *pCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ DbdataCursor *pCsr = (DbdataCursor*)pCursor;
+ DbdataTable *pTab = (DbdataTable*)pCursor->pVtab;
+ int rc = SQLITE_OK;
+ const char *zSchema = "main";
+
+ dbdataResetCursor(pCsr);
+ assert( pCsr->iPgno==1 );
+ if( idxNum & 0x01 ){
+ zSchema = (const char*)sqlite3_value_text(argv[0]);
+ }
+ if( idxNum & 0x02 ){
+ pCsr->iPgno = sqlite3_value_int(argv[(idxNum & 0x01)]);
+ pCsr->bOnePage = 1;
+ }else{
+ pCsr->nPage = dbdataDbsize(pCsr, zSchema);
+ rc = dbdataDbsize(pCsr, zSchema);
+ }
+
+ if( rc==SQLITE_OK ){
+ if( pTab->pStmt ){
+ pCsr->pStmt = pTab->pStmt;
+ pTab->pStmt = 0;
+ }else{
+ rc = sqlite3_prepare_v2(pTab->db,
+ "SELECT data FROM sqlite_dbpage(?) WHERE pgno=?", -1,
+ &pCsr->pStmt, 0
+ );
+ }
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_bind_text(pCsr->pStmt, 1, zSchema, -1, SQLITE_TRANSIENT);
+ }else{
+ pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db));
+ }
+ if( rc==SQLITE_OK ){
+ rc = dbdataNext(pCursor);
+ }
+ return rc;
+}
+
+/*
+** Return a column for the sqlite_dbdata or sqlite_dbptr table.
+*/
+static int dbdataColumn(
+ sqlite3_vtab_cursor *pCursor,
+ sqlite3_context *ctx,
+ int i
+){
+ DbdataCursor *pCsr = (DbdataCursor*)pCursor;
+ DbdataTable *pTab = (DbdataTable*)pCursor->pVtab;
+ if( pTab->bPtr ){
+ switch( i ){
+ case DBPTR_COLUMN_PGNO:
+ sqlite3_result_int64(ctx, pCsr->iPgno);
+ break;
+ case DBPTR_COLUMN_CHILD: {
+ int iOff = pCsr->iPgno==1 ? 100 : 0;
+ if( pCsr->iCell<0 ){
+ iOff += 8;
+ }else{
+ iOff += 12 + pCsr->iCell*2;
+ if( iOff>pCsr->nPage ) return SQLITE_OK;
+ iOff = get_uint16(&pCsr->aPage[iOff]);
+ }
+ if( iOff<=pCsr->nPage ){
+ sqlite3_result_int64(ctx, get_uint32(&pCsr->aPage[iOff]));
+ }
+ break;
+ }
+ }
+ }else{
+ switch( i ){
+ case DBDATA_COLUMN_PGNO:
+ sqlite3_result_int64(ctx, pCsr->iPgno);
+ break;
+ case DBDATA_COLUMN_CELL:
+ sqlite3_result_int(ctx, pCsr->iCell);
+ break;
+ case DBDATA_COLUMN_FIELD:
+ sqlite3_result_int(ctx, pCsr->iField);
+ break;
+ case DBDATA_COLUMN_VALUE: {
+ if( pCsr->iField<0 ){
+ sqlite3_result_int64(ctx, pCsr->iIntkey);
+ }else{
+ sqlite3_int64 iType;
+ dbdataGetVarint(pCsr->pHdrPtr, &iType);
+ dbdataValue(
+ ctx, iType, pCsr->pPtr, &pCsr->pRec[pCsr->nRec] - pCsr->pPtr
+ );
+ }
+ break;
+ }
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for an sqlite_dbdata or sqlite_dptr table.
+*/
+static int dbdataRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
+ DbdataCursor *pCsr = (DbdataCursor*)pCursor;
+ *pRowid = pCsr->iRowid;
+ return SQLITE_OK;
+}
+
+
+/*
+** Invoke this routine to register the "sqlite_dbdata" virtual table module
+*/
+static int sqlite3DbdataRegister(sqlite3 *db){
+ static const sqlite3_module dbdata_module = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ dbdataConnect, /* xConnect */
+ dbdataBestIndex, /* xBestIndex */
+ dbdataDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ dbdataOpen, /* xOpen - open a cursor */
+ dbdataClose, /* xClose - close a cursor */
+ dbdataFilter, /* xFilter - configure scan constraints */
+ dbdataNext, /* xNext - advance a cursor */
+ dbdataEof, /* xEof - check for end of scan */
+ dbdataColumn, /* xColumn - read data */
+ dbdataRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
+ };
+
+ int rc = sqlite3_create_module(db, "sqlite_dbdata", &dbdata_module, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_module(db, "sqlite_dbptr", &dbdata_module, (void*)1);
+ }
+ return rc;
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_dbdata_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi);
+ return sqlite3DbdataRegister(db);
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi);
+ return sqlite3DbdataRegister(db);
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/dbdump.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/dbdump.c 2019-10-08 13:42:19.115412000 +0200
@@ -0,0 +1,724 @@
+/*
+** 2016-03-13
+**
+** 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 implements a C-language subroutine that converts the content
+** of an SQLite database into UTF-8 text SQL statements that can be used
+** to exactly recreate the original database. ROWID values are preserved.
+**
+** A prototype of the implemented subroutine is this:
+**
+** int sqlite3_db_dump(
+** sqlite3 *db,
+** const char *zSchema,
+** const char *zTable,
+** void (*xCallback)(void*, const char*),
+** void *pArg
+** );
+**
+** The db parameter is the database connection. zSchema is the schema within
+** that database which is to be dumped. Usually the zSchema is "main" but
+** can also be "temp" or any ATTACH-ed database. If zTable is not NULL, then
+** only the content of that one table is dumped. If zTable is NULL, then all
+** tables are dumped.
+**
+** The generate text is passed to xCallback() in multiple calls. The second
+** argument to xCallback() is a copy of the pArg parameter. The first
+** argument is some of the output text that this routine generates. The
+** signature to xCallback() is designed to make it compatible with fputs().
+**
+** The sqlite3_db_dump() subroutine returns SQLITE_OK on success or some error
+** code if it encounters a problem.
+**
+** If this file is compiled with -DDBDUMP_STANDALONE then a "main()" routine
+** is included so that this routine becomes a command-line utility. The
+** command-line utility takes two or three arguments which are the name
+** of the database file, the schema, and optionally the table, forming the
+** first three arguments of a single call to the library routine.
+*/
+#include "sqlite3.h"
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+/*
+** The state of the dump process.
+*/
+typedef struct DState DState;
+struct DState {
+ sqlite3 *db; /* The database connection */
+ int nErr; /* Number of errors seen so far */
+ int rc; /* Error code */
+ int writableSchema; /* True if in writable_schema mode */
+ int (*xCallback)(const char*,void*); /* Send output here */
+ void *pArg; /* Argument to xCallback() */
+};
+
+/*
+** A variable length string to which one can append text.
+*/
+typedef struct DText DText;
+struct DText {
+ char *z; /* The text */
+ int n; /* Number of bytes of content in z[] */
+ int nAlloc; /* Number of bytes allocated to z[] */
+};
+
+/*
+** Initialize and destroy a DText object
+*/
+static void initText(DText *p){
+ memset(p, 0, sizeof(*p));
+}
+static void freeText(DText *p){
+ sqlite3_free(p->z);
+ initText(p);
+}
+
+/* zIn is either a pointer to a NULL-terminated string in memory obtained
+** from malloc(), or a NULL pointer. The string pointed to by zAppend is
+** added to zIn, and the result returned in memory obtained from malloc().
+** zIn, if it was not NULL, is freed.
+**
+** If the third argument, quote, is not '\0', then it is used as a
+** quote character for zAppend.
+*/
+static void appendText(DText *p, char const *zAppend, char quote){
+ int len;
+ int i;
+ int nAppend = (int)(strlen(zAppend) & 0x3fffffff);
+
+ len = nAppend+p->n+1;
+ if( quote ){
+ len += 2;
+ for(i=0; i<nAppend; i++){
+ if( zAppend[i]==quote ) len++;
+ }
+ }
+
+ if( p->n+len>=p->nAlloc ){
+ char *zNew;
+ p->nAlloc = p->nAlloc*2 + len + 20;
+ zNew = sqlite3_realloc(p->z, p->nAlloc);
+ if( zNew==0 ){
+ freeText(p);
+ return;
+ }
+ p->z = zNew;
+ }
+
+ if( quote ){
+ char *zCsr = p->z+p->n;
+ *zCsr++ = quote;
+ for(i=0; i<nAppend; i++){
+ *zCsr++ = zAppend[i];
+ if( zAppend[i]==quote ) *zCsr++ = quote;
+ }
+ *zCsr++ = quote;
+ p->n = (int)(zCsr - p->z);
+ *zCsr = '\0';
+ }else{
+ memcpy(p->z+p->n, zAppend, nAppend);
+ p->n += nAppend;
+ p->z[p->n] = '\0';
+ }
+}
+
+/*
+** Attempt to determine if identifier zName needs to be quoted, either
+** because it contains non-alphanumeric characters, or because it is an
+** SQLite keyword. Be conservative in this estimate: When in doubt assume
+** that quoting is required.
+**
+** Return '"' if quoting is required. Return 0 if no quoting is required.
+*/
+static char quoteChar(const char *zName){
+ int i;
+ if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"';
+ for(i=0; zName[i]; i++){
+ if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"';
+ }
+ return sqlite3_keyword_check(zName, i) ? '"' : 0;
+}
+
+
+/*
+** Release memory previously allocated by tableColumnList().
+*/
+static void freeColumnList(char **azCol){
+ int i;
+ for(i=1; azCol[i]; i++){
+ sqlite3_free(azCol[i]);
+ }
+ /* azCol[0] is a static string */
+ sqlite3_free(azCol);
+}
+
+/*
+** Return a list of pointers to strings which are the names of all
+** columns in table zTab. The memory to hold the names is dynamically
+** allocated and must be released by the caller using a subsequent call
+** to freeColumnList().
+**
+** The azCol[0] entry is usually NULL. However, if zTab contains a rowid
+** value that needs to be preserved, then azCol[0] is filled in with the
+** name of the rowid column.
+**
+** The first regular column in the table is azCol[1]. The list is terminated
+** by an entry with azCol[i]==0.
+*/
+static char **tableColumnList(DState *p, const char *zTab){
+ const char **azCol = 0;
+ sqlite3_stmt *pStmt = 0;
+ char *zSql;
+ int nCol = 0;
+ int nAlloc = 0;
+ int nPK = 0; /* Number of PRIMARY KEY columns seen */
+ int isIPK = 0; /* True if one PRIMARY KEY column of type INTEGER */
+ int preserveRowid = 1;
+ int rc;
+
+ zSql = sqlite3_mprintf("PRAGMA table_info=%Q", zTab);
+ if( zSql==0 ) return 0;
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ if( rc ) return 0;
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ if( nCol>=nAlloc-2 ){
+ char **azNew;
+ nAlloc = nAlloc*2 + nCol + 10;
+ azNew = sqlite3_realloc64(azCol, nAlloc*sizeof(azCol[0]));
+ if( azNew==0 ) goto col_oom;
+ azCol = azNew;
+ azCol[0] = 0;
+ }
+ azCol[++nCol] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
+ if( azCol[nCol]==0 ) goto col_oom;
+ if( sqlite3_column_int(pStmt, 5) ){
+ nPK++;
+ if( nPK==1
+ && sqlite3_stricmp((const char*)sqlite3_column_text(pStmt,2),
+ "INTEGER")==0
+ ){
+ isIPK = 1;
+ }else{
+ isIPK = 0;
+ }
+ }
+ }
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+ azCol[nCol+1] = 0;
+
+ /* The decision of whether or not a rowid really needs to be preserved
+ ** is tricky. We never need to preserve a rowid for a WITHOUT ROWID table
+ ** or a table with an INTEGER PRIMARY KEY. We are unable to preserve
+ ** rowids on tables where the rowid is inaccessible because there are other
+ ** columns in the table named "rowid", "_rowid_", and "oid".
+ */
+ if( isIPK ){
+ /* If a single PRIMARY KEY column with type INTEGER was seen, then it
+ ** might be an alise for the ROWID. But it might also be a WITHOUT ROWID
+ ** table or a INTEGER PRIMARY KEY DESC column, neither of which are
+ ** ROWID aliases. To distinguish these cases, check to see if
+ ** there is a "pk" entry in "PRAGMA index_list". There will be
+ ** no "pk" index if the PRIMARY KEY really is an alias for the ROWID.
+ */
+ zSql = sqlite3_mprintf("SELECT 1 FROM pragma_index_list(%Q)"
+ " WHERE origin='pk'", zTab);
+ if( zSql==0 ) goto col_oom;
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ if( rc ){
+ freeColumnList(azCol);
+ return 0;
+ }
+ rc = sqlite3_step(pStmt);
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+ preserveRowid = rc==SQLITE_ROW;
+ }
+ if( preserveRowid ){
+ /* Only preserve the rowid if we can find a name to use for the
+ ** rowid */
+ static const char *const azRowid[] = { "rowid", "_rowid_", "oid" };
+ int i, j;
+ for(j=0; j<3; j++){
+ for(i=1; i<=nCol; i++){
+ if( sqlite3_stricmp(azRowid[j],azCol[i])==0 ) break;
+ }
+ if( i>nCol ){
+ /* At this point, we know that azRowid[j] is not the name of any
+ ** ordinary column in the table. Verify that azRowid[j] is a valid
+ ** name for the rowid before adding it to azCol[0]. WITHOUT ROWID
+ ** tables will fail this last check */
+ rc = sqlite3_table_column_metadata(p->db,0,zTab,azRowid[j],0,0,0,0,0);
+ if( rc==SQLITE_OK ) azCol[0] = azRowid[j];
+ break;
+ }
+ }
+ }
+ return azCol;
+
+col_oom:
+ sqlite3_finalize(pStmt);
+ freeColumnList(azCol);
+ p->nErr++;
+ p->rc = SQLITE_NOMEM;
+ return 0;
+}
+
+/*
+** Send mprintf-formatted content to the output callback.
+*/
+static void output_formatted(DState *p, const char *zFormat, ...){
+ va_list ap;
+ char *z;
+ va_start(ap, zFormat);
+ z = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+ p->xCallback(z, p->pArg);
+ sqlite3_free(z);
+}
+
+/*
+** Find a string that is not found anywhere in z[]. Return a pointer
+** to that string.
+**
+** Try to use zA and zB first. If both of those are already found in z[]
+** then make up some string and store it in the buffer zBuf.
+*/
+static const char *unused_string(
+ const char *z, /* Result must not appear anywhere in z */
+ const char *zA, const char *zB, /* Try these first */
+ char *zBuf /* Space to store a generated string */
+){
+ unsigned i = 0;
+ if( strstr(z, zA)==0 ) return zA;
+ if( strstr(z, zB)==0 ) return zB;
+ do{
+ sqlite3_snprintf(20,zBuf,"(%s%u)", zA, i++);
+ }while( strstr(z,zBuf)!=0 );
+ return zBuf;
+}
+
+/*
+** Output the given string as a quoted string using SQL quoting conventions.
+** Additionallly , escape the "\n" and "\r" characters so that they do not
+** get corrupted by end-of-line translation facilities in some operating
+** systems.
+*/
+static void output_quoted_escaped_string(DState *p, const char *z){
+ int i;
+ char c;
+ for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
+ if( c==0 ){
+ output_formatted(p,"'%s'",z);
+ }else{
+ const char *zNL = 0;
+ const char *zCR = 0;
+ int nNL = 0;
+ int nCR = 0;
+ char zBuf1[20], zBuf2[20];
+ for(i=0; z[i]; i++){
+ if( z[i]=='\n' ) nNL++;
+ if( z[i]=='\r' ) nCR++;
+ }
+ if( nNL ){
+ p->xCallback("replace(", p->pArg);
+ zNL = unused_string(z, "\\n", "\\012", zBuf1);
+ }
+ if( nCR ){
+ p->xCallback("replace(", p->pArg);
+ zCR = unused_string(z, "\\r", "\\015", zBuf2);
+ }
+ p->xCallback("'", p->pArg);
+ while( *z ){
+ for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
+ if( c=='\'' ) i++;
+ if( i ){
+ output_formatted(p, "%.*s", i, z);
+ z += i;
+ }
+ if( c=='\'' ){
+ p->xCallback("'", p->pArg);
+ continue;
+ }
+ if( c==0 ){
+ break;
+ }
+ z++;
+ if( c=='\n' ){
+ p->xCallback(zNL, p->pArg);
+ continue;
+ }
+ p->xCallback(zCR, p->pArg);
+ }
+ p->xCallback("'", p->pArg);
+ if( nCR ){
+ output_formatted(p, ",'%s',char(13))", zCR);
+ }
+ if( nNL ){
+ output_formatted(p, ",'%s',char(10))", zNL);
+ }
+ }
+}
+
+/*
+** This is an sqlite3_exec callback routine used for dumping the database.
+** Each row received by this callback consists of a table name,
+** the table type ("index" or "table") and SQL to create the table.
+** This routine should print text sufficient to recreate the table.
+*/
+static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
+ int rc;
+ const char *zTable;
+ const char *zType;
+ const char *zSql;
+ DState *p = (DState*)pArg;
+ sqlite3_stmt *pStmt;
+
+ (void)azCol;
+ if( nArg!=3 ) return 1;
+ zTable = azArg[0];
+ zType = azArg[1];
+ zSql = azArg[2];
+
+ if( strcmp(zTable, "sqlite_sequence")==0 ){
+ p->xCallback("DELETE FROM sqlite_sequence;\n", p->pArg);
+ }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
+ p->xCallback("ANALYZE sqlite_master;\n", p->pArg);
+ }else if( strncmp(zTable, "sqlite_", 7)==0 ){
+ return 0;
+ }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
+ if( !p->writableSchema ){
+ p->xCallback("PRAGMA writable_schema=ON;\n", p->pArg);
+ p->writableSchema = 1;
+ }
+ output_formatted(p,
+ "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
+ "VALUES('table','%q','%q',0,'%q');",
+ zTable, zTable, zSql);
+ return 0;
+ }else{
+ if( sqlite3_strglob("CREATE TABLE ['\"]*", zSql)==0 ){
+ p->xCallback("CREATE TABLE IF NOT EXISTS ", p->pArg);
+ p->xCallback(zSql+13, p->pArg);
+ }else{
+ p->xCallback(zSql, p->pArg);
+ }
+ p->xCallback(";\n", p->pArg);
+ }
+
+ if( strcmp(zType, "table")==0 ){
+ DText sSelect;
+ DText sTable;
+ char **azTCol;
+ int i;
+ int nCol;
+
+ azTCol = tableColumnList(p, zTable);
+ if( azTCol==0 ) return 0;
+
+ initText(&sTable);
+ appendText(&sTable, "INSERT INTO ", 0);
+
+ /* Always quote the table name, even if it appears to be pure ascii,
+ ** in case it is a keyword. Ex: INSERT INTO "table" ... */
+ appendText(&sTable, zTable, quoteChar(zTable));
+
+ /* If preserving the rowid, add a column list after the table name.
+ ** In other words: "INSERT INTO tab(rowid,a,b,c,...) VALUES(...)"
+ ** instead of the usual "INSERT INTO tab VALUES(...)".
+ */
+ if( azTCol[0] ){
+ appendText(&sTable, "(", 0);
+ appendText(&sTable, azTCol[0], 0);
+ for(i=1; azTCol[i]; i++){
+ appendText(&sTable, ",", 0);
+ appendText(&sTable, azTCol[i], quoteChar(azTCol[i]));
+ }
+ appendText(&sTable, ")", 0);
+ }
+ appendText(&sTable, " VALUES(", 0);
+
+ /* Build an appropriate SELECT statement */
+ initText(&sSelect);
+ appendText(&sSelect, "SELECT ", 0);
+ if( azTCol[0] ){
+ appendText(&sSelect, azTCol[0], 0);
+ appendText(&sSelect, ",", 0);
+ }
+ for(i=1; azTCol[i]; i++){
+ appendText(&sSelect, azTCol[i], quoteChar(azTCol[i]));
+ if( azTCol[i+1] ){
+ appendText(&sSelect, ",", 0);
+ }
+ }
+ nCol = i;
+ if( azTCol[0]==0 ) nCol--;
+ freeColumnList(azTCol);
+ appendText(&sSelect, " FROM ", 0);
+ appendText(&sSelect, zTable, quoteChar(zTable));
+
+ rc = sqlite3_prepare_v2(p->db, sSelect.z, -1, &pStmt, 0);
+ if( rc!=SQLITE_OK ){
+ p->nErr++;
+ if( p->rc==SQLITE_OK ) p->rc = rc;
+ }else{
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ p->xCallback(sTable.z, p->pArg);
+ for(i=0; i<nCol; i++){
+ if( i ) p->xCallback(",", p->pArg);
+ switch( sqlite3_column_type(pStmt,i) ){
+ case SQLITE_INTEGER: {
+ output_formatted(p, "%lld", sqlite3_column_int64(pStmt,i));
+ break;
+ }
+ case SQLITE_FLOAT: {
+ double r = sqlite3_column_double(pStmt,i);
+ sqlite3_uint64 ur;
+ memcpy(&ur,&r,sizeof(r));
+ if( ur==0x7ff0000000000000LL ){
+ p->xCallback("1e999", p->pArg);
+ }else if( ur==0xfff0000000000000LL ){
+ p->xCallback("-1e999", p->pArg);
+ }else{
+ output_formatted(p, "%!.20g", r);
+ }
+ break;
+ }
+ case SQLITE_NULL: {
+ p->xCallback("NULL", p->pArg);
+ break;
+ }
+ case SQLITE_TEXT: {
+ output_quoted_escaped_string(p,
+ (const char*)sqlite3_column_text(pStmt,i));
+ break;
+ }
+ case SQLITE_BLOB: {
+ int nByte = sqlite3_column_bytes(pStmt,i);
+ unsigned char *a = (unsigned char*)sqlite3_column_blob(pStmt,i);
+ int j;
+ p->xCallback("x'", p->pArg);
+ for(j=0; j<nByte; j++){
+ char zWord[3];
+ zWord[0] = "0123456789abcdef"[(a[j]>>4)&15];
+ zWord[1] = "0123456789abcdef"[a[j]&15];
+ zWord[2] = 0;
+ p->xCallback(zWord, p->pArg);
+ }
+ p->xCallback("'", p->pArg);
+ break;
+ }
+ }
+ }
+ p->xCallback(");\n", p->pArg);
+ }
+ }
+ sqlite3_finalize(pStmt);
+ freeText(&sTable);
+ freeText(&sSelect);
+ }
+ return 0;
+}
+
+
+/*
+** Execute a query statement that will generate SQL output. Print
+** the result columns, comma-separated, on a line and then add a
+** semicolon terminator to the end of that line.
+**
+** If the number of columns is 1 and that column contains text "--"
+** then write the semicolon on a separate line. That way, if a
+** "--" comment occurs at the end of the statement, the comment
+** won't consume the semicolon terminator.
+*/
+static void output_sql_from_query(
+ DState *p, /* Query context */
+ const char *zSelect, /* SELECT statement to extract content */
+ ...
+){
+ sqlite3_stmt *pSelect;
+ int rc;
+ int nResult;
+ int i;
+ const char *z;
+ char *zSql;
+ va_list ap;
+ va_start(ap, zSelect);
+ zSql = sqlite3_vmprintf(zSelect, ap);
+ va_end(ap);
+ if( zSql==0 ){
+ p->rc = SQLITE_NOMEM;
+ p->nErr++;
+ return;
+ }
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pSelect, 0);
+ sqlite3_free(zSql);
+ if( rc!=SQLITE_OK || !pSelect ){
+ output_formatted(p, "/**** ERROR: (%d) %s *****/\n", rc,
+ sqlite3_errmsg(p->db));
+ p->nErr++;
+ return;
+ }
+ rc = sqlite3_step(pSelect);
+ nResult = sqlite3_column_count(pSelect);
+ while( rc==SQLITE_ROW ){
+ z = (const char*)sqlite3_column_text(pSelect, 0);
+ p->xCallback(z, p->pArg);
+ for(i=1; i<nResult; i++){
+ p->xCallback(",", p->pArg);
+ p->xCallback((const char*)sqlite3_column_text(pSelect,i), p->pArg);
+ }
+ if( z==0 ) z = "";
+ while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
+ if( z[0] ){
+ p->xCallback("\n;\n", p->pArg);
+ }else{
+ p->xCallback(";\n", p->pArg);
+ }
+ rc = sqlite3_step(pSelect);
+ }
+ rc = sqlite3_finalize(pSelect);
+ if( rc!=SQLITE_OK ){
+ output_formatted(p, "/**** ERROR: (%d) %s *****/\n", rc,
+ sqlite3_errmsg(p->db));
+ if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
+ }
+}
+
+/*
+** Run zQuery. Use dump_callback() as the callback routine so that
+** the contents of the query are output as SQL statements.
+**
+** If we get a SQLITE_CORRUPT error, rerun the query after appending
+** "ORDER BY rowid DESC" to the end.
+*/
+static void run_schema_dump_query(
+ DState *p,
+ const char *zQuery,
+ ...
+){
+ char *zErr = 0;
+ char *z;
+ va_list ap;
+ va_start(ap, zQuery);
+ z = sqlite3_vmprintf(zQuery, ap);
+ va_end(ap);
+ sqlite3_exec(p->db, z, dump_callback, p, &zErr);
+ sqlite3_free(z);
+ if( zErr ){
+ output_formatted(p, "/****** %s ******/\n", zErr);
+ sqlite3_free(zErr);
+ p->nErr++;
+ zErr = 0;
+ }
+}
+
+/*
+** Convert an SQLite database into SQL statements that will recreate that
+** database.
+*/
+int sqlite3_db_dump(
+ sqlite3 *db, /* The database connection */
+ const char *zSchema, /* Which schema to dump. Usually "main". */
+ const char *zTable, /* Which table to dump. NULL means everything. */
+ int (*xCallback)(const char*,void*), /* Output sent to this callback */
+ void *pArg /* Second argument of the callback */
+){
+ DState x;
+ memset(&x, 0, sizeof(x));
+ x.rc = sqlite3_exec(db, "BEGIN", 0, 0, 0);
+ if( x.rc ) return x.rc;
+ x.db = db;
+ x.xCallback = xCallback;
+ x.pArg = pArg;
+ xCallback("PRAGMA foreign_keys=OFF;\nBEGIN TRANSACTION;\n", pArg);
+ if( zTable==0 ){
+ run_schema_dump_query(&x,
+ "SELECT name, type, sql FROM \"%w\".sqlite_master "
+ "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'",
+ zSchema
+ );
+ run_schema_dump_query(&x,
+ "SELECT name, type, sql FROM \"%w\".sqlite_master "
+ "WHERE name=='sqlite_sequence'", zSchema
+ );
+ output_sql_from_query(&x,
+ "SELECT sql FROM sqlite_master "
+ "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
+ );
+ }else{
+ run_schema_dump_query(&x,
+ "SELECT name, type, sql FROM \"%w\".sqlite_master "
+ "WHERE tbl_name=%Q COLLATE nocase AND type=='table'"
+ " AND sql NOT NULL",
+ zSchema, zTable
+ );
+ output_sql_from_query(&x,
+ "SELECT sql FROM \"%w\".sqlite_master "
+ "WHERE sql NOT NULL"
+ " AND type IN ('index','trigger','view')"
+ " AND tbl_name=%Q COLLATE nocase",
+ zSchema, zTable
+ );
+ }
+ if( x.writableSchema ){
+ xCallback("PRAGMA writable_schema=OFF;\n", pArg);
+ }
+ xCallback(x.nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n", pArg);
+ sqlite3_exec(db, "COMMIT", 0, 0, 0);
+ return x.rc;
+}
+
+
+
+/* The generic subroutine is above. The code the follows implements
+** the command-line interface.
+*/
+#ifdef DBDUMP_STANDALONE
+#include <stdio.h>
+
+/*
+** Command-line interface
+*/
+int main(int argc, char **argv){
+ sqlite3 *db;
+ const char *zDb;
+ const char *zSchema;
+ const char *zTable = 0;
+ int rc;
+
+ if( argc<2 || argc>4 ){
+ fprintf(stderr, "Usage: %s DATABASE ?SCHEMA? ?TABLE?\n", argv[0]);
+ return 1;
+ }
+ zDb = argv[1];
+ zSchema = argc>=3 ? argv[2] : "main";
+ zTable = argc==4 ? argv[3] : 0;
+
+ rc = sqlite3_open(zDb, &db);
+ if( rc ){
+ fprintf(stderr, "Cannot open \"%s\": %s\n", zDb, sqlite3_errmsg(db));
+ sqlite3_close(db);
+ return 1;
+ }
+ rc = sqlite3_db_dump(db, zSchema, zTable,
+ (int(*)(const char*,void*))fputs, (void*)stdout);
+ if( rc ){
+ fprintf(stderr, "Error: sqlite3_db_dump() returns %d\n", rc);
+ }
+ sqlite3_close(db);
+ return rc!=SQLITE_OK;
+}
+#endif /* DBDUMP_STANDALONE */
--- origsrc/sqlite-autoconf-3300000/eval.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/eval.c 2019-10-08 13:42:19.120294600 +0200
@@ -0,0 +1,141 @@
+/*
+** 2014-11-10
+**
+** 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 SQLite extension implements SQL function eval() which runs
+** SQL statements recursively.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <string.h>
+
+/*
+** Structure used to accumulate the output
+*/
+struct EvalResult {
+ char *z; /* Accumulated output */
+ const char *zSep; /* Separator */
+ int szSep; /* Size of the separator string */
+ size_t nAlloc; /* Number of bytes allocated for z[] */
+ size_t nUsed; /* Number of bytes of z[] actually used */
+};
+
+/*
+** Callback from sqlite_exec() for the eval() function.
+*/
+static int callback(void *pCtx, int argc, char **argv, char **colnames){
+ struct EvalResult *p = (struct EvalResult*)pCtx;
+ int i;
+ if( argv==0 ) return 0;
+ for(i=0; i<argc; i++){
+ const char *z = argv[i] ? argv[i] : "";
+ size_t sz = strlen(z);
+ if( sz+p->nUsed+p->szSep+1 > p->nAlloc ){
+ char *zNew;
+ p->nAlloc = p->nAlloc*2 + sz + p->szSep + 1;
+ /* Using sqlite3_realloc64() would be better, but it is a recent
+ ** addition and will cause a segfault if loaded by an older version
+ ** of SQLite. */
+ zNew = p->nAlloc<=0x7fffffff ? sqlite3_realloc(p->z, p->nAlloc) : 0;
+ if( zNew==0 ){
+ sqlite3_free(p->z);
+ memset(p, 0, sizeof(*p));
+ return 1;
+ }
+ p->z = zNew;
+ }
+ if( p->nUsed>0 ){
+ memcpy(&p->z[p->nUsed], p->zSep, p->szSep);
+ p->nUsed += p->szSep;
+ }
+ memcpy(&p->z[p->nUsed], z, sz);
+ p->nUsed += sz;
+ }
+ return 0;
+}
+
+/*
+** Implementation of the eval(X) and eval(X,Y) SQL functions.
+**
+** Evaluate the SQL text in X. Return the results, using string
+** Y as the separator. If Y is omitted, use a single space character.
+*/
+static void sqlEvalFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zSql;
+ sqlite3 *db;
+ char *zErr = 0;
+ int rc;
+ struct EvalResult x;
+
+ memset(&x, 0, sizeof(x));
+ x.zSep = " ";
+ zSql = (const char*)sqlite3_value_text(argv[0]);
+ if( zSql==0 ) return;
+ if( argc>1 ){
+ x.zSep = (const char*)sqlite3_value_text(argv[1]);
+ if( x.zSep==0 ) return;
+ }
+ x.szSep = (int)strlen(x.zSep);
+ db = sqlite3_context_db_handle(context);
+ rc = sqlite3_exec(db, zSql, callback, &x, &zErr);
+ if( rc!=SQLITE_OK ){
+ sqlite3_result_error(context, zErr, -1);
+ sqlite3_free(zErr);
+ }else if( x.zSep==0 ){
+ sqlite3_result_error_nomem(context);
+ sqlite3_free(x.z);
+ }else{
+ sqlite3_result_text(context, x.z, x.nUsed, sqlite3_free);
+ }
+}
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_eval_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0,
+ sqlEvalFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0,
+ sqlEvalFunc, 0, 0);
+ }
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0,
+ sqlEvalFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0,
+ sqlEvalFunc, 0, 0);
+ }
+ return rc;
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/explain.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/explain.c 2019-10-08 13:42:19.126152200 +0200
@@ -0,0 +1,322 @@
+/*
+** 2018-09-16
+**
+** 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 demonstrates an eponymous virtual table that returns the
+** EXPLAIN output from an SQL statement.
+**
+** Usage example:
+**
+** .load ./explain
+** SELECT p2 FROM explain('SELECT * FROM sqlite_master')
+** WHERE opcode='OpenRead';
+**
+** This module was originally written to help simplify SQLite testing,
+** by providing an easier means of verifying certain patterns in the
+** generated bytecode.
+*/
+#if !defined(SQLITEINT_H)
+#include "sqlite3ext.h"
+#endif
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/* explain_vtab is a subclass of sqlite3_vtab which will
+** serve as the underlying representation of a explain virtual table
+*/
+typedef struct explain_vtab explain_vtab;
+struct explain_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this explain vtab */
+};
+
+/* explain_cursor is a subclass of sqlite3_vtab_cursor which will
+** serve as the underlying representation of a cursor that scans
+** over rows of the result from an EXPLAIN operation.
+*/
+typedef struct explain_cursor explain_cursor;
+struct explain_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this cursor */
+ char *zSql; /* Value for the EXPLN_COLUMN_SQL column */
+ sqlite3_stmt *pExplain; /* Statement being explained */
+ int rc; /* Result of last sqlite3_step() on pExplain */
+};
+
+/*
+** The explainConnect() method is invoked to create a new
+** explain_vtab that describes the explain virtual table.
+**
+** Think of this routine as the constructor for explain_vtab objects.
+**
+** All this routine needs to do is:
+**
+** (1) Allocate the explain_vtab object and initialize all fields.
+**
+** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
+** result set of queries against explain will look like.
+*/
+static int explainConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ explain_vtab *pNew;
+ int rc;
+
+/* Column numbers */
+#define EXPLN_COLUMN_ADDR 0 /* Instruction address */
+#define EXPLN_COLUMN_OPCODE 1 /* Opcode */
+#define EXPLN_COLUMN_P1 2 /* Operand 1 */
+#define EXPLN_COLUMN_P2 3 /* Operand 2 */
+#define EXPLN_COLUMN_P3 4 /* Operand 3 */
+#define EXPLN_COLUMN_P4 5 /* Operand 4 */
+#define EXPLN_COLUMN_P5 6 /* Operand 5 */
+#define EXPLN_COLUMN_COMMENT 7 /* Comment */
+#define EXPLN_COLUMN_SQL 8 /* SQL that is being explained */
+
+
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x(addr,opcode,p1,p2,p3,p4,p5,comment,sql HIDDEN)");
+ if( rc==SQLITE_OK ){
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->db = db;
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for explain_cursor objects.
+*/
+static int explainDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new explain_cursor object.
+*/
+static int explainOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ explain_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ pCur->db = ((explain_vtab*)p)->db;
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Destructor for a explain_cursor.
+*/
+static int explainClose(sqlite3_vtab_cursor *cur){
+ explain_cursor *pCur = (explain_cursor*)cur;
+ sqlite3_finalize(pCur->pExplain);
+ sqlite3_free(pCur->zSql);
+ sqlite3_free(pCur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a explain_cursor to its next row of output.
+*/
+static int explainNext(sqlite3_vtab_cursor *cur){
+ explain_cursor *pCur = (explain_cursor*)cur;
+ pCur->rc = sqlite3_step(pCur->pExplain);
+ if( pCur->rc!=SQLITE_DONE && pCur->rc!=SQLITE_ROW ) return pCur->rc;
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the explain_cursor
+** is currently pointing.
+*/
+static int explainColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ explain_cursor *pCur = (explain_cursor*)cur;
+ if( i==EXPLN_COLUMN_SQL ){
+ sqlite3_result_text(ctx, pCur->zSql, -1, SQLITE_TRANSIENT);
+ }else{
+ sqlite3_result_value(ctx, sqlite3_column_value(pCur->pExplain, i));
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** rowid is the same as the output value.
+*/
+static int explainRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ explain_cursor *pCur = (explain_cursor*)cur;
+ *pRowid = sqlite3_column_int64(pCur->pExplain, 0);
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int explainEof(sqlite3_vtab_cursor *cur){
+ explain_cursor *pCur = (explain_cursor*)cur;
+ return pCur->rc!=SQLITE_ROW;
+}
+
+/*
+** This method is called to "rewind" the explain_cursor object back
+** to the first row of output. This method is always called at least
+** once prior to any call to explainColumn() or explainRowid() or
+** explainEof().
+**
+** The argv[0] is the SQL statement that is to be explained.
+*/
+static int explainFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ explain_cursor *pCur = (explain_cursor *)pVtabCursor;
+ char *zSql = 0;
+ int rc;
+ sqlite3_finalize(pCur->pExplain);
+ pCur->pExplain = 0;
+ if( sqlite3_value_type(argv[0])!=SQLITE_TEXT ){
+ pCur->rc = SQLITE_DONE;
+ return SQLITE_OK;
+ }
+ sqlite3_free(pCur->zSql);
+ pCur->zSql = sqlite3_mprintf("%s", sqlite3_value_text(argv[0]));
+ if( pCur->zSql ){
+ zSql = sqlite3_mprintf("EXPLAIN %s", pCur->zSql);
+ }
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pExplain, 0);
+ sqlite3_free(zSql);
+ }
+ if( rc ){
+ sqlite3_finalize(pCur->pExplain);
+ pCur->pExplain = 0;
+ sqlite3_free(pCur->zSql);
+ pCur->zSql = 0;
+ }else{
+ pCur->rc = sqlite3_step(pCur->pExplain);
+ rc = (pCur->rc==SQLITE_DONE || pCur->rc==SQLITE_ROW) ? SQLITE_OK : pCur->rc;
+ }
+ return rc;
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the explain virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+*/
+static int explainBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int i; /* Loop counter */
+ int idx = -1; /* Index of a usable == constraint against SQL */
+ int unusable = 0; /* True if there are unusable constraints on SQL */
+
+ pIdxInfo->estimatedRows = 500;
+ for(i=0; i<pIdxInfo->nConstraint; i++){
+ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
+ if( p->iColumn!=EXPLN_COLUMN_SQL ) continue;
+ if( !p->usable ){
+ unusable = 1;
+ }else if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ idx = i;
+ }
+ }
+ if( idx>=0 ){
+ /* There exists a usable == constraint against the SQL column */
+ pIdxInfo->estimatedCost = 10.0;
+ pIdxInfo->idxNum = 1;
+ pIdxInfo->aConstraintUsage[idx].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[idx].omit = 1;
+ }else if( unusable ){
+ /* There are unusable constraints against the SQL column. Do not allow
+ ** this plan to continue forward. */
+ return SQLITE_CONSTRAINT;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** This following structure defines all the methods for the
+** explain virtual table.
+*/
+static const sqlite3_module explainModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ explainConnect, /* xConnect */
+ explainBestIndex, /* xBestIndex */
+ explainDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ explainOpen, /* xOpen - open a cursor */
+ explainClose, /* xClose - close a cursor */
+ explainFilter, /* xFilter - configure scan constraints */
+ explainNext, /* xNext - advance a cursor */
+ explainEof, /* xEof - check for end of scan */
+ explainColumn, /* xColumn - read data */
+ explainRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0, /* xShadowName */
+};
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+int sqlite3ExplainVtabInit(sqlite3 *db){
+ int rc = SQLITE_OK;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3_create_module(db, "explain", &explainModule, 0);
+#endif
+ return rc;
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_explain_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3ExplainVtabInit(db);
+#endif
+ return rc;
+}
--- origsrc/sqlite-autoconf-3300000/fileio.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/fileio.c 2019-10-08 13:42:19.131033600 +0200
@@ -0,0 +1,1018 @@
+/*
+** 2014-06-13
+**
+** 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 SQLite extension implements SQL functions readfile() and
+** writefile(), and eponymous virtual type "fsdir".
+**
+** WRITEFILE(FILE, DATA [, MODE [, MTIME]]):
+**
+** If neither of the optional arguments is present, then this UDF
+** function writes blob DATA to file FILE. If successful, the number
+** of bytes written is returned. If an error occurs, NULL is returned.
+**
+** If the first option argument - MODE - is present, then it must
+** be passed an integer value that corresponds to a POSIX mode
+** value (file type + permissions, as returned in the stat.st_mode
+** field by the stat() system call). Three types of files may
+** be written/created:
+**
+** regular files: (mode & 0170000)==0100000
+** symbolic links: (mode & 0170000)==0120000
+** directories: (mode & 0170000)==0040000
+**
+** For a directory, the DATA is ignored. For a symbolic link, it is
+** interpreted as text and used as the target of the link. For a
+** regular file, it is interpreted as a blob and written into the
+** named file. Regardless of the type of file, its permissions are
+** set to (mode & 0777) before returning.
+**
+** If the optional MTIME argument is present, then it is interpreted
+** as an integer - the number of seconds since the unix epoch. The
+** modification-time of the target file is set to this value before
+** returning.
+**
+** If three or more arguments are passed to this function and an
+** error is encountered, an exception is raised.
+**
+** READFILE(FILE):
+**
+** Read and return the contents of file FILE (type blob) from disk.
+**
+** FSDIR:
+**
+** Used as follows:
+**
+** SELECT * FROM fsdir($path [, $dir]);
+**
+** Parameter $path is an absolute or relative pathname. If the file that it
+** refers to does not exist, it is an error. If the path refers to a regular
+** file or symbolic link, it returns a single row. Or, if the path refers
+** to a directory, it returns one row for the directory, and one row for each
+** file within the hierarchy rooted at $path.
+**
+** Each row has the following columns:
+**
+** name: Path to file or directory (text value).
+** mode: Value of stat.st_mode for directory entry (an integer).
+** mtime: Value of stat.st_mtime for directory entry (an integer).
+** data: For a regular file, a blob containing the file data. For a
+** symlink, a text value containing the text of the link. For a
+** directory, NULL.
+**
+** If a non-NULL value is specified for the optional $dir parameter and
+** $path is a relative path, then $path is interpreted relative to $dir.
+** And the paths returned in the "name" column of the table are also
+** relative to directory $dir.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#if !defined(_WIN32) && !defined(WIN32)
+# include <unistd.h>
+# include <utime.h>
+# include <sys/time.h>
+#else
+# include "windows.h"
+# include <io.h>
+# include <direct.h>
+# include "test_windirent.h"
+# ifndef chmod
+# define chmod _chmod
+# endif
+# ifndef stat
+# define stat _stat
+# endif
+# define mkdir(path,mode) _mkdir(path)
+# define lstat(path,buf) stat(path,buf)
+#endif
+#include <time.h>
+#include <errno.h>
+
+
+/*
+** Structure of the fsdir() table-valued function
+*/
+ /* 0 1 2 3 4 5 */
+#define FSDIR_SCHEMA "(name,mode,mtime,data,path HIDDEN,dir HIDDEN)"
+#define FSDIR_COLUMN_NAME 0 /* Name of the file */
+#define FSDIR_COLUMN_MODE 1 /* Access mode */
+#define FSDIR_COLUMN_MTIME 2 /* Last modification time */
+#define FSDIR_COLUMN_DATA 3 /* File content */
+#define FSDIR_COLUMN_PATH 4 /* Path to top of search */
+#define FSDIR_COLUMN_DIR 5 /* Path is relative to this directory */
+
+
+/*
+** Set the result stored by context ctx to a blob containing the
+** contents of file zName. Or, leave the result unchanged (NULL)
+** if the file does not exist or is unreadable.
+**
+** If the file exceeds the SQLite blob size limit, through an
+** SQLITE_TOOBIG error.
+**
+** Throw an SQLITE_IOERR if there are difficulties pulling the file
+** off of disk.
+*/
+static void readFileContents(sqlite3_context *ctx, const char *zName){
+ FILE *in;
+ sqlite3_int64 nIn;
+ void *pBuf;
+ sqlite3 *db;
+ int mxBlob;
+
+ in = fopen(zName, "rb");
+ if( in==0 ){
+ /* File does not exist or is unreadable. Leave the result set to NULL. */
+ return;
+ }
+ fseek(in, 0, SEEK_END);
+ nIn = ftell(in);
+ rewind(in);
+ db = sqlite3_context_db_handle(ctx);
+ mxBlob = sqlite3_limit(db, SQLITE_LIMIT_LENGTH, -1);
+ if( nIn>mxBlob ){
+ sqlite3_result_error_code(ctx, SQLITE_TOOBIG);
+ fclose(in);
+ return;
+ }
+ pBuf = sqlite3_malloc( nIn ? nIn : 1 );
+ if( pBuf==0 ){
+ sqlite3_result_error_nomem(ctx);
+ fclose(in);
+ return;
+ }
+ if( nIn==(sqlite3_int64)fread(pBuf, 1, (size_t)nIn, in) ){
+ sqlite3_result_blob64(ctx, pBuf, nIn, sqlite3_free);
+ }else{
+ sqlite3_result_error_code(ctx, SQLITE_IOERR);
+ sqlite3_free(pBuf);
+ }
+ fclose(in);
+}
+
+/*
+** Implementation of the "readfile(X)" SQL function. The entire content
+** of the file named X is read and returned as a BLOB. NULL is returned
+** if the file does not exist or is unreadable.
+*/
+static void readfileFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zName;
+ (void)(argc); /* Unused parameter */
+ zName = (const char*)sqlite3_value_text(argv[0]);
+ if( zName==0 ) return;
+ readFileContents(context, zName);
+}
+
+/*
+** Set the error message contained in context ctx to the results of
+** vprintf(zFmt, ...).
+*/
+static void ctxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){
+ char *zMsg = 0;
+ va_list ap;
+ va_start(ap, zFmt);
+ zMsg = sqlite3_vmprintf(zFmt, ap);
+ sqlite3_result_error(ctx, zMsg, -1);
+ sqlite3_free(zMsg);
+ va_end(ap);
+}
+
+#if defined(_WIN32)
+/*
+** This function is designed to convert a Win32 FILETIME structure into the
+** number of seconds since the Unix Epoch (1970-01-01 00:00:00 UTC).
+*/
+static sqlite3_uint64 fileTimeToUnixTime(
+ LPFILETIME pFileTime
+){
+ SYSTEMTIME epochSystemTime;
+ ULARGE_INTEGER epochIntervals;
+ FILETIME epochFileTime;
+ ULARGE_INTEGER fileIntervals;
+
+ memset(&epochSystemTime, 0, sizeof(SYSTEMTIME));
+ epochSystemTime.wYear = 1970;
+ epochSystemTime.wMonth = 1;
+ epochSystemTime.wDay = 1;
+ SystemTimeToFileTime(&epochSystemTime, &epochFileTime);
+ epochIntervals.LowPart = epochFileTime.dwLowDateTime;
+ epochIntervals.HighPart = epochFileTime.dwHighDateTime;
+
+ fileIntervals.LowPart = pFileTime->dwLowDateTime;
+ fileIntervals.HighPart = pFileTime->dwHighDateTime;
+
+ return (fileIntervals.QuadPart - epochIntervals.QuadPart) / 10000000;
+}
+
+/*
+** This function attempts to normalize the time values found in the stat()
+** buffer to UTC. This is necessary on Win32, where the runtime library
+** appears to return these values as local times.
+*/
+static void statTimesToUtc(
+ const char *zPath,
+ struct stat *pStatBuf
+){
+ HANDLE hFindFile;
+ WIN32_FIND_DATAW fd;
+ LPWSTR zUnicodeName;
+ extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
+ zUnicodeName = sqlite3_win32_utf8_to_unicode(zPath);
+ if( zUnicodeName ){
+ memset(&fd, 0, sizeof(WIN32_FIND_DATAW));
+ hFindFile = FindFirstFileW(zUnicodeName, &fd);
+ if( hFindFile!=NULL ){
+ pStatBuf->st_ctime = (time_t)fileTimeToUnixTime(&fd.ftCreationTime);
+ pStatBuf->st_atime = (time_t)fileTimeToUnixTime(&fd.ftLastAccessTime);
+ pStatBuf->st_mtime = (time_t)fileTimeToUnixTime(&fd.ftLastWriteTime);
+ FindClose(hFindFile);
+ }
+ sqlite3_free(zUnicodeName);
+ }
+}
+#endif
+
+/*
+** This function is used in place of stat(). On Windows, special handling
+** is required in order for the included time to be returned as UTC. On all
+** other systems, this function simply calls stat().
+*/
+static int fileStat(
+ const char *zPath,
+ struct stat *pStatBuf
+){
+#if defined(_WIN32)
+ int rc = stat(zPath, pStatBuf);
+ if( rc==0 ) statTimesToUtc(zPath, pStatBuf);
+ return rc;
+#else
+ return stat(zPath, pStatBuf);
+#endif
+}
+
+/*
+** This function is used in place of lstat(). On Windows, special handling
+** is required in order for the included time to be returned as UTC. On all
+** other systems, this function simply calls lstat().
+*/
+static int fileLinkStat(
+ const char *zPath,
+ struct stat *pStatBuf
+){
+#if defined(_WIN32)
+ int rc = lstat(zPath, pStatBuf);
+ if( rc==0 ) statTimesToUtc(zPath, pStatBuf);
+ return rc;
+#else
+ return lstat(zPath, pStatBuf);
+#endif
+}
+
+/*
+** Argument zFile is the name of a file that will be created and/or written
+** by SQL function writefile(). This function ensures that the directory
+** zFile will be written to exists, creating it if required. The permissions
+** for any path components created by this function are set in accordance
+** with the current umask.
+**
+** If an OOM condition is encountered, SQLITE_NOMEM is returned. Otherwise,
+** SQLITE_OK is returned if the directory is successfully created, or
+** SQLITE_ERROR otherwise.
+*/
+static int makeDirectory(
+ const char *zFile
+){
+ char *zCopy = sqlite3_mprintf("%s", zFile);
+ int rc = SQLITE_OK;
+
+ if( zCopy==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ int nCopy = (int)strlen(zCopy);
+ int i = 1;
+
+ while( rc==SQLITE_OK ){
+ struct stat sStat;
+ int rc2;
+
+ for(; zCopy[i]!='/' && i<nCopy; i++);
+ if( i==nCopy ) break;
+ zCopy[i] = '\0';
+
+ rc2 = fileStat(zCopy, &sStat);
+ if( rc2!=0 ){
+ if( mkdir(zCopy, 0777) ) rc = SQLITE_ERROR;
+ }else{
+ if( !S_ISDIR(sStat.st_mode) ) rc = SQLITE_ERROR;
+ }
+ zCopy[i] = '/';
+ i++;
+ }
+
+ sqlite3_free(zCopy);
+ }
+
+ return rc;
+}
+
+/*
+** This function does the work for the writefile() UDF. Refer to
+** header comments at the top of this file for details.
+*/
+static int writeFile(
+ sqlite3_context *pCtx, /* Context to return bytes written in */
+ const char *zFile, /* File to write */
+ sqlite3_value *pData, /* Data to write */
+ mode_t mode, /* MODE parameter passed to writefile() */
+ sqlite3_int64 mtime /* MTIME parameter (or -1 to not set time) */
+){
+#if !defined(_WIN32) && !defined(WIN32)
+ if( S_ISLNK(mode) ){
+ const char *zTo = (const char*)sqlite3_value_text(pData);
+ if( symlink(zTo, zFile)<0 ) return 1;
+ }else
+#endif
+ {
+ if( S_ISDIR(mode) ){
+ if( mkdir(zFile, mode) ){
+ /* The mkdir() call to create the directory failed. This might not
+ ** be an error though - if there is already a directory at the same
+ ** path and either the permissions already match or can be changed
+ ** to do so using chmod(), it is not an error. */
+ struct stat sStat;
+ if( errno!=EEXIST
+ || 0!=fileStat(zFile, &sStat)
+ || !S_ISDIR(sStat.st_mode)
+ || ((sStat.st_mode&0777)!=(mode&0777) && 0!=chmod(zFile, mode&0777))
+ ){
+ return 1;
+ }
+ }
+ }else{
+ sqlite3_int64 nWrite = 0;
+ const char *z;
+ int rc = 0;
+ FILE *out = fopen(zFile, "wb");
+ if( out==0 ) return 1;
+ z = (const char*)sqlite3_value_blob(pData);
+ if( z ){
+ sqlite3_int64 n = fwrite(z, 1, sqlite3_value_bytes(pData), out);
+ nWrite = sqlite3_value_bytes(pData);
+ if( nWrite!=n ){
+ rc = 1;
+ }
+ }
+ fclose(out);
+ if( rc==0 && mode && chmod(zFile, mode & 0777) ){
+ rc = 1;
+ }
+ if( rc ) return 2;
+ sqlite3_result_int64(pCtx, nWrite);
+ }
+ }
+
+ if( mtime>=0 ){
+#if defined(_WIN32)
+ /* Windows */
+ FILETIME lastAccess;
+ FILETIME lastWrite;
+ SYSTEMTIME currentTime;
+ LONGLONG intervals;
+ HANDLE hFile;
+ LPWSTR zUnicodeName;
+ extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
+
+ GetSystemTime(&currentTime);
+ SystemTimeToFileTime(&currentTime, &lastAccess);
+ intervals = Int32x32To64(mtime, 10000000) + 116444736000000000;
+ lastWrite.dwLowDateTime = (DWORD)intervals;
+ lastWrite.dwHighDateTime = intervals >> 32;
+ zUnicodeName = sqlite3_win32_utf8_to_unicode(zFile);
+ if( zUnicodeName==0 ){
+ return 1;
+ }
+ hFile = CreateFileW(
+ zUnicodeName, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL
+ );
+ sqlite3_free(zUnicodeName);
+ if( hFile!=INVALID_HANDLE_VALUE ){
+ BOOL bResult = SetFileTime(hFile, NULL, &lastAccess, &lastWrite);
+ CloseHandle(hFile);
+ return !bResult;
+ }else{
+ return 1;
+ }
+#elif defined(AT_FDCWD) && 0 /* utimensat() is not universally available */
+ /* Recent unix */
+ struct timespec times[2];
+ times[0].tv_nsec = times[1].tv_nsec = 0;
+ times[0].tv_sec = time(0);
+ times[1].tv_sec = mtime;
+ if( utimensat(AT_FDCWD, zFile, times, AT_SYMLINK_NOFOLLOW) ){
+ return 1;
+ }
+#else
+ /* Legacy unix */
+ struct timeval times[2];
+ times[0].tv_usec = times[1].tv_usec = 0;
+ times[0].tv_sec = time(0);
+ times[1].tv_sec = mtime;
+ if( utimes(zFile, times) ){
+ return 1;
+ }
+#endif
+ }
+
+ return 0;
+}
+
+/*
+** Implementation of the "writefile(W,X[,Y[,Z]]])" SQL function.
+** Refer to header comments at the top of this file for details.
+*/
+static void writefileFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zFile;
+ mode_t mode = 0;
+ int res;
+ sqlite3_int64 mtime = -1;
+
+ if( argc<2 || argc>4 ){
+ sqlite3_result_error(context,
+ "wrong number of arguments to function writefile()", -1
+ );
+ return;
+ }
+
+ zFile = (const char*)sqlite3_value_text(argv[0]);
+ if( zFile==0 ) return;
+ if( argc>=3 ){
+ mode = (mode_t)sqlite3_value_int(argv[2]);
+ }
+ if( argc==4 ){
+ mtime = sqlite3_value_int64(argv[3]);
+ }
+
+ res = writeFile(context, zFile, argv[1], mode, mtime);
+ if( res==1 && errno==ENOENT ){
+ if( makeDirectory(zFile)==SQLITE_OK ){
+ res = writeFile(context, zFile, argv[1], mode, mtime);
+ }
+ }
+
+ if( argc>2 && res!=0 ){
+#if !defined(_WIN32) && !defined(WIN32)
+ if( S_ISLNK(mode) ){
+ ctxErrorMsg(context, "failed to create symlink: %s", zFile);
+ }else
+#endif
+ if( S_ISDIR(mode) ){
+ ctxErrorMsg(context, "failed to create directory: %s", zFile);
+ }else{
+ ctxErrorMsg(context, "failed to write file: %s", zFile);
+ }
+ }
+}
+
+/*
+** SQL function: lsmode(MODE)
+**
+** Given a numberic st_mode from stat(), convert it into a human-readable
+** text string in the style of "ls -l".
+*/
+static void lsModeFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ int i;
+ int iMode = sqlite3_value_int(argv[0]);
+ char z[16];
+ (void)argc;
+#if !defined(_WIN32) && !defined(WIN32)
+ if( S_ISLNK(iMode) ){
+ z[0] = 'l';
+ }else
+#endif
+ if( S_ISREG(iMode) ){
+ z[0] = '-';
+ }else if( S_ISDIR(iMode) ){
+ z[0] = 'd';
+ }else{
+ z[0] = '?';
+ }
+ for(i=0; i<3; i++){
+ int m = (iMode >> ((2-i)*3));
+ char *a = &z[1 + i*3];
+ a[0] = (m & 0x4) ? 'r' : '-';
+ a[1] = (m & 0x2) ? 'w' : '-';
+ a[2] = (m & 0x1) ? 'x' : '-';
+ }
+ z[10] = '\0';
+ sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
+}
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/*
+** Cursor type for recursively iterating through a directory structure.
+*/
+typedef struct fsdir_cursor fsdir_cursor;
+typedef struct FsdirLevel FsdirLevel;
+
+struct FsdirLevel {
+ DIR *pDir; /* From opendir() */
+ char *zDir; /* Name of directory (nul-terminated) */
+};
+
+struct fsdir_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+
+ int nLvl; /* Number of entries in aLvl[] array */
+ int iLvl; /* Index of current entry */
+ FsdirLevel *aLvl; /* Hierarchy of directories being traversed */
+
+ const char *zBase;
+ int nBase;
+
+ struct stat sStat; /* Current lstat() results */
+ char *zPath; /* Path to current entry */
+ sqlite3_int64 iRowid; /* Current rowid */
+};
+
+typedef struct fsdir_tab fsdir_tab;
+struct fsdir_tab {
+ sqlite3_vtab base; /* Base class - must be first */
+};
+
+/*
+** Construct a new fsdir virtual table object.
+*/
+static int fsdirConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ fsdir_tab *pNew = 0;
+ int rc;
+ (void)pAux;
+ (void)argc;
+ (void)argv;
+ (void)pzErr;
+ rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA);
+ if( rc==SQLITE_OK ){
+ pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) );
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ }
+ *ppVtab = (sqlite3_vtab*)pNew;
+ return rc;
+}
+
+/*
+** This method is the destructor for fsdir vtab objects.
+*/
+static int fsdirDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new fsdir_cursor object.
+*/
+static int fsdirOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ fsdir_cursor *pCur;
+ (void)p;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ pCur->iLvl = -1;
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Reset a cursor back to the state it was in when first returned
+** by fsdirOpen().
+*/
+static void fsdirResetCursor(fsdir_cursor *pCur){
+ int i;
+ for(i=0; i<=pCur->iLvl; i++){
+ FsdirLevel *pLvl = &pCur->aLvl[i];
+ if( pLvl->pDir ) closedir(pLvl->pDir);
+ sqlite3_free(pLvl->zDir);
+ }
+ sqlite3_free(pCur->zPath);
+ sqlite3_free(pCur->aLvl);
+ pCur->aLvl = 0;
+ pCur->zPath = 0;
+ pCur->zBase = 0;
+ pCur->nBase = 0;
+ pCur->nLvl = 0;
+ pCur->iLvl = -1;
+ pCur->iRowid = 1;
+}
+
+/*
+** Destructor for an fsdir_cursor.
+*/
+static int fsdirClose(sqlite3_vtab_cursor *cur){
+ fsdir_cursor *pCur = (fsdir_cursor*)cur;
+
+ fsdirResetCursor(pCur);
+ sqlite3_free(pCur);
+ return SQLITE_OK;
+}
+
+/*
+** Set the error message for the virtual table associated with cursor
+** pCur to the results of vprintf(zFmt, ...).
+*/
+static void fsdirSetErrmsg(fsdir_cursor *pCur, const char *zFmt, ...){
+ va_list ap;
+ va_start(ap, zFmt);
+ pCur->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap);
+ va_end(ap);
+}
+
+
+/*
+** Advance an fsdir_cursor to its next row of output.
+*/
+static int fsdirNext(sqlite3_vtab_cursor *cur){
+ fsdir_cursor *pCur = (fsdir_cursor*)cur;
+ mode_t m = pCur->sStat.st_mode;
+
+ pCur->iRowid++;
+ if( S_ISDIR(m) ){
+ /* Descend into this directory */
+ int iNew = pCur->iLvl + 1;
+ FsdirLevel *pLvl;
+ if( iNew>=pCur->nLvl ){
+ int nNew = iNew+1;
+ size_t nByte = nNew*sizeof(FsdirLevel);
+ FsdirLevel *aNew = (FsdirLevel*)sqlite3_realloc(pCur->aLvl, nByte);
+ if( aNew==0 ) return SQLITE_NOMEM;
+ memset(&aNew[pCur->nLvl], 0, sizeof(FsdirLevel)*(nNew-pCur->nLvl));
+ pCur->aLvl = aNew;
+ pCur->nLvl = nNew;
+ }
+ pCur->iLvl = iNew;
+ pLvl = &pCur->aLvl[iNew];
+
+ pLvl->zDir = pCur->zPath;
+ pCur->zPath = 0;
+ pLvl->pDir = opendir(pLvl->zDir);
+ if( pLvl->pDir==0 ){
+ fsdirSetErrmsg(pCur, "cannot read directory: %s", pCur->zPath);
+ return SQLITE_ERROR;
+ }
+ }
+
+ while( pCur->iLvl>=0 ){
+ FsdirLevel *pLvl = &pCur->aLvl[pCur->iLvl];
+ struct dirent *pEntry = readdir(pLvl->pDir);
+ if( pEntry ){
+ if( pEntry->d_name[0]=='.' ){
+ if( pEntry->d_name[1]=='.' && pEntry->d_name[2]=='\0' ) continue;
+ if( pEntry->d_name[1]=='\0' ) continue;
+ }
+ sqlite3_free(pCur->zPath);
+ pCur->zPath = sqlite3_mprintf("%s/%s", pLvl->zDir, pEntry->d_name);
+ if( pCur->zPath==0 ) return SQLITE_NOMEM;
+ if( fileLinkStat(pCur->zPath, &pCur->sStat) ){
+ fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
+ return SQLITE_ERROR;
+ }
+ return SQLITE_OK;
+ }
+ closedir(pLvl->pDir);
+ sqlite3_free(pLvl->zDir);
+ pLvl->pDir = 0;
+ pLvl->zDir = 0;
+ pCur->iLvl--;
+ }
+
+ /* EOF */
+ sqlite3_free(pCur->zPath);
+ pCur->zPath = 0;
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the series_cursor
+** is currently pointing.
+*/
+static int fsdirColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ fsdir_cursor *pCur = (fsdir_cursor*)cur;
+ switch( i ){
+ case FSDIR_COLUMN_NAME: {
+ sqlite3_result_text(ctx, &pCur->zPath[pCur->nBase], -1, SQLITE_TRANSIENT);
+ break;
+ }
+
+ case FSDIR_COLUMN_MODE:
+ sqlite3_result_int64(ctx, pCur->sStat.st_mode);
+ break;
+
+ case FSDIR_COLUMN_MTIME:
+ sqlite3_result_int64(ctx, pCur->sStat.st_mtime);
+ break;
+
+ case FSDIR_COLUMN_DATA: {
+ mode_t m = pCur->sStat.st_mode;
+ if( S_ISDIR(m) ){
+ sqlite3_result_null(ctx);
+#if !defined(_WIN32) && !defined(WIN32)
+ }else if( S_ISLNK(m) ){
+ char aStatic[64];
+ char *aBuf = aStatic;
+ size_t nBuf = 64;
+ size_t n;
+
+ while( 1 ){
+ n = readlink(pCur->zPath, aBuf, nBuf);
+ if( n<nBuf ) break;
+ if( aBuf!=aStatic ) sqlite3_free(aBuf);
+ nBuf = nBuf*2;
+ aBuf = sqlite3_malloc(nBuf);
+ if( aBuf==0 ){
+ sqlite3_result_error_nomem(ctx);
+ return SQLITE_NOMEM;
+ }
+ }
+
+ sqlite3_result_text(ctx, aBuf, n, SQLITE_TRANSIENT);
+ if( aBuf!=aStatic ) sqlite3_free(aBuf);
+#endif
+ }else{
+ readFileContents(ctx, pCur->zPath);
+ }
+ }
+ case FSDIR_COLUMN_PATH:
+ default: {
+ /* The FSDIR_COLUMN_PATH and FSDIR_COLUMN_DIR are input parameters.
+ ** always return their values as NULL */
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** first row returned is assigned rowid value 1, and each subsequent
+** row a value 1 more than that of the previous.
+*/
+static int fsdirRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ fsdir_cursor *pCur = (fsdir_cursor*)cur;
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int fsdirEof(sqlite3_vtab_cursor *cur){
+ fsdir_cursor *pCur = (fsdir_cursor*)cur;
+ return (pCur->zPath==0);
+}
+
+/*
+** xFilter callback.
+**
+** idxNum==1 PATH parameter only
+** idxNum==2 Both PATH and DIR supplied
+*/
+static int fsdirFilter(
+ sqlite3_vtab_cursor *cur,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ const char *zDir = 0;
+ fsdir_cursor *pCur = (fsdir_cursor*)cur;
+ (void)idxStr;
+ fsdirResetCursor(pCur);
+
+ if( idxNum==0 ){
+ fsdirSetErrmsg(pCur, "table function fsdir requires an argument");
+ return SQLITE_ERROR;
+ }
+
+ assert( argc==idxNum && (argc==1 || argc==2) );
+ zDir = (const char*)sqlite3_value_text(argv[0]);
+ if( zDir==0 ){
+ fsdirSetErrmsg(pCur, "table function fsdir requires a non-NULL argument");
+ return SQLITE_ERROR;
+ }
+ if( argc==2 ){
+ pCur->zBase = (const char*)sqlite3_value_text(argv[1]);
+ }
+ if( pCur->zBase ){
+ pCur->nBase = (int)strlen(pCur->zBase)+1;
+ pCur->zPath = sqlite3_mprintf("%s/%s", pCur->zBase, zDir);
+ }else{
+ pCur->zPath = sqlite3_mprintf("%s", zDir);
+ }
+
+ if( pCur->zPath==0 ){
+ return SQLITE_NOMEM;
+ }
+ if( fileLinkStat(pCur->zPath, &pCur->sStat) ){
+ fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
+ return SQLITE_ERROR;
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the generate_series virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+**
+** In this implementation idxNum is used to represent the
+** query plan. idxStr is unused.
+**
+** The query plan is represented by values of idxNum:
+**
+** (1) The path value is supplied by argv[0]
+** (2) Path is in argv[0] and dir is in argv[1]
+*/
+static int fsdirBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int i; /* Loop over constraints */
+ int idxPath = -1; /* Index in pIdxInfo->aConstraint of PATH= */
+ int idxDir = -1; /* Index in pIdxInfo->aConstraint of DIR= */
+ int seenPath = 0; /* True if an unusable PATH= constraint is seen */
+ int seenDir = 0; /* True if an unusable DIR= constraint is seen */
+ const struct sqlite3_index_constraint *pConstraint;
+
+ (void)tab;
+ pConstraint = pIdxInfo->aConstraint;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
+ if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+ switch( pConstraint->iColumn ){
+ case FSDIR_COLUMN_PATH: {
+ if( pConstraint->usable ){
+ idxPath = i;
+ seenPath = 0;
+ }else if( idxPath<0 ){
+ seenPath = 1;
+ }
+ break;
+ }
+ case FSDIR_COLUMN_DIR: {
+ if( pConstraint->usable ){
+ idxDir = i;
+ seenDir = 0;
+ }else if( idxDir<0 ){
+ seenDir = 1;
+ }
+ break;
+ }
+ }
+ }
+ if( seenPath || seenDir ){
+ /* If input parameters are unusable, disallow this plan */
+ return SQLITE_CONSTRAINT;
+ }
+
+ if( idxPath<0 ){
+ pIdxInfo->idxNum = 0;
+ /* The pIdxInfo->estimatedCost should have been initialized to a huge
+ ** number. Leave it unchanged. */
+ pIdxInfo->estimatedRows = 0x7fffffff;
+ }else{
+ pIdxInfo->aConstraintUsage[idxPath].omit = 1;
+ pIdxInfo->aConstraintUsage[idxPath].argvIndex = 1;
+ if( idxDir>=0 ){
+ pIdxInfo->aConstraintUsage[idxDir].omit = 1;
+ pIdxInfo->aConstraintUsage[idxDir].argvIndex = 2;
+ pIdxInfo->idxNum = 2;
+ pIdxInfo->estimatedCost = 10.0;
+ }else{
+ pIdxInfo->idxNum = 1;
+ pIdxInfo->estimatedCost = 100.0;
+ }
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Register the "fsdir" virtual table.
+*/
+static int fsdirRegister(sqlite3 *db){
+ static const sqlite3_module fsdirModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ fsdirConnect, /* xConnect */
+ fsdirBestIndex, /* xBestIndex */
+ fsdirDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ fsdirOpen, /* xOpen - open a cursor */
+ fsdirClose, /* xClose - close a cursor */
+ fsdirFilter, /* xFilter - configure scan constraints */
+ fsdirNext, /* xNext - advance a cursor */
+ fsdirEof, /* xEof - check for end of scan */
+ fsdirColumn, /* xColumn - read data */
+ fsdirRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0, /* xShadowName */
+ };
+
+ int rc = sqlite3_create_module(db, "fsdir", &fsdirModule, 0);
+ return rc;
+}
+#else /* SQLITE_OMIT_VIRTUALTABLE */
+# define fsdirRegister(x) SQLITE_OK
+#endif
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_fileio_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
+ readfileFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "writefile", -1, SQLITE_UTF8, 0,
+ writefileFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "lsmode", 1, SQLITE_UTF8, 0,
+ lsModeFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = fsdirRegister(db);
+ }
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
+ readfileFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0,
+ writefileFunc, 0, 0);
+ }
+ return rc;
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/fossildelta.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/fossildelta.c 2019-10-08 13:42:19.135915400 +0200
@@ -0,0 +1,1115 @@
+/*
+** 2019-02-19
+**
+** 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 SQLite extension implements the delta functions used by the RBU
+** extension. Three scalar functions and one table-valued function are
+** implemented here:
+**
+** delta_apply(X,D) -- apply delta D to file X and return the result
+** delta_create(X,Y) -- compute and return a delta that carries X into Y
+** delta_output_size(D) -- blob size in bytes output from applying delta D
+** delta_parse(D) -- returns rows describing delta D
+**
+** The delta format is the Fossil delta format, described in a comment
+** on the delete_create() function implementation below, and also at
+**
+** https://www.fossil-scm.org/fossil/doc/trunk/www/delta_format.wiki
+**
+** This delta format is used by the RBU extension, which is the main
+** reason that these routines are included in the extension library.
+** RBU does not use this extension directly. Rather, this extension is
+** provided as a convenience to developers who want to analyze RBU files
+** that contain deltas.
+*/
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+
+#ifndef SQLITE_AMALGAMATION
+/*
+** The "u32" type must be an unsigned 32-bit integer. Adjust this
+*/
+typedef unsigned int u32;
+
+/*
+** Must be a 16-bit value
+*/
+typedef short int s16;
+typedef unsigned short int u16;
+
+#endif /* SQLITE_AMALGAMATION */
+
+
+/*
+** The width of a hash window in bytes. The algorithm only works if this
+** is a power of 2.
+*/
+#define NHASH 16
+
+/*
+** The current state of the rolling hash.
+**
+** z[] holds the values that have been hashed. z[] is a circular buffer.
+** z[i] is the first entry and z[(i+NHASH-1)%NHASH] is the last entry of
+** the window.
+**
+** Hash.a is the sum of all elements of hash.z[]. Hash.b is a weighted
+** sum. Hash.b is z[i]*NHASH + z[i+1]*(NHASH-1) + ... + z[i+NHASH-1]*1.
+** (Each index for z[] should be module NHASH, of course. The %NHASH operator
+** is omitted in the prior expression for brevity.)
+*/
+typedef struct hash hash;
+struct hash {
+ u16 a, b; /* Hash values */
+ u16 i; /* Start of the hash window */
+ char z[NHASH]; /* The values that have been hashed */
+};
+
+/*
+** Initialize the rolling hash using the first NHASH characters of z[]
+*/
+static void hash_init(hash *pHash, const char *z){
+ u16 a, b, i;
+ a = b = z[0];
+ for(i=1; i<NHASH; i++){
+ a += z[i];
+ b += a;
+ }
+ memcpy(pHash->z, z, NHASH);
+ pHash->a = a & 0xffff;
+ pHash->b = b & 0xffff;
+ pHash->i = 0;
+}
+
+/*
+** Advance the rolling hash by a single character "c"
+*/
+static void hash_next(hash *pHash, int c){
+ u16 old = pHash->z[pHash->i];
+ pHash->z[pHash->i] = c;
+ pHash->i = (pHash->i+1)&(NHASH-1);
+ pHash->a = pHash->a - old + c;
+ pHash->b = pHash->b - NHASH*old + pHash->a;
+}
+
+/*
+** Return a 32-bit hash value
+*/
+static u32 hash_32bit(hash *pHash){
+ return (pHash->a & 0xffff) | (((u32)(pHash->b & 0xffff))<<16);
+}
+
+/*
+** Compute a hash on NHASH bytes.
+**
+** This routine is intended to be equivalent to:
+** hash h;
+** hash_init(&h, zInput);
+** return hash_32bit(&h);
+*/
+static u32 hash_once(const char *z){
+ u16 a, b, i;
+ a = b = z[0];
+ for(i=1; i<NHASH; i++){
+ a += z[i];
+ b += a;
+ }
+ return a | (((u32)b)<<16);
+}
+
+/*
+** Write an base-64 integer into the given buffer.
+*/
+static void putInt(unsigned int v, char **pz){
+ static const char zDigits[] =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~";
+ /* 123456789 123456789 123456789 123456789 123456789 123456789 123 */
+ int i, j;
+ char zBuf[20];
+ if( v==0 ){
+ *(*pz)++ = '0';
+ return;
+ }
+ for(i=0; v>0; i++, v>>=6){
+ zBuf[i] = zDigits[v&0x3f];
+ }
+ for(j=i-1; j>=0; j--){
+ *(*pz)++ = zBuf[j];
+ }
+}
+
+/*
+** Read bytes from *pz and convert them into a positive integer. When
+** finished, leave *pz pointing to the first character past the end of
+** the integer. The *pLen parameter holds the length of the string
+** in *pz and is decremented once for each character in the integer.
+*/
+static unsigned int deltaGetInt(const char **pz, int *pLen){
+ static const signed char zValue[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
+ -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36,
+ -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, -1, -1, -1, 63, -1,
+ };
+ unsigned int v = 0;
+ int c;
+ unsigned char *z = (unsigned char*)*pz;
+ unsigned char *zStart = z;
+ while( (c = zValue[0x7f&*(z++)])>=0 ){
+ v = (v<<6) + c;
+ }
+ z--;
+ *pLen -= z - zStart;
+ *pz = (char*)z;
+ return v;
+}
+
+/*
+** Return the number digits in the base-64 representation of a positive integer
+*/
+static int digit_count(int v){
+ unsigned int i, x;
+ for(i=1, x=64; v>=x; i++, x <<= 6){}
+ return i;
+}
+
+#ifdef __GNUC__
+# define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__)
+#else
+# define GCC_VERSION 0
+#endif
+
+/*
+** Compute a 32-bit big-endian checksum on the N-byte buffer. If the
+** buffer is not a multiple of 4 bytes length, compute the sum that would
+** have occurred if the buffer was padded with zeros to the next multiple
+** of four bytes.
+*/
+static unsigned int checksum(const char *zIn, size_t N){
+ static const int byteOrderTest = 1;
+ const unsigned char *z = (const unsigned char *)zIn;
+ const unsigned char *zEnd = (const unsigned char*)&zIn[N&~3];
+ unsigned sum = 0;
+ assert( (z - (const unsigned char*)0)%4==0 ); /* Four-byte alignment */
+ if( 0==*(char*)&byteOrderTest ){
+ /* This is a big-endian machine */
+ while( z<zEnd ){
+ sum += *(unsigned*)z;
+ z += 4;
+ }
+ }else{
+ /* A little-endian machine */
+#if GCC_VERSION>=4003000
+ while( z<zEnd ){
+ sum += __builtin_bswap32(*(unsigned*)z);
+ z += 4;
+ }
+#elif defined(_MSC_VER) && _MSC_VER>=1300
+ while( z<zEnd ){
+ sum += _byteswap_ulong(*(unsigned*)z);
+ z += 4;
+ }
+#else
+ unsigned sum0 = 0;
+ unsigned sum1 = 0;
+ unsigned sum2 = 0;
+ while(N >= 16){
+ sum0 += ((unsigned)z[0] + z[4] + z[8] + z[12]);
+ sum1 += ((unsigned)z[1] + z[5] + z[9] + z[13]);
+ sum2 += ((unsigned)z[2] + z[6] + z[10]+ z[14]);
+ sum += ((unsigned)z[3] + z[7] + z[11]+ z[15]);
+ z += 16;
+ N -= 16;
+ }
+ while(N >= 4){
+ sum0 += z[0];
+ sum1 += z[1];
+ sum2 += z[2];
+ sum += z[3];
+ z += 4;
+ N -= 4;
+ }
+ sum += (sum2 << 8) + (sum1 << 16) + (sum0 << 24);
+#endif
+ }
+ switch(N&3){
+ case 3: sum += (z[2] << 8);
+ case 2: sum += (z[1] << 16);
+ case 1: sum += (z[0] << 24);
+ default: ;
+ }
+ return sum;
+}
+
+/*
+** Create a new delta.
+**
+** The delta is written into a preallocated buffer, zDelta, which
+** should be at least 60 bytes longer than the target file, zOut.
+** The delta string will be NUL-terminated, but it might also contain
+** embedded NUL characters if either the zSrc or zOut files are
+** binary. This function returns the length of the delta string
+** in bytes, excluding the final NUL terminator character.
+**
+** Output Format:
+**
+** The delta begins with a base64 number followed by a newline. This
+** number is the number of bytes in the TARGET file. Thus, given a
+** delta file z, a program can compute the size of the output file
+** simply by reading the first line and decoding the base-64 number
+** found there. The delta_output_size() routine does exactly this.
+**
+** After the initial size number, the delta consists of a series of
+** literal text segments and commands to copy from the SOURCE file.
+** A copy command looks like this:
+**
+** NNN@MMM,
+**
+** where NNN is the number of bytes to be copied and MMM is the offset
+** into the source file of the first byte (both base-64). If NNN is 0
+** it means copy the rest of the input file. Literal text is like this:
+**
+** NNN:TTTTT
+**
+** where NNN is the number of bytes of text (base-64) and TTTTT is the text.
+**
+** The last term is of the form
+**
+** NNN;
+**
+** In this case, NNN is a 32-bit bigendian checksum of the output file
+** that can be used to verify that the delta applied correctly. All
+** numbers are in base-64.
+**
+** Pure text files generate a pure text delta. Binary files generate a
+** delta that may contain some binary data.
+**
+** Algorithm:
+**
+** The encoder first builds a hash table to help it find matching
+** patterns in the source file. 16-byte chunks of the source file
+** sampled at evenly spaced intervals are used to populate the hash
+** table.
+**
+** Next we begin scanning the target file using a sliding 16-byte
+** window. The hash of the 16-byte window in the target is used to
+** search for a matching section in the source file. When a match
+** is found, a copy command is added to the delta. An effort is
+** made to extend the matching section to regions that come before
+** and after the 16-byte hash window. A copy command is only issued
+** if the result would use less space that just quoting the text
+** literally. Literal text is added to the delta for sections that
+** do not match or which can not be encoded efficiently using copy
+** commands.
+*/
+static int delta_create(
+ const char *zSrc, /* The source or pattern file */
+ unsigned int lenSrc, /* Length of the source file */
+ const char *zOut, /* The target file */
+ unsigned int lenOut, /* Length of the target file */
+ char *zDelta /* Write the delta into this buffer */
+){
+ int i, base;
+ char *zOrigDelta = zDelta;
+ hash h;
+ int nHash; /* Number of hash table entries */
+ int *landmark; /* Primary hash table */
+ int *collide; /* Collision chain */
+ int lastRead = -1; /* Last byte of zSrc read by a COPY command */
+
+ /* Add the target file size to the beginning of the delta
+ */
+ putInt(lenOut, &zDelta);
+ *(zDelta++) = '\n';
+
+ /* If the source file is very small, it means that we have no
+ ** chance of ever doing a copy command. Just output a single
+ ** literal segment for the entire target and exit.
+ */
+ if( lenSrc<=NHASH ){
+ putInt(lenOut, &zDelta);
+ *(zDelta++) = ':';
+ memcpy(zDelta, zOut, lenOut);
+ zDelta += lenOut;
+ putInt(checksum(zOut, lenOut), &zDelta);
+ *(zDelta++) = ';';
+ return zDelta - zOrigDelta;
+ }
+
+ /* Compute the hash table used to locate matching sections in the
+ ** source file.
+ */
+ nHash = lenSrc/NHASH;
+ collide = sqlite3_malloc64( (sqlite3_int64)nHash*2*sizeof(int) );
+ memset(collide, -1, nHash*2*sizeof(int));
+ landmark = &collide[nHash];
+ for(i=0; i<lenSrc-NHASH; i+=NHASH){
+ int hv = hash_once(&zSrc[i]) % nHash;
+ collide[i/NHASH] = landmark[hv];
+ landmark[hv] = i/NHASH;
+ }
+
+ /* Begin scanning the target file and generating copy commands and
+ ** literal sections of the delta.
+ */
+ base = 0; /* We have already generated everything before zOut[base] */
+ while( base+NHASH<lenOut ){
+ int iSrc, iBlock;
+ unsigned int bestCnt, bestOfst=0, bestLitsz=0;
+ hash_init(&h, &zOut[base]);
+ i = 0; /* Trying to match a landmark against zOut[base+i] */
+ bestCnt = 0;
+ while( 1 ){
+ int hv;
+ int limit = 250;
+
+ hv = hash_32bit(&h) % nHash;
+ iBlock = landmark[hv];
+ while( iBlock>=0 && (limit--)>0 ){
+ /*
+ ** The hash window has identified a potential match against
+ ** landmark block iBlock. But we need to investigate further.
+ **
+ ** Look for a region in zOut that matches zSrc. Anchor the search
+ ** at zSrc[iSrc] and zOut[base+i]. Do not include anything prior to
+ ** zOut[base] or after zOut[outLen] nor anything after zSrc[srcLen].
+ **
+ ** Set cnt equal to the length of the match and set ofst so that
+ ** zSrc[ofst] is the first element of the match. litsz is the number
+ ** of characters between zOut[base] and the beginning of the match.
+ ** sz will be the overhead (in bytes) needed to encode the copy
+ ** command. Only generate copy command if the overhead of the
+ ** copy command is less than the amount of literal text to be copied.
+ */
+ int cnt, ofst, litsz;
+ int j, k, x, y;
+ int sz;
+ int limitX;
+
+ /* Beginning at iSrc, match forwards as far as we can. j counts
+ ** the number of characters that match */
+ iSrc = iBlock*NHASH;
+ y = base+i;
+ limitX = ( lenSrc-iSrc <= lenOut-y ) ? lenSrc : iSrc + lenOut - y;
+ for(x=iSrc; x<limitX; x++, y++){
+ if( zSrc[x]!=zOut[y] ) break;
+ }
+ j = x - iSrc - 1;
+
+ /* Beginning at iSrc-1, match backwards as far as we can. k counts
+ ** the number of characters that match */
+ for(k=1; k<iSrc && k<=i; k++){
+ if( zSrc[iSrc-k]!=zOut[base+i-k] ) break;
+ }
+ k--;
+
+ /* Compute the offset and size of the matching region */
+ ofst = iSrc-k;
+ cnt = j+k+1;
+ litsz = i-k; /* Number of bytes of literal text before the copy */
+ /* sz will hold the number of bytes needed to encode the "insert"
+ ** command and the copy command, not counting the "insert" text */
+ sz = digit_count(i-k)+digit_count(cnt)+digit_count(ofst)+3;
+ if( cnt>=sz && cnt>bestCnt ){
+ /* Remember this match only if it is the best so far and it
+ ** does not increase the file size */
+ bestCnt = cnt;
+ bestOfst = iSrc-k;
+ bestLitsz = litsz;
+ }
+
+ /* Check the next matching block */
+ iBlock = collide[iBlock];
+ }
+
+ /* We have a copy command that does not cause the delta to be larger
+ ** than a literal insert. So add the copy command to the delta.
+ */
+ if( bestCnt>0 ){
+ if( bestLitsz>0 ){
+ /* Add an insert command before the copy */
+ putInt(bestLitsz,&zDelta);
+ *(zDelta++) = ':';
+ memcpy(zDelta, &zOut[base], bestLitsz);
+ zDelta += bestLitsz;
+ base += bestLitsz;
+ }
+ base += bestCnt;
+ putInt(bestCnt, &zDelta);
+ *(zDelta++) = '@';
+ putInt(bestOfst, &zDelta);
+ *(zDelta++) = ',';
+ if( bestOfst + bestCnt -1 > lastRead ){
+ lastRead = bestOfst + bestCnt - 1;
+ }
+ bestCnt = 0;
+ break;
+ }
+
+ /* If we reach this point, it means no match is found so far */
+ if( base+i+NHASH>=lenOut ){
+ /* We have reached the end of the file and have not found any
+ ** matches. Do an "insert" for everything that does not match */
+ putInt(lenOut-base, &zDelta);
+ *(zDelta++) = ':';
+ memcpy(zDelta, &zOut[base], lenOut-base);
+ zDelta += lenOut-base;
+ base = lenOut;
+ break;
+ }
+
+ /* Advance the hash by one character. Keep looking for a match */
+ hash_next(&h, zOut[base+i+NHASH]);
+ i++;
+ }
+ }
+ /* Output a final "insert" record to get all the text at the end of
+ ** the file that does not match anything in the source file.
+ */
+ if( base<lenOut ){
+ putInt(lenOut-base, &zDelta);
+ *(zDelta++) = ':';
+ memcpy(zDelta, &zOut[base], lenOut-base);
+ zDelta += lenOut-base;
+ }
+ /* Output the final checksum record. */
+ putInt(checksum(zOut, lenOut), &zDelta);
+ *(zDelta++) = ';';
+ sqlite3_free(collide);
+ return zDelta - zOrigDelta;
+}
+
+/*
+** Return the size (in bytes) of the output from applying
+** a delta.
+**
+** This routine is provided so that an procedure that is able
+** to call delta_apply() can learn how much space is required
+** for the output and hence allocate nor more space that is really
+** needed.
+*/
+static int delta_output_size(const char *zDelta, int lenDelta){
+ int size;
+ size = deltaGetInt(&zDelta, &lenDelta);
+ if( *zDelta!='\n' ){
+ /* ERROR: size integer not terminated by "\n" */
+ return -1;
+ }
+ return size;
+}
+
+
+/*
+** Apply a delta.
+**
+** The output buffer should be big enough to hold the whole output
+** file and a NUL terminator at the end. The delta_output_size()
+** routine will determine this size for you.
+**
+** The delta string should be null-terminated. But the delta string
+** may contain embedded NUL characters (if the input and output are
+** binary files) so we also have to pass in the length of the delta in
+** the lenDelta parameter.
+**
+** This function returns the size of the output file in bytes (excluding
+** the final NUL terminator character). Except, if the delta string is
+** malformed or intended for use with a source file other than zSrc,
+** then this routine returns -1.
+**
+** Refer to the delta_create() documentation above for a description
+** of the delta file format.
+*/
+static int delta_apply(
+ const char *zSrc, /* The source or pattern file */
+ int lenSrc, /* Length of the source file */
+ const char *zDelta, /* Delta to apply to the pattern */
+ int lenDelta, /* Length of the delta */
+ char *zOut /* Write the output into this preallocated buffer */
+){
+ unsigned int limit;
+ unsigned int total = 0;
+#ifdef FOSSIL_ENABLE_DELTA_CKSUM_TEST
+ char *zOrigOut = zOut;
+#endif
+
+ limit = deltaGetInt(&zDelta, &lenDelta);
+ if( *zDelta!='\n' ){
+ /* ERROR: size integer not terminated by "\n" */
+ return -1;
+ }
+ zDelta++; lenDelta--;
+ while( *zDelta && lenDelta>0 ){
+ unsigned int cnt, ofst;
+ cnt = deltaGetInt(&zDelta, &lenDelta);
+ switch( zDelta[0] ){
+ case '@': {
+ zDelta++; lenDelta--;
+ ofst = deltaGetInt(&zDelta, &lenDelta);
+ if( lenDelta>0 && zDelta[0]!=',' ){
+ /* ERROR: copy command not terminated by ',' */
+ return -1;
+ }
+ zDelta++; lenDelta--;
+ total += cnt;
+ if( total>limit ){
+ /* ERROR: copy exceeds output file size */
+ return -1;
+ }
+ if( ofst+cnt > lenSrc ){
+ /* ERROR: copy extends past end of input */
+ return -1;
+ }
+ memcpy(zOut, &zSrc[ofst], cnt);
+ zOut += cnt;
+ break;
+ }
+ case ':': {
+ zDelta++; lenDelta--;
+ total += cnt;
+ if( total>limit ){
+ /* ERROR: insert command gives an output larger than predicted */
+ return -1;
+ }
+ if( cnt>lenDelta ){
+ /* ERROR: insert count exceeds size of delta */
+ return -1;
+ }
+ memcpy(zOut, zDelta, cnt);
+ zOut += cnt;
+ zDelta += cnt;
+ lenDelta -= cnt;
+ break;
+ }
+ case ';': {
+ zDelta++; lenDelta--;
+ zOut[0] = 0;
+#ifdef FOSSIL_ENABLE_DELTA_CKSUM_TEST
+ if( cnt!=checksum(zOrigOut, total) ){
+ /* ERROR: bad checksum */
+ return -1;
+ }
+#endif
+ if( total!=limit ){
+ /* ERROR: generated size does not match predicted size */
+ return -1;
+ }
+ return total;
+ }
+ default: {
+ /* ERROR: unknown delta operator */
+ return -1;
+ }
+ }
+ }
+ /* ERROR: unterminated delta */
+ return -1;
+}
+
+/*
+** SQL functions: delta_create(X,Y)
+**
+** Return a delta for carrying X into Y.
+*/
+static void deltaCreateFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *aOrig; int nOrig; /* old blob */
+ const char *aNew; int nNew; /* new blob */
+ char *aOut; int nOut; /* output delta */
+
+ assert( argc==2 );
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
+ if( sqlite3_value_type(argv[1])==SQLITE_NULL ) return;
+ nOrig = sqlite3_value_bytes(argv[0]);
+ aOrig = (const char*)sqlite3_value_blob(argv[0]);
+ nNew = sqlite3_value_bytes(argv[1]);
+ aNew = (const char*)sqlite3_value_blob(argv[1]);
+ aOut = sqlite3_malloc64(nNew+70);
+ if( aOut==0 ){
+ sqlite3_result_error_nomem(context);
+ }else{
+ nOut = delta_create(aOrig, nOrig, aNew, nNew, aOut);
+ if( nOut<0 ){
+ sqlite3_free(aOut);
+ sqlite3_result_error(context, "cannot create fossil delta", -1);
+ }else{
+ sqlite3_result_blob(context, aOut, nOut, sqlite3_free);
+ }
+ }
+}
+
+/*
+** SQL functions: delta_apply(X,D)
+**
+** Return the result of applying delta D to input X.
+*/
+static void deltaApplyFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *aOrig; int nOrig; /* The X input */
+ const char *aDelta; int nDelta; /* The input delta (D) */
+ char *aOut; int nOut, nOut2; /* The output */
+
+ assert( argc==2 );
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
+ if( sqlite3_value_type(argv[1])==SQLITE_NULL ) return;
+ nOrig = sqlite3_value_bytes(argv[0]);
+ aOrig = (const char*)sqlite3_value_blob(argv[0]);
+ nDelta = sqlite3_value_bytes(argv[1]);
+ aDelta = (const char*)sqlite3_value_blob(argv[1]);
+
+ /* Figure out the size of the output */
+ nOut = delta_output_size(aDelta, nDelta);
+ if( nOut<0 ){
+ sqlite3_result_error(context, "corrupt fossil delta", -1);
+ return;
+ }
+ aOut = sqlite3_malloc64((sqlite3_int64)nOut+1);
+ if( aOut==0 ){
+ sqlite3_result_error_nomem(context);
+ }else{
+ nOut2 = delta_apply(aOrig, nOrig, aDelta, nDelta, aOut);
+ if( nOut2!=nOut ){
+ sqlite3_free(aOut);
+ sqlite3_result_error(context, "corrupt fossil delta", -1);
+ }else{
+ sqlite3_result_blob(context, aOut, nOut, sqlite3_free);
+ }
+ }
+}
+
+
+/*
+** SQL functions: delta_output_size(D)
+**
+** Return the size of the output that results from applying delta D.
+*/
+static void deltaOutputSizeFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *aDelta; int nDelta; /* The input delta (D) */
+ int nOut; /* Size of output */
+ assert( argc==1 );
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
+ nDelta = sqlite3_value_bytes(argv[0]);
+ aDelta = (const char*)sqlite3_value_blob(argv[0]);
+
+ /* Figure out the size of the output */
+ nOut = delta_output_size(aDelta, nDelta);
+ if( nOut<0 ){
+ sqlite3_result_error(context, "corrupt fossil delta", -1);
+ return;
+ }else{
+ sqlite3_result_int(context, nOut);
+ }
+}
+
+/*****************************************************************************
+** Table-valued SQL function: delta_parse(DELTA)
+**
+** Schema:
+**
+** CREATE TABLE delta_parse(
+** op TEXT,
+** a1 INT,
+** a2 ANY,
+** delta HIDDEN BLOB
+** );
+**
+** Given an input DELTA, this function parses the delta and returns
+** rows for each entry in the delta. The op column has one of the
+** values SIZE, COPY, INSERT, CHECKSUM, ERROR.
+**
+** Assuming no errors, the first row has op='SIZE'. a1 is the size of
+** the output in bytes and a2 is NULL.
+**
+** After the initial SIZE row, there are zero or more 'COPY' and/or 'INSERT'
+** rows. A COPY row means content is copied from the source into the
+** output. Column a1 is the number of bytes to copy and a2 is the offset
+** into source from which to begin copying. An INSERT row means to
+** insert text into the output stream. Column a1 is the number of bytes
+** to insert and column is a BLOB that contains the text to be inserted.
+**
+** The last row of a well-formed delta will have an op value of 'CHECKSUM'.
+** The a1 column will be the value of the checksum and a2 will be NULL.
+**
+** If the input delta is not well-formed, then a row with an op value
+** of 'ERROR' is returned. The a1 value of the ERROR row is the offset
+** into the delta where the error was encountered and a2 is NULL.
+*/
+typedef struct deltaparsevtab_vtab deltaparsevtab_vtab;
+typedef struct deltaparsevtab_cursor deltaparsevtab_cursor;
+struct deltaparsevtab_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ /* No additional information needed */
+};
+struct deltaparsevtab_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ char *aDelta; /* The delta being parsed */
+ int nDelta; /* Number of bytes in the delta */
+ int iCursor; /* Current cursor location */
+ int eOp; /* Name of current operator */
+ unsigned int a1, a2; /* Arguments to current operator */
+ int iNext; /* Next cursor value */
+};
+
+/* Operator names:
+*/
+static const char *azOp[] = {
+ "SIZE", "COPY", "INSERT", "CHECKSUM", "ERROR", "EOF"
+};
+#define DELTAPARSE_OP_SIZE 0
+#define DELTAPARSE_OP_COPY 1
+#define DELTAPARSE_OP_INSERT 2
+#define DELTAPARSE_OP_CHECKSUM 3
+#define DELTAPARSE_OP_ERROR 4
+#define DELTAPARSE_OP_EOF 5
+
+/*
+** The deltaparsevtabConnect() method is invoked to create a new
+** deltaparse virtual table.
+**
+** Think of this routine as the constructor for deltaparsevtab_vtab objects.
+**
+** All this routine needs to do is:
+**
+** (1) Allocate the deltaparsevtab_vtab object and initialize all fields.
+**
+** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
+** result set of queries against the virtual table will look like.
+*/
+static int deltaparsevtabConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ deltaparsevtab_vtab *pNew;
+ int rc;
+
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x(op,a1,a2,delta HIDDEN)"
+ );
+ /* For convenience, define symbolic names for the index to each column. */
+#define DELTAPARSEVTAB_OP 0
+#define DELTAPARSEVTAB_A1 1
+#define DELTAPARSEVTAB_A2 2
+#define DELTAPARSEVTAB_DELTA 3
+ if( rc==SQLITE_OK ){
+ pNew = sqlite3_malloc64( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for deltaparsevtab_vtab objects.
+*/
+static int deltaparsevtabDisconnect(sqlite3_vtab *pVtab){
+ deltaparsevtab_vtab *p = (deltaparsevtab_vtab*)pVtab;
+ sqlite3_free(p);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new deltaparsevtab_cursor object.
+*/
+static int deltaparsevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ deltaparsevtab_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Destructor for a deltaparsevtab_cursor.
+*/
+static int deltaparsevtabClose(sqlite3_vtab_cursor *cur){
+ deltaparsevtab_cursor *pCur = (deltaparsevtab_cursor*)cur;
+ sqlite3_free(pCur->aDelta);
+ sqlite3_free(pCur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a deltaparsevtab_cursor to its next row of output.
+*/
+static int deltaparsevtabNext(sqlite3_vtab_cursor *cur){
+ deltaparsevtab_cursor *pCur = (deltaparsevtab_cursor*)cur;
+ const char *z;
+ int i = 0;
+
+ pCur->iCursor = pCur->iNext;
+ z = pCur->aDelta + pCur->iCursor;
+ pCur->a1 = deltaGetInt(&z, &i);
+ switch( z[0] ){
+ case '@': {
+ z++;
+ pCur->a2 = deltaGetInt(&z, &i);
+ pCur->eOp = DELTAPARSE_OP_COPY;
+ pCur->iNext = (int)(&z[1] - pCur->aDelta);
+ break;
+ }
+ case ':': {
+ z++;
+ pCur->a2 = (unsigned int)(z - pCur->aDelta);
+ pCur->eOp = DELTAPARSE_OP_INSERT;
+ pCur->iNext = (int)(&z[pCur->a1] - pCur->aDelta);
+ break;
+ }
+ case ';': {
+ pCur->eOp = DELTAPARSE_OP_CHECKSUM;
+ pCur->iNext = pCur->nDelta;
+ break;
+ }
+ default: {
+ if( pCur->iNext==pCur->nDelta ){
+ pCur->eOp = DELTAPARSE_OP_EOF;
+ }else{
+ pCur->eOp = DELTAPARSE_OP_ERROR;
+ pCur->iNext = pCur->nDelta;
+ }
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the deltaparsevtab_cursor
+** is currently pointing.
+*/
+static int deltaparsevtabColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ deltaparsevtab_cursor *pCur = (deltaparsevtab_cursor*)cur;
+ switch( i ){
+ case DELTAPARSEVTAB_OP: {
+ sqlite3_result_text(ctx, azOp[pCur->eOp], -1, SQLITE_STATIC);
+ break;
+ }
+ case DELTAPARSEVTAB_A1: {
+ sqlite3_result_int(ctx, pCur->a1);
+ break;
+ }
+ case DELTAPARSEVTAB_A2: {
+ if( pCur->eOp==DELTAPARSE_OP_COPY ){
+ sqlite3_result_int(ctx, pCur->a2);
+ }else if( pCur->eOp==DELTAPARSE_OP_INSERT ){
+ sqlite3_result_blob(ctx, pCur->aDelta+pCur->a2, pCur->a1,
+ SQLITE_TRANSIENT);
+ }
+ break;
+ }
+ case DELTAPARSEVTAB_DELTA: {
+ sqlite3_result_blob(ctx, pCur->aDelta, pCur->nDelta, SQLITE_TRANSIENT);
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** rowid is the same as the output value.
+*/
+static int deltaparsevtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ deltaparsevtab_cursor *pCur = (deltaparsevtab_cursor*)cur;
+ *pRowid = pCur->iCursor;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int deltaparsevtabEof(sqlite3_vtab_cursor *cur){
+ deltaparsevtab_cursor *pCur = (deltaparsevtab_cursor*)cur;
+ return pCur->eOp==DELTAPARSE_OP_EOF;
+}
+
+/*
+** This method is called to "rewind" the deltaparsevtab_cursor object back
+** to the first row of output. This method is always called at least
+** once prior to any call to deltaparsevtabColumn() or deltaparsevtabRowid() or
+** deltaparsevtabEof().
+*/
+static int deltaparsevtabFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ deltaparsevtab_cursor *pCur = (deltaparsevtab_cursor *)pVtabCursor;
+ const char *a;
+ int i = 0;
+ pCur->eOp = DELTAPARSE_OP_ERROR;
+ if( idxNum!=1 ){
+ return SQLITE_OK;
+ }
+ pCur->nDelta = sqlite3_value_bytes(argv[0]);
+ a = (const char*)sqlite3_value_blob(argv[0]);
+ if( pCur->nDelta==0 || a==0 ){
+ return SQLITE_OK;
+ }
+ pCur->aDelta = sqlite3_malloc64( pCur->nDelta+1 );
+ if( pCur->aDelta==0 ){
+ pCur->nDelta = 0;
+ return SQLITE_NOMEM;
+ }
+ memcpy(pCur->aDelta, a, pCur->nDelta);
+ pCur->aDelta[pCur->nDelta] = 0;
+ a = pCur->aDelta;
+ pCur->eOp = DELTAPARSE_OP_SIZE;
+ pCur->a1 = deltaGetInt(&a, &i);
+ if( a[0]!='\n' ){
+ pCur->eOp = DELTAPARSE_OP_ERROR;
+ pCur->a1 = pCur->a2 = 0;
+ pCur->iNext = pCur->nDelta;
+ return SQLITE_OK;
+ }
+ a++;
+ pCur->iNext = (unsigned int)(a - pCur->aDelta);
+ return SQLITE_OK;
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+*/
+static int deltaparsevtabBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int i;
+ for(i=0; i<pIdxInfo->nConstraint; i++){
+ if( pIdxInfo->aConstraint[i].iColumn != DELTAPARSEVTAB_DELTA ) continue;
+ if( pIdxInfo->aConstraint[i].usable==0 ) continue;
+ if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ pIdxInfo->estimatedCost = (double)1;
+ pIdxInfo->estimatedRows = 10;
+ pIdxInfo->idxNum = 1;
+ return SQLITE_OK;
+ }
+ pIdxInfo->idxNum = 0;
+ pIdxInfo->estimatedCost = (double)0x7fffffff;
+ pIdxInfo->estimatedRows = 0x7fffffff;
+ return SQLITE_CONSTRAINT;
+}
+
+/*
+** This following structure defines all the methods for the
+** virtual table.
+*/
+static const sqlite3_module deltaparsevtabModule = {
+ /* iVersion */ 0,
+ /* xCreate */ 0,
+ /* xConnect */ deltaparsevtabConnect,
+ /* xBestIndex */ deltaparsevtabBestIndex,
+ /* xDisconnect */ deltaparsevtabDisconnect,
+ /* xDestroy */ 0,
+ /* xOpen */ deltaparsevtabOpen,
+ /* xClose */ deltaparsevtabClose,
+ /* xFilter */ deltaparsevtabFilter,
+ /* xNext */ deltaparsevtabNext,
+ /* xEof */ deltaparsevtabEof,
+ /* xColumn */ deltaparsevtabColumn,
+ /* xRowid */ deltaparsevtabRowid,
+ /* xUpdate */ 0,
+ /* xBegin */ 0,
+ /* xSync */ 0,
+ /* xCommit */ 0,
+ /* xRollback */ 0,
+ /* xFindMethod */ 0,
+ /* xRename */ 0,
+ /* xSavepoint */ 0,
+ /* xRelease */ 0,
+ /* xRollbackTo */ 0,
+ /* xShadowName */ 0
+};
+
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_fossildelta_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "delta_create", 2, SQLITE_UTF8, 0,
+ deltaCreateFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "delta_apply", 2, SQLITE_UTF8, 0,
+ deltaApplyFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "delta_output_size", 1, SQLITE_UTF8, 0,
+ deltaOutputSizeFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_module(db, "delta_parse", &deltaparsevtabModule, 0);
+ }
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "delta_create", 2, SQLITE_UTF8, 0,
+ deltaCreateFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "delta_apply", 2, SQLITE_UTF8, 0,
+ deltaApplyFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "delta_output_size", 1, SQLITE_UTF8, 0,
+ deltaOutputSizeFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_module(db, "delta_parse", &deltaparsevtabModule, 0);
+ }
+ return rc;
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/fuzzer.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/fuzzer.c 2019-10-08 13:42:19.140797200 +0200
@@ -0,0 +1,1199 @@
+/*
+** 2011 March 24
+**
+** 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.
+**
+*************************************************************************
+**
+** Code for a demonstration virtual table that generates variations
+** on an input word at increasing edit distances from the original.
+**
+** A fuzzer virtual table is created like this:
+**
+** CREATE VIRTUAL TABLE f USING fuzzer(<fuzzer-data-table>);
+**
+** When it is created, the new fuzzer table must be supplied with the
+** name of a "fuzzer data table", which must reside in the same database
+** file as the new fuzzer table. The fuzzer data table contains the various
+** transformations and their costs that the fuzzer logic uses to generate
+** variations.
+**
+** The fuzzer data table must contain exactly four columns (more precisely,
+** the statement "SELECT * FROM <fuzzer_data_table>" must return records
+** that consist of four columns). It does not matter what the columns are
+** named.
+**
+** Each row in the fuzzer data table represents a single character
+** transformation. The left most column of the row (column 0) contains an
+** integer value - the identifier of the ruleset to which the transformation
+** rule belongs (see "MULTIPLE RULE SETS" below). The second column of the
+** row (column 0) contains the input character or characters. The third
+** column contains the output character or characters. And the fourth column
+** contains the integer cost of making the transformation. For example:
+**
+** CREATE TABLE f_data(ruleset, cFrom, cTo, Cost);
+** INSERT INTO f_data(ruleset, cFrom, cTo, Cost) VALUES(0, '', 'a', 100);
+** INSERT INTO f_data(ruleset, cFrom, cTo, Cost) VALUES(0, 'b', '', 87);
+** INSERT INTO f_data(ruleset, cFrom, cTo, Cost) VALUES(0, 'o', 'oe', 38);
+** INSERT INTO f_data(ruleset, cFrom, cTo, Cost) VALUES(0, 'oe', 'o', 40);
+**
+** The first row inserted into the fuzzer data table by the SQL script
+** above indicates that the cost of inserting a letter 'a' is 100. (All
+** costs are integers. We recommend that costs be scaled so that the
+** average cost is around 100.) The second INSERT statement creates a rule
+** saying that the cost of deleting a single letter 'b' is 87. The third
+** and fourth INSERT statements mean that the cost of transforming a
+** single letter "o" into the two-letter sequence "oe" is 38 and that the
+** cost of transforming "oe" back into "o" is 40.
+**
+** The contents of the fuzzer data table are loaded into main memory when
+** a fuzzer table is first created, and may be internally reloaded by the
+** system at any subsequent time. Therefore, the fuzzer data table should be
+** populated before the fuzzer table is created and not modified thereafter.
+** If you do need to modify the contents of the fuzzer data table, it is
+** recommended that the associated fuzzer table be dropped, the fuzzer data
+** table edited, and the fuzzer table recreated within a single transaction.
+** Alternatively, the fuzzer data table can be edited then the database
+** connection can be closed and reopened.
+**
+** Once it has been created, the fuzzer table can be queried as follows:
+**
+** SELECT word, distance FROM f
+** WHERE word MATCH 'abcdefg'
+** AND distance<200;
+**
+** This first query outputs the string "abcdefg" and all strings that
+** can be derived from that string by appling the specified transformations.
+** The strings are output together with their total transformation cost
+** (called "distance") and appear in order of increasing cost. No string
+** is output more than once. If there are multiple ways to transform the
+** target string into the output string then the lowest cost transform is
+** the one that is returned. In the example, the search is limited to
+** strings with a total distance of less than 200.
+**
+** The fuzzer is a read-only table. Any attempt to DELETE, INSERT, or
+** UPDATE on a fuzzer table will throw an error.
+**
+** It is important to put some kind of a limit on the fuzzer output. This
+** can be either in the form of a LIMIT clause at the end of the query,
+** or better, a "distance<NNN" constraint where NNN is some number. The
+** running time and memory requirement is exponential in the value of NNN
+** so you want to make sure that NNN is not too big. A value of NNN that
+** is about twice the average transformation cost seems to give good results.
+**
+** The fuzzer table can be useful for tasks such as spelling correction.
+** Suppose there is a second table vocabulary(w) where the w column contains
+** all correctly spelled words. Let $word be a word you want to look up.
+**
+** SELECT vocabulary.w FROM f, vocabulary
+** WHERE f.word MATCH $word
+** AND f.distance<=200
+** AND f.word=vocabulary.w
+** LIMIT 20
+**
+** The query above gives the 20 closest words to the $word being tested.
+** (Note that for good performance, the vocubulary.w column should be
+** indexed.)
+**
+** A similar query can be used to find all words in the dictionary that
+** begin with some prefix $prefix:
+**
+** SELECT vocabulary.w FROM f, vocabulary
+** WHERE f.word MATCH $prefix
+** AND f.distance<=200
+** AND vocabulary.w BETWEEN f.word AND (f.word || x'F7BFBFBF')
+** LIMIT 50
+**
+** This last query will show up to 50 words out of the vocabulary that
+** match or nearly match the $prefix.
+**
+** MULTIPLE RULE SETS
+**
+** Normally, the "ruleset" value associated with all character transformations
+** in the fuzzer data table is zero. However, if required, the fuzzer table
+** allows multiple rulesets to be defined. Each query uses only a single
+** ruleset. This allows, for example, a single fuzzer table to support
+** multiple languages.
+**
+** By default, only the rules from ruleset 0 are used. To specify an
+** alternative ruleset, a "ruleset = ?" expression must be added to the
+** WHERE clause of a SELECT, where ? is the identifier of the desired
+** ruleset. For example:
+**
+** SELECT vocabulary.w FROM f, vocabulary
+** WHERE f.word MATCH $word
+** AND f.distance<=200
+** AND f.word=vocabulary.w
+** AND f.ruleset=1 -- Specify the ruleset to use here
+** LIMIT 20
+**
+** If no "ruleset = ?" constraint is specified in the WHERE clause, ruleset
+** 0 is used.
+**
+** LIMITS
+**
+** The maximum ruleset number is 2147483647. The maximum length of either
+** of the strings in the second or third column of the fuzzer data table
+** is 50 bytes. The maximum cost on a rule is 1000.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+
+/* If SQLITE_DEBUG is not defined, disable assert statements. */
+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
+# define NDEBUG
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/*
+** Forward declaration of objects used by this implementation
+*/
+typedef struct fuzzer_vtab fuzzer_vtab;
+typedef struct fuzzer_cursor fuzzer_cursor;
+typedef struct fuzzer_rule fuzzer_rule;
+typedef struct fuzzer_seen fuzzer_seen;
+typedef struct fuzzer_stem fuzzer_stem;
+
+/*
+** Various types.
+**
+** fuzzer_cost is the "cost" of an edit operation.
+**
+** fuzzer_len is the length of a matching string.
+**
+** fuzzer_ruleid is an ruleset identifier.
+*/
+typedef int fuzzer_cost;
+typedef signed char fuzzer_len;
+typedef int fuzzer_ruleid;
+
+/*
+** Limits
+*/
+#define FUZZER_MX_LENGTH 50 /* Maximum length of a rule string */
+#define FUZZER_MX_RULEID 2147483647 /* Maximum rule ID */
+#define FUZZER_MX_COST 1000 /* Maximum single-rule cost */
+#define FUZZER_MX_OUTPUT_LENGTH 100 /* Maximum length of an output string */
+
+
+/*
+** Each transformation rule is stored as an instance of this object.
+** All rules are kept on a linked list sorted by rCost.
+*/
+struct fuzzer_rule {
+ fuzzer_rule *pNext; /* Next rule in order of increasing rCost */
+ char *zFrom; /* Transform from */
+ fuzzer_cost rCost; /* Cost of this transformation */
+ fuzzer_len nFrom, nTo; /* Length of the zFrom and zTo strings */
+ fuzzer_ruleid iRuleset; /* The rule set to which this rule belongs */
+ char zTo[4]; /* Transform to (extra space appended) */
+};
+
+/*
+** A stem object is used to generate variants. It is also used to record
+** previously generated outputs.
+**
+** Every stem is added to a hash table as it is output. Generation of
+** duplicate stems is suppressed.
+**
+** Active stems (those that might generate new outputs) are kepts on a linked
+** list sorted by increasing cost. The cost is the sum of rBaseCost and
+** pRule->rCost.
+*/
+struct fuzzer_stem {
+ char *zBasis; /* Word being fuzzed */
+ const fuzzer_rule *pRule; /* Current rule to apply */
+ fuzzer_stem *pNext; /* Next stem in rCost order */
+ fuzzer_stem *pHash; /* Next stem with same hash on zBasis */
+ fuzzer_cost rBaseCost; /* Base cost of getting to zBasis */
+ fuzzer_cost rCostX; /* Precomputed rBaseCost + pRule->rCost */
+ fuzzer_len nBasis; /* Length of the zBasis string */
+ fuzzer_len n; /* Apply pRule at this character offset */
+};
+
+/*
+** A fuzzer virtual-table object
+*/
+struct fuzzer_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ char *zClassName; /* Name of this class. Default: "fuzzer" */
+ fuzzer_rule *pRule; /* All active rules in this fuzzer */
+ int nCursor; /* Number of active cursors */
+};
+
+#define FUZZER_HASH 4001 /* Hash table size */
+#define FUZZER_NQUEUE 20 /* Number of slots on the stem queue */
+
+/* A fuzzer cursor object */
+struct fuzzer_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3_int64 iRowid; /* The rowid of the current word */
+ fuzzer_vtab *pVtab; /* The virtual table this cursor belongs to */
+ fuzzer_cost rLimit; /* Maximum cost of any term */
+ fuzzer_stem *pStem; /* Stem with smallest rCostX */
+ fuzzer_stem *pDone; /* Stems already processed to completion */
+ fuzzer_stem *aQueue[FUZZER_NQUEUE]; /* Queue of stems with higher rCostX */
+ int mxQueue; /* Largest used index in aQueue[] */
+ char *zBuf; /* Temporary use buffer */
+ int nBuf; /* Bytes allocated for zBuf */
+ int nStem; /* Number of stems allocated */
+ int iRuleset; /* Only process rules from this ruleset */
+ fuzzer_rule nullRule; /* Null rule used first */
+ fuzzer_stem *apHash[FUZZER_HASH]; /* Hash of previously generated terms */
+};
+
+/*
+** The two input rule lists are both sorted in order of increasing
+** cost. Merge them together into a single list, sorted by cost, and
+** return a pointer to the head of that list.
+*/
+static fuzzer_rule *fuzzerMergeRules(fuzzer_rule *pA, fuzzer_rule *pB){
+ fuzzer_rule head;
+ fuzzer_rule *pTail;
+
+ pTail = &head;
+ while( pA && pB ){
+ if( pA->rCost<=pB->rCost ){
+ pTail->pNext = pA;
+ pTail = pA;
+ pA = pA->pNext;
+ }else{
+ pTail->pNext = pB;
+ pTail = pB;
+ pB = pB->pNext;
+ }
+ }
+ if( pA==0 ){
+ pTail->pNext = pB;
+ }else{
+ pTail->pNext = pA;
+ }
+ return head.pNext;
+}
+
+/*
+** Statement pStmt currently points to a row in the fuzzer data table. This
+** function allocates and populates a fuzzer_rule structure according to
+** the content of the row.
+**
+** If successful, *ppRule is set to point to the new object and SQLITE_OK
+** is returned. Otherwise, *ppRule is zeroed, *pzErr may be set to point
+** to an error message and an SQLite error code returned.
+*/
+static int fuzzerLoadOneRule(
+ fuzzer_vtab *p, /* Fuzzer virtual table handle */
+ sqlite3_stmt *pStmt, /* Base rule on statements current row */
+ fuzzer_rule **ppRule, /* OUT: New rule object */
+ char **pzErr /* OUT: Error message */
+){
+ sqlite3_int64 iRuleset = sqlite3_column_int64(pStmt, 0);
+ const char *zFrom = (const char *)sqlite3_column_text(pStmt, 1);
+ const char *zTo = (const char *)sqlite3_column_text(pStmt, 2);
+ int nCost = sqlite3_column_int(pStmt, 3);
+
+ int rc = SQLITE_OK; /* Return code */
+ int nFrom; /* Size of string zFrom, in bytes */
+ int nTo; /* Size of string zTo, in bytes */
+ fuzzer_rule *pRule = 0; /* New rule object to return */
+
+ if( zFrom==0 ) zFrom = "";
+ if( zTo==0 ) zTo = "";
+ nFrom = (int)strlen(zFrom);
+ nTo = (int)strlen(zTo);
+
+ /* Silently ignore null transformations */
+ if( strcmp(zFrom, zTo)==0 ){
+ *ppRule = 0;
+ return SQLITE_OK;
+ }
+
+ if( nCost<=0 || nCost>FUZZER_MX_COST ){
+ *pzErr = sqlite3_mprintf("%s: cost must be between 1 and %d",
+ p->zClassName, FUZZER_MX_COST
+ );
+ rc = SQLITE_ERROR;
+ }else
+ if( nFrom>FUZZER_MX_LENGTH || nTo>FUZZER_MX_LENGTH ){
+ *pzErr = sqlite3_mprintf("%s: maximum string length is %d",
+ p->zClassName, FUZZER_MX_LENGTH
+ );
+ rc = SQLITE_ERROR;
+ }else
+ if( iRuleset<0 || iRuleset>FUZZER_MX_RULEID ){
+ *pzErr = sqlite3_mprintf("%s: ruleset must be between 0 and %d",
+ p->zClassName, FUZZER_MX_RULEID
+ );
+ rc = SQLITE_ERROR;
+ }else{
+
+ pRule = sqlite3_malloc( sizeof(*pRule) + nFrom + nTo );
+ if( pRule==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(pRule, 0, sizeof(*pRule));
+ pRule->zFrom = pRule->zTo;
+ pRule->zFrom += nTo + 1;
+ pRule->nFrom = (fuzzer_len)nFrom;
+ memcpy(pRule->zFrom, zFrom, nFrom+1);
+ memcpy(pRule->zTo, zTo, nTo+1);
+ pRule->nTo = (fuzzer_len)nTo;
+ pRule->rCost = nCost;
+ pRule->iRuleset = (int)iRuleset;
+ }
+ }
+
+ *ppRule = pRule;
+ return rc;
+}
+
+/*
+** Load the content of the fuzzer data table into memory.
+*/
+static int fuzzerLoadRules(
+ sqlite3 *db, /* Database handle */
+ fuzzer_vtab *p, /* Virtual fuzzer table to configure */
+ const char *zDb, /* Database containing rules data */
+ const char *zData, /* Table containing rules data */
+ char **pzErr /* OUT: Error message */
+){
+ int rc = SQLITE_OK; /* Return code */
+ char *zSql; /* SELECT used to read from rules table */
+ fuzzer_rule *pHead = 0;
+
+ zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", zDb, zData);
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ int rc2; /* finalize() return code */
+ sqlite3_stmt *pStmt = 0;
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+ if( rc!=SQLITE_OK ){
+ *pzErr = sqlite3_mprintf("%s: %s", p->zClassName, sqlite3_errmsg(db));
+ }else if( sqlite3_column_count(pStmt)!=4 ){
+ *pzErr = sqlite3_mprintf("%s: %s has %d columns, expected 4",
+ p->zClassName, zData, sqlite3_column_count(pStmt)
+ );
+ rc = SQLITE_ERROR;
+ }else{
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ fuzzer_rule *pRule = 0;
+ rc = fuzzerLoadOneRule(p, pStmt, &pRule, pzErr);
+ if( pRule ){
+ pRule->pNext = pHead;
+ pHead = pRule;
+ }
+ }
+ }
+ rc2 = sqlite3_finalize(pStmt);
+ if( rc==SQLITE_OK ) rc = rc2;
+ }
+ sqlite3_free(zSql);
+
+ /* All rules are now in a singly linked list starting at pHead. This
+ ** block sorts them by cost and then sets fuzzer_vtab.pRule to point to
+ ** point to the head of the sorted list.
+ */
+ if( rc==SQLITE_OK ){
+ unsigned int i;
+ fuzzer_rule *pX;
+ fuzzer_rule *a[15];
+ for(i=0; i<sizeof(a)/sizeof(a[0]); i++) a[i] = 0;
+ while( (pX = pHead)!=0 ){
+ pHead = pX->pNext;
+ pX->pNext = 0;
+ for(i=0; a[i] && i<sizeof(a)/sizeof(a[0])-1; i++){
+ pX = fuzzerMergeRules(a[i], pX);
+ a[i] = 0;
+ }
+ a[i] = fuzzerMergeRules(a[i], pX);
+ }
+ for(pX=a[0], i=1; i<sizeof(a)/sizeof(a[0]); i++){
+ pX = fuzzerMergeRules(a[i], pX);
+ }
+ p->pRule = fuzzerMergeRules(p->pRule, pX);
+ }else{
+ /* An error has occurred. Setting p->pRule to point to the head of the
+ ** allocated list ensures that the list will be cleaned up in this case.
+ */
+ assert( p->pRule==0 );
+ p->pRule = pHead;
+ }
+
+ return rc;
+}
+
+/*
+** This function converts an SQL quoted string into an unquoted string
+** and returns a pointer to a buffer allocated using sqlite3_malloc()
+** containing the result. The caller should eventually free this buffer
+** using sqlite3_free.
+**
+** Examples:
+**
+** "abc" becomes abc
+** 'xyz' becomes xyz
+** [pqr] becomes pqr
+** `mno` becomes mno
+*/
+static char *fuzzerDequote(const char *zIn){
+ size_t nIn; /* Size of input string, in bytes */
+ char *zOut; /* Output (dequoted) string */
+
+ nIn = strlen(zIn);
+ zOut = sqlite3_malloc(nIn+1);
+ if( zOut ){
+ char q = zIn[0]; /* Quote character (if any ) */
+
+ if( q!='[' && q!= '\'' && q!='"' && q!='`' ){
+ memcpy(zOut, zIn, (size_t)(nIn+1));
+ }else{
+ size_t iOut = 0; /* Index of next byte to write to output */
+ size_t iIn; /* Index of next byte to read from input */
+
+ if( q=='[' ) q = ']';
+ for(iIn=1; iIn<nIn; iIn++){
+ if( zIn[iIn]==q ) iIn++;
+ zOut[iOut++] = zIn[iIn];
+ }
+ }
+ assert( strlen(zOut)<=nIn );
+ }
+ return zOut;
+}
+
+/*
+** xDisconnect/xDestroy method for the fuzzer module.
+*/
+static int fuzzerDisconnect(sqlite3_vtab *pVtab){
+ fuzzer_vtab *p = (fuzzer_vtab*)pVtab;
+ assert( p->nCursor==0 );
+ while( p->pRule ){
+ fuzzer_rule *pRule = p->pRule;
+ p->pRule = pRule->pNext;
+ sqlite3_free(pRule);
+ }
+ sqlite3_free(p);
+ return SQLITE_OK;
+}
+
+/*
+** xConnect/xCreate method for the fuzzer module. Arguments are:
+**
+** argv[0] -> module name ("fuzzer")
+** argv[1] -> database name
+** argv[2] -> table name
+** argv[3] -> fuzzer rule table name
+*/
+static int fuzzerConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ int rc = SQLITE_OK; /* Return code */
+ fuzzer_vtab *pNew = 0; /* New virtual table */
+ const char *zModule = argv[0];
+ const char *zDb = argv[1];
+
+ if( argc!=4 ){
+ *pzErr = sqlite3_mprintf(
+ "%s: wrong number of CREATE VIRTUAL TABLE arguments", zModule
+ );
+ rc = SQLITE_ERROR;
+ }else{
+ size_t nModule; /* Length of zModule, in bytes */
+
+ nModule = strlen(zModule);
+ pNew = sqlite3_malloc( sizeof(*pNew) + nModule + 1);
+ if( pNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ char *zTab; /* Dequoted name of fuzzer data table */
+
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->zClassName = (char*)&pNew[1];
+ memcpy(pNew->zClassName, zModule, (size_t)(nModule+1));
+
+ zTab = fuzzerDequote(argv[3]);
+ if( zTab==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = fuzzerLoadRules(db, pNew, zDb, zTab, pzErr);
+ sqlite3_free(zTab);
+ }
+
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_declare_vtab(db, "CREATE TABLE x(word,distance,ruleset)");
+ }
+ if( rc!=SQLITE_OK ){
+ fuzzerDisconnect((sqlite3_vtab *)pNew);
+ pNew = 0;
+ }
+ }
+ }
+
+ *ppVtab = (sqlite3_vtab *)pNew;
+ return rc;
+}
+
+/*
+** Open a new fuzzer cursor.
+*/
+static int fuzzerOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+ fuzzer_vtab *p = (fuzzer_vtab*)pVTab;
+ fuzzer_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ pCur->pVtab = p;
+ *ppCursor = &pCur->base;
+ p->nCursor++;
+ return SQLITE_OK;
+}
+
+/*
+** Free all stems in a list.
+*/
+static void fuzzerClearStemList(fuzzer_stem *pStem){
+ while( pStem ){
+ fuzzer_stem *pNext = pStem->pNext;
+ sqlite3_free(pStem);
+ pStem = pNext;
+ }
+}
+
+/*
+** Free up all the memory allocated by a cursor. Set it rLimit to 0
+** to indicate that it is at EOF.
+*/
+static void fuzzerClearCursor(fuzzer_cursor *pCur, int clearHash){
+ int i;
+ fuzzerClearStemList(pCur->pStem);
+ fuzzerClearStemList(pCur->pDone);
+ for(i=0; i<FUZZER_NQUEUE; i++) fuzzerClearStemList(pCur->aQueue[i]);
+ pCur->rLimit = (fuzzer_cost)0;
+ if( clearHash && pCur->nStem ){
+ pCur->mxQueue = 0;
+ pCur->pStem = 0;
+ pCur->pDone = 0;
+ memset(pCur->aQueue, 0, sizeof(pCur->aQueue));
+ memset(pCur->apHash, 0, sizeof(pCur->apHash));
+ }
+ pCur->nStem = 0;
+}
+
+/*
+** Close a fuzzer cursor.
+*/
+static int fuzzerClose(sqlite3_vtab_cursor *cur){
+ fuzzer_cursor *pCur = (fuzzer_cursor *)cur;
+ fuzzerClearCursor(pCur, 0);
+ sqlite3_free(pCur->zBuf);
+ pCur->pVtab->nCursor--;
+ sqlite3_free(pCur);
+ return SQLITE_OK;
+}
+
+/*
+** Compute the current output term for a fuzzer_stem.
+*/
+static int fuzzerRender(
+ fuzzer_stem *pStem, /* The stem to be rendered */
+ char **pzBuf, /* Write results into this buffer. realloc if needed */
+ int *pnBuf /* Size of the buffer */
+){
+ const fuzzer_rule *pRule = pStem->pRule;
+ int n; /* Size of output term without nul-term */
+ char *z; /* Buffer to assemble output term in */
+
+ n = pStem->nBasis + pRule->nTo - pRule->nFrom;
+ if( (*pnBuf)<n+1 ){
+ (*pzBuf) = sqlite3_realloc((*pzBuf), n+100);
+ if( (*pzBuf)==0 ) return SQLITE_NOMEM;
+ (*pnBuf) = n+100;
+ }
+ n = pStem->n;
+ z = *pzBuf;
+ if( n<0 ){
+ memcpy(z, pStem->zBasis, pStem->nBasis+1);
+ }else{
+ memcpy(z, pStem->zBasis, n);
+ memcpy(&z[n], pRule->zTo, pRule->nTo);
+ memcpy(&z[n+pRule->nTo], &pStem->zBasis[n+pRule->nFrom],
+ pStem->nBasis-n-pRule->nFrom+1);
+ }
+
+ assert( z[pStem->nBasis + pRule->nTo - pRule->nFrom]==0 );
+ return SQLITE_OK;
+}
+
+/*
+** Compute a hash on zBasis.
+*/
+static unsigned int fuzzerHash(const char *z){
+ unsigned int h = 0;
+ while( *z ){ h = (h<<3) ^ (h>>29) ^ *(z++); }
+ return h % FUZZER_HASH;
+}
+
+/*
+** Current cost of a stem
+*/
+static fuzzer_cost fuzzerCost(fuzzer_stem *pStem){
+ return pStem->rCostX = pStem->rBaseCost + pStem->pRule->rCost;
+}
+
+#if 0
+/*
+** Print a description of a fuzzer_stem on stderr.
+*/
+static void fuzzerStemPrint(
+ const char *zPrefix,
+ fuzzer_stem *pStem,
+ const char *zSuffix
+){
+ if( pStem->n<0 ){
+ fprintf(stderr, "%s[%s](%d)-->self%s",
+ zPrefix,
+ pStem->zBasis, pStem->rBaseCost,
+ zSuffix
+ );
+ }else{
+ char *zBuf = 0;
+ int nBuf = 0;
+ if( fuzzerRender(pStem, &zBuf, &nBuf)!=SQLITE_OK ) return;
+ fprintf(stderr, "%s[%s](%d)-->{%s}(%d)%s",
+ zPrefix,
+ pStem->zBasis, pStem->rBaseCost, zBuf, pStem->,
+ zSuffix
+ );
+ sqlite3_free(zBuf);
+ }
+}
+#endif
+
+/*
+** Return 1 if the string to which the cursor is point has already
+** been emitted. Return 0 if not. Return -1 on a memory allocation
+** failures.
+*/
+static int fuzzerSeen(fuzzer_cursor *pCur, fuzzer_stem *pStem){
+ unsigned int h;
+ fuzzer_stem *pLookup;
+
+ if( fuzzerRender(pStem, &pCur->zBuf, &pCur->nBuf)==SQLITE_NOMEM ){
+ return -1;
+ }
+ h = fuzzerHash(pCur->zBuf);
+ pLookup = pCur->apHash[h];
+ while( pLookup && strcmp(pLookup->zBasis, pCur->zBuf)!=0 ){
+ pLookup = pLookup->pHash;
+ }
+ return pLookup!=0;
+}
+
+/*
+** If argument pRule is NULL, this function returns false.
+**
+** Otherwise, it returns true if rule pRule should be skipped. A rule
+** should be skipped if it does not belong to rule-set iRuleset, or if
+** applying it to stem pStem would create a string longer than
+** FUZZER_MX_OUTPUT_LENGTH bytes.
+*/
+static int fuzzerSkipRule(
+ const fuzzer_rule *pRule, /* Determine whether or not to skip this */
+ fuzzer_stem *pStem, /* Stem rule may be applied to */
+ int iRuleset /* Rule-set used by the current query */
+){
+ return pRule && (
+ (pRule->iRuleset!=iRuleset)
+ || (pStem->nBasis + pRule->nTo - pRule->nFrom)>FUZZER_MX_OUTPUT_LENGTH
+ );
+}
+
+/*
+** Advance a fuzzer_stem to its next value. Return 0 if there are
+** no more values that can be generated by this fuzzer_stem. Return
+** -1 on a memory allocation failure.
+*/
+static int fuzzerAdvance(fuzzer_cursor *pCur, fuzzer_stem *pStem){
+ const fuzzer_rule *pRule;
+ while( (pRule = pStem->pRule)!=0 ){
+ assert( pRule==&pCur->nullRule || pRule->iRuleset==pCur->iRuleset );
+ while( pStem->n < pStem->nBasis - pRule->nFrom ){
+ pStem->n++;
+ if( pRule->nFrom==0
+ || memcmp(&pStem->zBasis[pStem->n], pRule->zFrom, pRule->nFrom)==0
+ ){
+ /* Found a rewrite case. Make sure it is not a duplicate */
+ int rc = fuzzerSeen(pCur, pStem);
+ if( rc<0 ) return -1;
+ if( rc==0 ){
+ fuzzerCost(pStem);
+ return 1;
+ }
+ }
+ }
+ pStem->n = -1;
+ do{
+ pRule = pRule->pNext;
+ }while( fuzzerSkipRule(pRule, pStem, pCur->iRuleset) );
+ pStem->pRule = pRule;
+ if( pRule && fuzzerCost(pStem)>pCur->rLimit ) pStem->pRule = 0;
+ }
+ return 0;
+}
+
+/*
+** The two input stem lists are both sorted in order of increasing
+** rCostX. Merge them together into a single list, sorted by rCostX, and
+** return a pointer to the head of that new list.
+*/
+static fuzzer_stem *fuzzerMergeStems(fuzzer_stem *pA, fuzzer_stem *pB){
+ fuzzer_stem head;
+ fuzzer_stem *pTail;
+
+ pTail = &head;
+ while( pA && pB ){
+ if( pA->rCostX<=pB->rCostX ){
+ pTail->pNext = pA;
+ pTail = pA;
+ pA = pA->pNext;
+ }else{
+ pTail->pNext = pB;
+ pTail = pB;
+ pB = pB->pNext;
+ }
+ }
+ if( pA==0 ){
+ pTail->pNext = pB;
+ }else{
+ pTail->pNext = pA;
+ }
+ return head.pNext;
+}
+
+/*
+** Load pCur->pStem with the lowest-cost stem. Return a pointer
+** to the lowest-cost stem.
+*/
+static fuzzer_stem *fuzzerLowestCostStem(fuzzer_cursor *pCur){
+ fuzzer_stem *pBest, *pX;
+ int iBest;
+ int i;
+
+ if( pCur->pStem==0 ){
+ iBest = -1;
+ pBest = 0;
+ for(i=0; i<=pCur->mxQueue; i++){
+ pX = pCur->aQueue[i];
+ if( pX==0 ) continue;
+ if( pBest==0 || pBest->rCostX>pX->rCostX ){
+ pBest = pX;
+ iBest = i;
+ }
+ }
+ if( pBest ){
+ pCur->aQueue[iBest] = pBest->pNext;
+ pBest->pNext = 0;
+ pCur->pStem = pBest;
+ }
+ }
+ return pCur->pStem;
+}
+
+/*
+** Insert pNew into queue of pending stems. Then find the stem
+** with the lowest rCostX and move it into pCur->pStem.
+** list. The insert is done such the pNew is in the correct order
+** according to fuzzer_stem.zBaseCost+fuzzer_stem.pRule->rCost.
+*/
+static fuzzer_stem *fuzzerInsert(fuzzer_cursor *pCur, fuzzer_stem *pNew){
+ fuzzer_stem *pX;
+ int i;
+
+ /* If pCur->pStem exists and is greater than pNew, then make pNew
+ ** the new pCur->pStem and insert the old pCur->pStem instead.
+ */
+ if( (pX = pCur->pStem)!=0 && pX->rCostX>pNew->rCostX ){
+ pNew->pNext = 0;
+ pCur->pStem = pNew;
+ pNew = pX;
+ }
+
+ /* Insert the new value */
+ pNew->pNext = 0;
+ pX = pNew;
+ for(i=0; i<=pCur->mxQueue; i++){
+ if( pCur->aQueue[i] ){
+ pX = fuzzerMergeStems(pX, pCur->aQueue[i]);
+ pCur->aQueue[i] = 0;
+ }else{
+ pCur->aQueue[i] = pX;
+ break;
+ }
+ }
+ if( i>pCur->mxQueue ){
+ if( i<FUZZER_NQUEUE ){
+ pCur->mxQueue = i;
+ pCur->aQueue[i] = pX;
+ }else{
+ assert( pCur->mxQueue==FUZZER_NQUEUE-1 );
+ pX = fuzzerMergeStems(pX, pCur->aQueue[FUZZER_NQUEUE-1]);
+ pCur->aQueue[FUZZER_NQUEUE-1] = pX;
+ }
+ }
+
+ return fuzzerLowestCostStem(pCur);
+}
+
+/*
+** Allocate a new fuzzer_stem. Add it to the hash table but do not
+** link it into either the pCur->pStem or pCur->pDone lists.
+*/
+static fuzzer_stem *fuzzerNewStem(
+ fuzzer_cursor *pCur,
+ const char *zWord,
+ fuzzer_cost rBaseCost
+){
+ fuzzer_stem *pNew;
+ fuzzer_rule *pRule;
+ unsigned int h;
+
+ pNew = sqlite3_malloc( sizeof(*pNew) + strlen(zWord) + 1 );
+ if( pNew==0 ) return 0;
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->zBasis = (char*)&pNew[1];
+ pNew->nBasis = (fuzzer_len)strlen(zWord);
+ memcpy(pNew->zBasis, zWord, pNew->nBasis+1);
+ pRule = pCur->pVtab->pRule;
+ while( fuzzerSkipRule(pRule, pNew, pCur->iRuleset) ){
+ pRule = pRule->pNext;
+ }
+ pNew->pRule = pRule;
+ pNew->n = -1;
+ pNew->rBaseCost = pNew->rCostX = rBaseCost;
+ h = fuzzerHash(pNew->zBasis);
+ pNew->pHash = pCur->apHash[h];
+ pCur->apHash[h] = pNew;
+ pCur->nStem++;
+ return pNew;
+}
+
+
+/*
+** Advance a cursor to its next row of output
+*/
+static int fuzzerNext(sqlite3_vtab_cursor *cur){
+ fuzzer_cursor *pCur = (fuzzer_cursor*)cur;
+ int rc;
+ fuzzer_stem *pStem, *pNew;
+
+ pCur->iRowid++;
+
+ /* Use the element the cursor is currently point to to create
+ ** a new stem and insert the new stem into the priority queue.
+ */
+ pStem = pCur->pStem;
+ if( pStem->rCostX>0 ){
+ rc = fuzzerRender(pStem, &pCur->zBuf, &pCur->nBuf);
+ if( rc==SQLITE_NOMEM ) return SQLITE_NOMEM;
+ pNew = fuzzerNewStem(pCur, pCur->zBuf, pStem->rCostX);
+ if( pNew ){
+ if( fuzzerAdvance(pCur, pNew)==0 ){
+ pNew->pNext = pCur->pDone;
+ pCur->pDone = pNew;
+ }else{
+ if( fuzzerInsert(pCur, pNew)==pNew ){
+ return SQLITE_OK;
+ }
+ }
+ }else{
+ return SQLITE_NOMEM;
+ }
+ }
+
+ /* Adjust the priority queue so that the first element of the
+ ** stem list is the next lowest cost word.
+ */
+ while( (pStem = pCur->pStem)!=0 ){
+ int res = fuzzerAdvance(pCur, pStem);
+ if( res<0 ){
+ return SQLITE_NOMEM;
+ }else if( res>0 ){
+ pCur->pStem = 0;
+ pStem = fuzzerInsert(pCur, pStem);
+ if( (rc = fuzzerSeen(pCur, pStem))!=0 ){
+ if( rc<0 ) return SQLITE_NOMEM;
+ continue;
+ }
+ return SQLITE_OK; /* New word found */
+ }
+ pCur->pStem = 0;
+ pStem->pNext = pCur->pDone;
+ pCur->pDone = pStem;
+ if( fuzzerLowestCostStem(pCur) ){
+ rc = fuzzerSeen(pCur, pCur->pStem);
+ if( rc<0 ) return SQLITE_NOMEM;
+ if( rc==0 ){
+ return SQLITE_OK;
+ }
+ }
+ }
+
+ /* Reach this point only if queue has been exhausted and there is
+ ** nothing left to be output. */
+ pCur->rLimit = (fuzzer_cost)0;
+ return SQLITE_OK;
+}
+
+/*
+** Called to "rewind" a cursor back to the beginning so that
+** it starts its output over again. Always called at least once
+** prior to any fuzzerColumn, fuzzerRowid, or fuzzerEof call.
+*/
+static int fuzzerFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ fuzzer_cursor *pCur = (fuzzer_cursor *)pVtabCursor;
+ const char *zWord = "";
+ fuzzer_stem *pStem;
+ int idx;
+
+ fuzzerClearCursor(pCur, 1);
+ pCur->rLimit = 2147483647;
+ idx = 0;
+ if( idxNum & 1 ){
+ zWord = (const char*)sqlite3_value_text(argv[0]);
+ idx++;
+ }
+ if( idxNum & 2 ){
+ pCur->rLimit = (fuzzer_cost)sqlite3_value_int(argv[idx]);
+ idx++;
+ }
+ if( idxNum & 4 ){
+ pCur->iRuleset = (fuzzer_cost)sqlite3_value_int(argv[idx]);
+ idx++;
+ }
+ pCur->nullRule.pNext = pCur->pVtab->pRule;
+ pCur->nullRule.rCost = 0;
+ pCur->nullRule.nFrom = 0;
+ pCur->nullRule.nTo = 0;
+ pCur->nullRule.zFrom = "";
+ pCur->iRowid = 1;
+ assert( pCur->pStem==0 );
+
+ /* If the query term is longer than FUZZER_MX_OUTPUT_LENGTH bytes, this
+ ** query will return zero rows. */
+ if( (int)strlen(zWord)<FUZZER_MX_OUTPUT_LENGTH ){
+ pCur->pStem = pStem = fuzzerNewStem(pCur, zWord, (fuzzer_cost)0);
+ if( pStem==0 ) return SQLITE_NOMEM;
+ pStem->pRule = &pCur->nullRule;
+ pStem->n = pStem->nBasis;
+ }else{
+ pCur->rLimit = 0;
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Only the word and distance columns have values. All other columns
+** return NULL
+*/
+static int fuzzerColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
+ fuzzer_cursor *pCur = (fuzzer_cursor*)cur;
+ if( i==0 ){
+ /* the "word" column */
+ if( fuzzerRender(pCur->pStem, &pCur->zBuf, &pCur->nBuf)==SQLITE_NOMEM ){
+ return SQLITE_NOMEM;
+ }
+ sqlite3_result_text(ctx, pCur->zBuf, -1, SQLITE_TRANSIENT);
+ }else if( i==1 ){
+ /* the "distance" column */
+ sqlite3_result_int(ctx, pCur->pStem->rCostX);
+ }else{
+ /* All other columns are NULL */
+ sqlite3_result_null(ctx);
+ }
+ return SQLITE_OK;
+}
+
+/*
+** The rowid.
+*/
+static int fuzzerRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ fuzzer_cursor *pCur = (fuzzer_cursor*)cur;
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** When the fuzzer_cursor.rLimit value is 0 or less, that is a signal
+** that the cursor has nothing more to output.
+*/
+static int fuzzerEof(sqlite3_vtab_cursor *cur){
+ fuzzer_cursor *pCur = (fuzzer_cursor*)cur;
+ return pCur->rLimit<=(fuzzer_cost)0;
+}
+
+/*
+** Search for terms of these forms:
+**
+** (A) word MATCH $str
+** (B1) distance < $value
+** (B2) distance <= $value
+** (C) ruleid == $ruleid
+**
+** The distance< and distance<= are both treated as distance<=.
+** The query plan number is a bit vector:
+**
+** bit 1: Term of the form (A) found
+** bit 2: Term like (B1) or (B2) found
+** bit 3: Term like (C) found
+**
+** If bit-1 is set, $str is always in filter.argv[0]. If bit-2 is set
+** then $value is in filter.argv[0] if bit-1 is clear and is in
+** filter.argv[1] if bit-1 is set. If bit-3 is set, then $ruleid is
+** in filter.argv[0] if bit-1 and bit-2 are both zero, is in
+** filter.argv[1] if exactly one of bit-1 and bit-2 are set, and is in
+** filter.argv[2] if both bit-1 and bit-2 are set.
+*/
+static int fuzzerBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+ int iPlan = 0;
+ int iDistTerm = -1;
+ int iRulesetTerm = -1;
+ int i;
+ int seenMatch = 0;
+ const struct sqlite3_index_constraint *pConstraint;
+ double rCost = 1e12;
+
+ pConstraint = pIdxInfo->aConstraint;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
+ if( pConstraint->iColumn==0
+ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH ){
+ seenMatch = 1;
+ }
+ if( pConstraint->usable==0 ) continue;
+ if( (iPlan & 1)==0
+ && pConstraint->iColumn==0
+ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH
+ ){
+ iPlan |= 1;
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ rCost /= 1e6;
+ }
+ if( (iPlan & 2)==0
+ && pConstraint->iColumn==1
+ && (pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT
+ || pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE)
+ ){
+ iPlan |= 2;
+ iDistTerm = i;
+ rCost /= 10.0;
+ }
+ if( (iPlan & 4)==0
+ && pConstraint->iColumn==2
+ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
+ ){
+ iPlan |= 4;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ iRulesetTerm = i;
+ rCost /= 10.0;
+ }
+ }
+ if( iPlan & 2 ){
+ pIdxInfo->aConstraintUsage[iDistTerm].argvIndex = 1+((iPlan&1)!=0);
+ }
+ if( iPlan & 4 ){
+ int idx = 1;
+ if( iPlan & 1 ) idx++;
+ if( iPlan & 2 ) idx++;
+ pIdxInfo->aConstraintUsage[iRulesetTerm].argvIndex = idx;
+ }
+ pIdxInfo->idxNum = iPlan;
+ if( pIdxInfo->nOrderBy==1
+ && pIdxInfo->aOrderBy[0].iColumn==1
+ && pIdxInfo->aOrderBy[0].desc==0
+ ){
+ pIdxInfo->orderByConsumed = 1;
+ }
+ if( seenMatch && (iPlan&1)==0 ) rCost = 1e99;
+ pIdxInfo->estimatedCost = rCost;
+
+ return SQLITE_OK;
+}
+
+/*
+** A virtual table module that implements the "fuzzer".
+*/
+static const sqlite3_module fuzzerModule = {
+ 0, /* iVersion */
+ fuzzerConnect,
+ fuzzerConnect,
+ fuzzerBestIndex,
+ fuzzerDisconnect,
+ fuzzerDisconnect,
+ fuzzerOpen, /* xOpen - open a cursor */
+ fuzzerClose, /* xClose - close a cursor */
+ fuzzerFilter, /* xFilter - configure scan constraints */
+ fuzzerNext, /* xNext - advance a cursor */
+ fuzzerEof, /* xEof - check for end of scan */
+ fuzzerColumn, /* xColumn - read data */
+ fuzzerRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+};
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_fuzzer_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3_create_module(db, "fuzzer", &fuzzerModule, 0);
+#endif
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3_create_module(db, "fuzzer", &fuzzerModule, 0);
+#endif
+ return rc;
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/icu.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/icu.c 2019-03-05 13:14:40.593000000 +0100
@@ -0,0 +1,563 @@
+/*
+** 2007 May 6
+**
+** 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.
+**
+*************************************************************************
+** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $
+**
+** This file implements an integration between the ICU library
+** ("International Components for Unicode", an open-source library
+** for handling unicode data) and SQLite. The integration uses
+** ICU to provide the following to SQLite:
+**
+** * An implementation of the SQL regexp() function (and hence REGEXP
+** operator) using the ICU uregex_XX() APIs.
+**
+** * Implementations of the SQL scalar upper() and lower() functions
+** for case mapping.
+**
+** * Integration of ICU and SQLite collation sequences.
+**
+** * An implementation of the LIKE operator that uses ICU to
+** provide case-independent matching.
+*/
+
+#if !defined(SQLITE_CORE) \
+ || defined(SQLITE_ENABLE_ICU) \
+ || defined(SQLITE_ENABLE_ICU_COLLATIONS)
+
+/* Include ICU headers */
+#include <unicode/utypes.h>
+#include <unicode/uregex.h>
+#include <unicode/ustring.h>
+#include <unicode/ucol.h>
+
+#include <assert.h>
+
+#ifndef SQLITE_CORE
+ #include "sqlite3ext.h"
+ SQLITE_EXTENSION_INIT1
+#else
+ #include "sqlite3.h"
+#endif
+
+/*
+** This function is called when an ICU function called from within
+** the implementation of an SQL scalar function returns an error.
+**
+** The scalar function context passed as the first argument is
+** loaded with an error message based on the following two args.
+*/
+static void icuFunctionError(
+ sqlite3_context *pCtx, /* SQLite scalar function context */
+ const char *zName, /* Name of ICU function that failed */
+ UErrorCode e /* Error code returned by ICU function */
+){
+ char zBuf[128];
+ sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e));
+ zBuf[127] = '\0';
+ sqlite3_result_error(pCtx, zBuf, -1);
+}
+
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
+
+/*
+** Maximum length (in bytes) of the pattern in a LIKE or GLOB
+** operator.
+*/
+#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH
+# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000
+#endif
+
+/*
+** Version of sqlite3_free() that is always a function, never a macro.
+*/
+static void xFree(void *p){
+ sqlite3_free(p);
+}
+
+/*
+** This lookup table is used to help decode the first byte of
+** a multi-byte UTF8 character. It is copied here from SQLite source
+** code file utf8.c.
+*/
+static const unsigned char icuUtf8Trans1[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
+};
+
+#define SQLITE_ICU_READ_UTF8(zIn, c) \
+ c = *(zIn++); \
+ if( c>=0xc0 ){ \
+ c = icuUtf8Trans1[c-0xc0]; \
+ while( (*zIn & 0xc0)==0x80 ){ \
+ c = (c<<6) + (0x3f & *(zIn++)); \
+ } \
+ }
+
+#define SQLITE_ICU_SKIP_UTF8(zIn) \
+ assert( *zIn ); \
+ if( *(zIn++)>=0xc0 ){ \
+ while( (*zIn & 0xc0)==0x80 ){zIn++;} \
+ }
+
+
+/*
+** Compare two UTF-8 strings for equality where the first string is
+** a "LIKE" expression. Return true (1) if they are the same and
+** false (0) if they are different.
+*/
+static int icuLikeCompare(
+ const uint8_t *zPattern, /* LIKE pattern */
+ const uint8_t *zString, /* The UTF-8 string to compare against */
+ const UChar32 uEsc /* The escape character */
+){
+ static const uint32_t MATCH_ONE = (uint32_t)'_';
+ static const uint32_t MATCH_ALL = (uint32_t)'%';
+
+ int prevEscape = 0; /* True if the previous character was uEsc */
+
+ while( 1 ){
+
+ /* Read (and consume) the next character from the input pattern. */
+ uint32_t uPattern;
+ SQLITE_ICU_READ_UTF8(zPattern, uPattern);
+ if( uPattern==0 ) break;
+
+ /* There are now 4 possibilities:
+ **
+ ** 1. uPattern is an unescaped match-all character "%",
+ ** 2. uPattern is an unescaped match-one character "_",
+ ** 3. uPattern is an unescaped escape character, or
+ ** 4. uPattern is to be handled as an ordinary character
+ */
+ if( !prevEscape && uPattern==MATCH_ALL ){
+ /* Case 1. */
+ uint8_t c;
+
+ /* Skip any MATCH_ALL or MATCH_ONE characters that follow a
+ ** MATCH_ALL. For each MATCH_ONE, skip one character in the
+ ** test string.
+ */
+ while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){
+ if( c==MATCH_ONE ){
+ if( *zString==0 ) return 0;
+ SQLITE_ICU_SKIP_UTF8(zString);
+ }
+ zPattern++;
+ }
+
+ if( *zPattern==0 ) return 1;
+
+ while( *zString ){
+ if( icuLikeCompare(zPattern, zString, uEsc) ){
+ return 1;
+ }
+ SQLITE_ICU_SKIP_UTF8(zString);
+ }
+ return 0;
+
+ }else if( !prevEscape && uPattern==MATCH_ONE ){
+ /* Case 2. */
+ if( *zString==0 ) return 0;
+ SQLITE_ICU_SKIP_UTF8(zString);
+
+ }else if( !prevEscape && uPattern==(uint32_t)uEsc){
+ /* Case 3. */
+ prevEscape = 1;
+
+ }else{
+ /* Case 4. */
+ uint32_t uString;
+ SQLITE_ICU_READ_UTF8(zString, uString);
+ uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT);
+ uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT);
+ if( uString!=uPattern ){
+ return 0;
+ }
+ prevEscape = 0;
+ }
+ }
+
+ return *zString==0;
+}
+
+/*
+** Implementation of the like() SQL function. This function implements
+** the build-in LIKE operator. The first argument to the function is the
+** pattern and the second argument is the string. So, the SQL statements:
+**
+** A LIKE B
+**
+** is implemented as like(B, A). If there is an escape character E,
+**
+** A LIKE B ESCAPE E
+**
+** is mapped to like(B, A, E).
+*/
+static void icuLikeFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const unsigned char *zA = sqlite3_value_text(argv[0]);
+ const unsigned char *zB = sqlite3_value_text(argv[1]);
+ UChar32 uEsc = 0;
+
+ /* Limit the length of the LIKE or GLOB pattern to avoid problems
+ ** of deep recursion and N*N behavior in patternCompare().
+ */
+ if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){
+ sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1);
+ return;
+ }
+
+
+ if( argc==3 ){
+ /* The escape character string must consist of a single UTF-8 character.
+ ** Otherwise, return an error.
+ */
+ size_t nE= sqlite3_value_bytes(argv[2]);
+ const unsigned char *zE = sqlite3_value_text(argv[2]);
+ int i = 0;
+ if( zE==0 ) return;
+ U8_NEXT(zE, i, nE, uEsc);
+ if( i!=nE){
+ sqlite3_result_error(context,
+ "ESCAPE expression must be a single character", -1);
+ return;
+ }
+ }
+
+ if( zA && zB ){
+ sqlite3_result_int(context, icuLikeCompare(zA, zB, uEsc));
+ }
+}
+
+/*
+** Function to delete compiled regexp objects. Registered as
+** a destructor function with sqlite3_set_auxdata().
+*/
+static void icuRegexpDelete(void *p){
+ URegularExpression *pExpr = (URegularExpression *)p;
+ uregex_close(pExpr);
+}
+
+/*
+** Implementation of SQLite REGEXP operator. This scalar function takes
+** two arguments. The first is a regular expression pattern to compile
+** the second is a string to match against that pattern. If either
+** argument is an SQL NULL, then NULL Is returned. Otherwise, the result
+** is 1 if the string matches the pattern, or 0 otherwise.
+**
+** SQLite maps the regexp() function to the regexp() operator such
+** that the following two are equivalent:
+**
+** zString REGEXP zPattern
+** regexp(zPattern, zString)
+**
+** Uses the following ICU regexp APIs:
+**
+** uregex_open()
+** uregex_matches()
+** uregex_close()
+*/
+static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
+ UErrorCode status = U_ZERO_ERROR;
+ URegularExpression *pExpr;
+ UBool res;
+ const UChar *zString = sqlite3_value_text16(apArg[1]);
+
+ (void)nArg; /* Unused parameter */
+
+ /* If the left hand side of the regexp operator is NULL,
+ ** then the result is also NULL.
+ */
+ if( !zString ){
+ return;
+ }
+
+ pExpr = sqlite3_get_auxdata(p, 0);
+ if( !pExpr ){
+ const UChar *zPattern = sqlite3_value_text16(apArg[0]);
+ if( !zPattern ){
+ return;
+ }
+ pExpr = uregex_open(zPattern, -1, 0, 0, &status);
+
+ if( U_SUCCESS(status) ){
+ sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete);
+ }else{
+ assert(!pExpr);
+ icuFunctionError(p, "uregex_open", status);
+ return;
+ }
+ }
+
+ /* Configure the text that the regular expression operates on. */
+ uregex_setText(pExpr, zString, -1, &status);
+ if( !U_SUCCESS(status) ){
+ icuFunctionError(p, "uregex_setText", status);
+ return;
+ }
+
+ /* Attempt the match */
+ res = uregex_matches(pExpr, 0, &status);
+ if( !U_SUCCESS(status) ){
+ icuFunctionError(p, "uregex_matches", status);
+ return;
+ }
+
+ /* Set the text that the regular expression operates on to a NULL
+ ** pointer. This is not really necessary, but it is tidier than
+ ** leaving the regular expression object configured with an invalid
+ ** pointer after this function returns.
+ */
+ uregex_setText(pExpr, 0, 0, &status);
+
+ /* Return 1 or 0. */
+ sqlite3_result_int(p, res ? 1 : 0);
+}
+
+/*
+** Implementations of scalar functions for case mapping - upper() and
+** lower(). Function upper() converts its input to upper-case (ABC).
+** Function lower() converts to lower-case (abc).
+**
+** ICU provides two types of case mapping, "general" case mapping and
+** "language specific". Refer to ICU documentation for the differences
+** between the two.
+**
+** To utilise "general" case mapping, the upper() or lower() scalar
+** functions are invoked with one argument:
+**
+** upper('ABC') -> 'abc'
+** lower('abc') -> 'ABC'
+**
+** To access ICU "language specific" case mapping, upper() or lower()
+** should be invoked with two arguments. The second argument is the name
+** of the locale to use. Passing an empty string ("") or SQL NULL value
+** as the second argument is the same as invoking the 1 argument version
+** of upper() or lower().
+**
+** lower('I', 'en_us') -> 'i'
+** lower('I', 'tr_tr') -> '\u131' (small dotless i)
+**
+** http://www.icu-project.org/userguide/posix.html#case_mappings
+*/
+static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
+ const UChar *zInput; /* Pointer to input string */
+ UChar *zOutput = 0; /* Pointer to output buffer */
+ size_t nInput; /* Size of utf-16 input string in bytes */
+ size_t nOut; /* Size of output buffer in bytes */
+ int cnt;
+ int bToUpper; /* True for toupper(), false for tolower() */
+ UErrorCode status;
+ const char *zLocale = 0;
+
+ assert(nArg==1 || nArg==2);
+ bToUpper = (sqlite3_user_data(p)!=0);
+ if( nArg==2 ){
+ zLocale = (const char *)sqlite3_value_text(apArg[1]);
+ }
+
+ zInput = sqlite3_value_text16(apArg[0]);
+ if( !zInput ){
+ return;
+ }
+ nOut = nInput = sqlite3_value_bytes16(apArg[0]);
+ if( nOut==0 ){
+ sqlite3_result_text16(p, "", 0, SQLITE_STATIC);
+ return;
+ }
+
+ for(cnt=0; cnt<2; cnt++){
+ UChar *zNew = sqlite3_realloc(zOutput, nOut);
+ if( zNew==0 ){
+ sqlite3_free(zOutput);
+ sqlite3_result_error_nomem(p);
+ return;
+ }
+ zOutput = zNew;
+ status = U_ZERO_ERROR;
+ if( bToUpper ){
+ nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
+ }else{
+ nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
+ }
+
+ if( U_SUCCESS(status) ){
+ sqlite3_result_text16(p, zOutput, nOut, xFree);
+ }else if( status==U_BUFFER_OVERFLOW_ERROR ){
+ assert( cnt==0 );
+ continue;
+ }else{
+ icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status);
+ }
+ return;
+ }
+ assert( 0 ); /* Unreachable */
+}
+
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
+
+/*
+** Collation sequence destructor function. The pCtx argument points to
+** a UCollator structure previously allocated using ucol_open().
+*/
+static void icuCollationDel(void *pCtx){
+ UCollator *p = (UCollator *)pCtx;
+ ucol_close(p);
+}
+
+/*
+** Collation sequence comparison function. The pCtx argument points to
+** a UCollator structure previously allocated using ucol_open().
+*/
+static int icuCollationColl(
+ void *pCtx,
+ int nLeft,
+ const void *zLeft,
+ int nRight,
+ const void *zRight
+){
+ UCollationResult res;
+ UCollator *p = (UCollator *)pCtx;
+ res = ucol_strcoll(p, (UChar *)zLeft, nLeft/2, (UChar *)zRight, nRight/2);
+ switch( res ){
+ case UCOL_LESS: return -1;
+ case UCOL_GREATER: return +1;
+ case UCOL_EQUAL: return 0;
+ }
+ assert(!"Unexpected return value from ucol_strcoll()");
+ return 0;
+}
+
+/*
+** Implementation of the scalar function icu_load_collation().
+**
+** This scalar function is used to add ICU collation based collation
+** types to an SQLite database connection. It is intended to be called
+** as follows:
+**
+** SELECT icu_load_collation(<locale>, <collation-name>);
+**
+** Where <locale> is a string containing an ICU locale identifier (i.e.
+** "en_AU", "tr_TR" etc.) and <collation-name> is the name of the
+** collation sequence to create.
+*/
+static void icuLoadCollation(
+ sqlite3_context *p,
+ int nArg,
+ sqlite3_value **apArg
+){
+ sqlite3 *db = (sqlite3 *)sqlite3_user_data(p);
+ UErrorCode status = U_ZERO_ERROR;
+ const char *zLocale; /* Locale identifier - (eg. "jp_JP") */
+ const char *zName; /* SQL Collation sequence name (eg. "japanese") */
+ UCollator *pUCollator; /* ICU library collation object */
+ int rc; /* Return code from sqlite3_create_collation_x() */
+
+ assert(nArg==2);
+ (void)nArg; /* Unused parameter */
+ zLocale = (const char *)sqlite3_value_text(apArg[0]);
+ zName = (const char *)sqlite3_value_text(apArg[1]);
+
+ if( !zLocale || !zName ){
+ return;
+ }
+
+ pUCollator = ucol_open(zLocale, &status);
+ if( !U_SUCCESS(status) ){
+ icuFunctionError(p, "ucol_open", status);
+ return;
+ }
+ assert(p);
+
+ rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator,
+ icuCollationColl, icuCollationDel
+ );
+ if( rc!=SQLITE_OK ){
+ ucol_close(pUCollator);
+ sqlite3_result_error(p, "Error registering collation function", -1);
+ }
+}
+
+/*
+** Register the ICU extension functions with database db.
+*/
+int sqlite3IcuInit(sqlite3 *db){
+ static const struct IcuScalar {
+ const char *zName; /* Function name */
+ unsigned char nArg; /* Number of arguments */
+ unsigned short enc; /* Optimal text encoding */
+ unsigned char iContext; /* sqlite3_user_data() context */
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
+ } scalars[] = {
+ {"icu_load_collation", 2, SQLITE_UTF8, 1, icuLoadCollation},
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
+ {"regexp", 2, SQLITE_ANY|SQLITE_DETERMINISTIC, 0, icuRegexpFunc},
+ {"lower", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
+ {"lower", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
+ {"upper", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
+ {"upper", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
+ {"lower", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
+ {"lower", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
+ {"upper", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
+ {"upper", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
+ {"like", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc},
+ {"like", 3, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc},
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
+ };
+ int rc = SQLITE_OK;
+ int i;
+
+ for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){
+ const struct IcuScalar *p = &scalars[i];
+ rc = sqlite3_create_function_v2(
+ db, p->zName, p->nArg, p->enc,
+ p->iContext ? (void*)db : (void*)0,
+ p->xFunc, 0, 0, 0
+ );
+ }
+
+ return rc;
+}
+
+#if !SQLITE_CORE
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_icu_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi)
+ return sqlite3IcuInit(db);
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi)
+ return sqlite3IcuInit(db);
+}
+#endif
+#endif
+
+#endif
--- origsrc/sqlite-autoconf-3300000/ieee754.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/ieee754.c 2019-10-08 13:42:19.145679400 +0200
@@ -0,0 +1,149 @@
+/*
+** 2013-04-17
+**
+** 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 SQLite extension implements functions for the exact display
+** and input of IEEE754 Binary64 floating-point numbers.
+**
+** ieee754(X)
+** ieee754(Y,Z)
+**
+** In the first form, the value X should be a floating-point number.
+** The function will return a string of the form 'ieee754(Y,Z)' where
+** Y and Z are integers such that X==Y*pow(2,Z).
+**
+** In the second form, Y and Z are integers which are the mantissa and
+** base-2 exponent of a new floating point number. The function returns
+** a floating-point value equal to Y*pow(2,Z).
+**
+** Examples:
+**
+** ieee754(2.0) -> 'ieee754(2,0)'
+** ieee754(45.25) -> 'ieee754(181,-2)'
+** ieee754(2, 0) -> 2.0
+** ieee754(181, -2) -> 45.25
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+
+/*
+** Implementation of the ieee754() function
+*/
+static void ieee754func(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ if( argc==1 ){
+ sqlite3_int64 m, a;
+ double r;
+ int e;
+ int isNeg;
+ char zResult[100];
+ assert( sizeof(m)==sizeof(r) );
+ if( sqlite3_value_type(argv[0])!=SQLITE_FLOAT ) return;
+ r = sqlite3_value_double(argv[0]);
+ if( r<0.0 ){
+ isNeg = 1;
+ r = -r;
+ }else{
+ isNeg = 0;
+ }
+ memcpy(&a,&r,sizeof(a));
+ if( a==0 ){
+ e = 0;
+ m = 0;
+ }else{
+ e = a>>52;
+ m = a & ((((sqlite3_int64)1)<<52)-1);
+ m |= ((sqlite3_int64)1)<<52;
+ while( e<1075 && m>0 && (m&1)==0 ){
+ m >>= 1;
+ e++;
+ }
+ if( isNeg ) m = -m;
+ }
+ sqlite3_snprintf(sizeof(zResult), zResult, "ieee754(%lld,%d)",
+ m, e-1075);
+ sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT);
+ }else if( argc==2 ){
+ sqlite3_int64 m, e, a;
+ double r;
+ int isNeg = 0;
+ m = sqlite3_value_int64(argv[0]);
+ e = sqlite3_value_int64(argv[1]);
+ if( m<0 ){
+ isNeg = 1;
+ m = -m;
+ if( m<0 ) return;
+ }else if( m==0 && e>1000 && e<1000 ){
+ sqlite3_result_double(context, 0.0);
+ return;
+ }
+ while( (m>>32)&0xffe00000 ){
+ m >>= 1;
+ e++;
+ }
+ while( m!=0 && ((m>>32)&0xfff00000)==0 ){
+ m <<= 1;
+ e--;
+ }
+ e += 1075;
+ if( e<0 ) e = m = 0;
+ if( e>0x7ff ) e = 0x7ff;
+ a = m & ((((sqlite3_int64)1)<<52)-1);
+ a |= e<<52;
+ if( isNeg ) a |= ((sqlite3_uint64)1)<<63;
+ memcpy(&r, &a, sizeof(r));
+ sqlite3_result_double(context, r);
+ }
+}
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_ieee_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "ieee754", 1, SQLITE_UTF8, 0,
+ ieee754func, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "ieee754", 2, SQLITE_UTF8, 0,
+ ieee754func, 0, 0);
+ }
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "ieee754", 1, SQLITE_UTF8, 0,
+ ieee754func, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "ieee754", 2, SQLITE_UTF8, 0,
+ ieee754func, 0, 0);
+ }
+ return rc;
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/json1.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/json1.c 2019-10-08 13:42:19.147633000 +0200
@@ -0,0 +1,2549 @@
+/*
+** 2015-08-12
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This SQLite extension implements JSON functions. The interface is
+** modeled after MySQL JSON functions:
+**
+** https://dev.mysql.com/doc/refman/5.7/en/json.html
+**
+** For the time being, all JSON is stored as pure text. (We might add
+** a JSONB type in the future which stores a binary encoding of JSON in
+** a BLOB, but there is no support for JSONB in the current implementation.
+** This implementation parses JSON text at 250 MB/s, so it is hard to see
+** how JSONB might improve on that.)
+*/
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1)
+#if !defined(SQLITEINT_H)
+#include "sqlite3ext.h"
+#endif
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+/* Mark a function parameter as unused, to suppress nuisance compiler
+** warnings. */
+#ifndef UNUSED_PARAM
+# define UNUSED_PARAM(X) (void)(X)
+#endif
+
+#ifndef LARGEST_INT64
+# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
+# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
+#endif
+
+/*
+** Versions of isspace(), isalnum() and isdigit() to which it is safe
+** to pass signed char values.
+*/
+#ifdef sqlite3Isdigit
+ /* Use the SQLite core versions if this routine is part of the
+ ** SQLite amalgamation */
+# define safe_isdigit(x) sqlite3Isdigit(x)
+# define safe_isalnum(x) sqlite3Isalnum(x)
+# define safe_isxdigit(x) sqlite3Isxdigit(x)
+#else
+ /* Use the standard library for separate compilation */
+#include <ctype.h> /* amalgamator: keep */
+# define safe_isdigit(x) isdigit((unsigned char)(x))
+# define safe_isalnum(x) isalnum((unsigned char)(x))
+# define safe_isxdigit(x) isxdigit((unsigned char)(x))
+#endif
+
+/*
+** Growing our own isspace() routine this way is twice as fast as
+** the library isspace() function, resulting in a 7% overall performance
+** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
+*/
+static const char jsonIsSpace[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+#define safe_isspace(x) (jsonIsSpace[(unsigned char)x])
+
+#ifndef SQLITE_AMALGAMATION
+ /* Unsigned integer types. These are already defined in the sqliteInt.h,
+ ** but the definitions need to be repeated for separate compilation. */
+ typedef unsigned int u32;
+ typedef unsigned short int u16;
+ typedef unsigned char u8;
+#endif
+
+/* Objects */
+typedef struct JsonString JsonString;
+typedef struct JsonNode JsonNode;
+typedef struct JsonParse JsonParse;
+
+/* An instance of this object represents a JSON string
+** under construction. Really, this is a generic string accumulator
+** that can be and is used to create strings other than JSON.
+*/
+struct JsonString {
+ sqlite3_context *pCtx; /* Function context - put error messages here */
+ char *zBuf; /* Append JSON content here */
+ size_t nAlloc; /* Bytes of storage available in zBuf[] */
+ size_t nUsed; /* Bytes of zBuf[] currently used */
+ u8 bStatic; /* True if zBuf is static space */
+ u8 bErr; /* True if an error has been encountered */
+ char zSpace[100]; /* Initial static space */
+};
+
+/* JSON type values
+*/
+#define JSON_NULL 0
+#define JSON_TRUE 1
+#define JSON_FALSE 2
+#define JSON_INT 3
+#define JSON_REAL 4
+#define JSON_STRING 5
+#define JSON_ARRAY 6
+#define JSON_OBJECT 7
+
+/* The "subtype" set for JSON values */
+#define JSON_SUBTYPE 74 /* Ascii for "J" */
+
+/*
+** Names of the various JSON types:
+*/
+static const char jsonType[][8] = {
+ "null", "true", "false", "integer", "real", "text", "array", "object"
+};
+
+/* Bit values for the JsonNode.jnFlag field
+*/
+#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */
+#define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */
+#define JNODE_REMOVE 0x04 /* Do not output */
+#define JNODE_REPLACE 0x08 /* Replace with JsonNode.u.iReplace */
+#define JNODE_PATCH 0x10 /* Patch with JsonNode.u.pPatch */
+#define JNODE_APPEND 0x20 /* More ARRAY/OBJECT entries at u.iAppend */
+#define JNODE_LABEL 0x40 /* Is a label of an object */
+
+
+/* A single node of parsed JSON
+*/
+struct JsonNode {
+ u8 eType; /* One of the JSON_ type values */
+ u8 jnFlags; /* JNODE flags */
+ u32 n; /* Bytes of content, or number of sub-nodes */
+ union {
+ const char *zJContent; /* Content for INT, REAL, and STRING */
+ u32 iAppend; /* More terms for ARRAY and OBJECT */
+ u32 iKey; /* Key for ARRAY objects in json_tree() */
+ u32 iReplace; /* Replacement content for JNODE_REPLACE */
+ JsonNode *pPatch; /* Node chain of patch for JNODE_PATCH */
+ } u;
+};
+
+/* A completely parsed JSON string
+*/
+struct JsonParse {
+ u32 nNode; /* Number of slots of aNode[] used */
+ u32 nAlloc; /* Number of slots of aNode[] allocated */
+ JsonNode *aNode; /* Array of nodes containing the parse */
+ const char *zJson; /* Original JSON string */
+ u32 *aUp; /* Index of parent of each node */
+ u8 oom; /* Set to true if out of memory */
+ u8 nErr; /* Number of errors seen */
+ u16 iDepth; /* Nesting depth */
+ int nJson; /* Length of the zJson string in bytes */
+ u32 iHold; /* Replace cache line with the lowest iHold value */
+};
+
+/*
+** Maximum nesting depth of JSON for this implementation.
+**
+** This limit is needed to avoid a stack overflow in the recursive
+** descent parser. A depth of 2000 is far deeper than any sane JSON
+** should go.
+*/
+#define JSON_MAX_DEPTH 2000
+
+/**************************************************************************
+** Utility routines for dealing with JsonString objects
+**************************************************************************/
+
+/* Set the JsonString object to an empty string
+*/
+static void jsonZero(JsonString *p){
+ p->zBuf = p->zSpace;
+ p->nAlloc = sizeof(p->zSpace);
+ p->nUsed = 0;
+ p->bStatic = 1;
+}
+
+/* Initialize the JsonString object
+*/
+static void jsonInit(JsonString *p, sqlite3_context *pCtx){
+ p->pCtx = pCtx;
+ p->bErr = 0;
+ jsonZero(p);
+}
+
+
+/* Free all allocated memory and reset the JsonString object back to its
+** initial state.
+*/
+static void jsonReset(JsonString *p){
+ if( !p->bStatic ) sqlite3_free(p->zBuf);
+ jsonZero(p);
+}
+
+
+/* Report an out-of-memory (OOM) condition
+*/
+static void jsonOom(JsonString *p){
+ p->bErr = 1;
+ sqlite3_result_error_nomem(p->pCtx);
+ jsonReset(p);
+}
+
+/* Enlarge pJson->zBuf so that it can hold at least N more bytes.
+** Return zero on success. Return non-zero on an OOM error
+*/
+static int jsonGrow(JsonString *p, u32 N){
+ size_t nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
+ char *zNew;
+ if( p->bStatic ){
+ if( p->bErr ) return 1;
+ zNew = sqlite3_malloc(nTotal);
+ if( zNew==0 ){
+ jsonOom(p);
+ return SQLITE_NOMEM;
+ }
+ memcpy(zNew, p->zBuf, (size_t)p->nUsed);
+ p->zBuf = zNew;
+ p->bStatic = 0;
+ }else{
+ zNew = sqlite3_realloc(p->zBuf, nTotal);
+ if( zNew==0 ){
+ jsonOom(p);
+ return SQLITE_NOMEM;
+ }
+ p->zBuf = zNew;
+ }
+ p->nAlloc = nTotal;
+ return SQLITE_OK;
+}
+
+/* Append N bytes from zIn onto the end of the JsonString string.
+*/
+static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
+ if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
+ memcpy(p->zBuf+p->nUsed, zIn, N);
+ p->nUsed += N;
+}
+
+/* Append formatted text (not to exceed N bytes) to the JsonString.
+*/
+static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
+ va_list ap;
+ if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return;
+ va_start(ap, zFormat);
+ sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap);
+ va_end(ap);
+ p->nUsed += (int)strlen(p->zBuf+p->nUsed);
+}
+
+/* Append a single character
+*/
+static void jsonAppendChar(JsonString *p, char c){
+ if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return;
+ p->zBuf[p->nUsed++] = c;
+}
+
+/* Append a comma separator to the output buffer, if the previous
+** character is not '[' or '{'.
+*/
+static void jsonAppendSeparator(JsonString *p){
+ char c;
+ if( p->nUsed==0 ) return;
+ c = p->zBuf[p->nUsed-1];
+ if( c!='[' && c!='{' ) jsonAppendChar(p, ',');
+}
+
+/* Append the N-byte string in zIn to the end of the JsonString string
+** under construction. Enclose the string in "..." and escape
+** any double-quotes or backslash characters contained within the
+** string.
+*/
+static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
+ u32 i;
+ if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return;
+ p->zBuf[p->nUsed++] = '"';
+ for(i=0; i<N; i++){
+ unsigned char c = ((unsigned const char*)zIn)[i];
+ if( c=='"' || c=='\\' ){
+ json_simple_escape:
+ if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return;
+ p->zBuf[p->nUsed++] = '\\';
+ }else if( c<=0x1f ){
+ static const char aSpecial[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ assert( sizeof(aSpecial)==32 );
+ assert( aSpecial['\b']=='b' );
+ assert( aSpecial['\f']=='f' );
+ assert( aSpecial['\n']=='n' );
+ assert( aSpecial['\r']=='r' );
+ assert( aSpecial['\t']=='t' );
+ if( aSpecial[c] ){
+ c = aSpecial[c];
+ goto json_simple_escape;
+ }
+ if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return;
+ p->zBuf[p->nUsed++] = '\\';
+ p->zBuf[p->nUsed++] = 'u';
+ p->zBuf[p->nUsed++] = '0';
+ p->zBuf[p->nUsed++] = '0';
+ p->zBuf[p->nUsed++] = '0' + (c>>4);
+ c = "0123456789abcdef"[c&0xf];
+ }
+ p->zBuf[p->nUsed++] = c;
+ }
+ p->zBuf[p->nUsed++] = '"';
+ assert( p->nUsed<p->nAlloc );
+}
+
+/*
+** Append a function parameter value to the JSON string under
+** construction.
+*/
+static void jsonAppendValue(
+ JsonString *p, /* Append to this JSON string */
+ sqlite3_value *pValue /* Value to append */
+){
+ switch( sqlite3_value_type(pValue) ){
+ case SQLITE_NULL: {
+ jsonAppendRaw(p, "null", 4);
+ break;
+ }
+ case SQLITE_INTEGER:
+ case SQLITE_FLOAT: {
+ const char *z = (const char*)sqlite3_value_text(pValue);
+ u32 n = (u32)sqlite3_value_bytes(pValue);
+ jsonAppendRaw(p, z, n);
+ break;
+ }
+ case SQLITE_TEXT: {
+ const char *z = (const char*)sqlite3_value_text(pValue);
+ u32 n = (u32)sqlite3_value_bytes(pValue);
+ if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){
+ jsonAppendRaw(p, z, n);
+ }else{
+ jsonAppendString(p, z, n);
+ }
+ break;
+ }
+ default: {
+ if( p->bErr==0 ){
+ sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
+ p->bErr = 2;
+ jsonReset(p);
+ }
+ break;
+ }
+ }
+}
+
+
+/* Make the JSON in p the result of the SQL function.
+*/
+static void jsonResult(JsonString *p){
+ if( p->bErr==0 ){
+ sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
+ p->bStatic ? SQLITE_TRANSIENT : sqlite3_free,
+ SQLITE_UTF8);
+ jsonZero(p);
+ }
+ assert( p->bStatic );
+}
+
+/**************************************************************************
+** Utility routines for dealing with JsonNode and JsonParse objects
+**************************************************************************/
+
+/*
+** Return the number of consecutive JsonNode slots need to represent
+** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and
+** OBJECT types, the number might be larger.
+**
+** Appended elements are not counted. The value returned is the number
+** by which the JsonNode counter should increment in order to go to the
+** next peer value.
+*/
+static u32 jsonNodeSize(JsonNode *pNode){
+ return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1;
+}
+
+/*
+** Reclaim all memory allocated by a JsonParse object. But do not
+** delete the JsonParse object itself.
+*/
+static void jsonParseReset(JsonParse *pParse){
+ sqlite3_free(pParse->aNode);
+ pParse->aNode = 0;
+ pParse->nNode = 0;
+ pParse->nAlloc = 0;
+ sqlite3_free(pParse->aUp);
+ pParse->aUp = 0;
+}
+
+/*
+** Free a JsonParse object that was obtained from sqlite3_malloc().
+*/
+static void jsonParseFree(JsonParse *pParse){
+ jsonParseReset(pParse);
+ sqlite3_free(pParse);
+}
+
+/*
+** Convert the JsonNode pNode into a pure JSON string and
+** append to pOut. Subsubstructure is also included. Return
+** the number of JsonNode objects that are encoded.
+*/
+static void jsonRenderNode(
+ JsonNode *pNode, /* The node to render */
+ JsonString *pOut, /* Write JSON here */
+ sqlite3_value **aReplace /* Replacement values */
+){
+ if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){
+ if( pNode->jnFlags & JNODE_REPLACE ){
+ jsonAppendValue(pOut, aReplace[pNode->u.iReplace]);
+ return;
+ }
+ pNode = pNode->u.pPatch;
+ }
+ switch( pNode->eType ){
+ default: {
+ assert( pNode->eType==JSON_NULL );
+ jsonAppendRaw(pOut, "null", 4);
+ break;
+ }
+ case JSON_TRUE: {
+ jsonAppendRaw(pOut, "true", 4);
+ break;
+ }
+ case JSON_FALSE: {
+ jsonAppendRaw(pOut, "false", 5);
+ break;
+ }
+ case JSON_STRING: {
+ if( pNode->jnFlags & JNODE_RAW ){
+ jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
+ break;
+ }
+ /* Fall through into the next case */
+ }
+ case JSON_REAL:
+ case JSON_INT: {
+ jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
+ break;
+ }
+ case JSON_ARRAY: {
+ u32 j = 1;
+ jsonAppendChar(pOut, '[');
+ for(;;){
+ while( j<=pNode->n ){
+ if( (pNode[j].jnFlags & JNODE_REMOVE)==0 ){
+ jsonAppendSeparator(pOut);
+ jsonRenderNode(&pNode[j], pOut, aReplace);
+ }
+ j += jsonNodeSize(&pNode[j]);
+ }
+ if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
+ pNode = &pNode[pNode->u.iAppend];
+ j = 1;
+ }
+ jsonAppendChar(pOut, ']');
+ break;
+ }
+ case JSON_OBJECT: {
+ u32 j = 1;
+ jsonAppendChar(pOut, '{');
+ for(;;){
+ while( j<=pNode->n ){
+ if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){
+ jsonAppendSeparator(pOut);
+ jsonRenderNode(&pNode[j], pOut, aReplace);
+ jsonAppendChar(pOut, ':');
+ jsonRenderNode(&pNode[j+1], pOut, aReplace);
+ }
+ j += 1 + jsonNodeSize(&pNode[j+1]);
+ }
+ if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
+ pNode = &pNode[pNode->u.iAppend];
+ j = 1;
+ }
+ jsonAppendChar(pOut, '}');
+ break;
+ }
+ }
+}
+
+/*
+** Return a JsonNode and all its descendents as a JSON string.
+*/
+static void jsonReturnJson(
+ JsonNode *pNode, /* Node to return */
+ sqlite3_context *pCtx, /* Return value for this function */
+ sqlite3_value **aReplace /* Array of replacement values */
+){
+ JsonString s;
+ jsonInit(&s, pCtx);
+ jsonRenderNode(pNode, &s, aReplace);
+ jsonResult(&s);
+ sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
+}
+
+/*
+** Make the JsonNode the return value of the function.
+*/
+static void jsonReturn(
+ JsonNode *pNode, /* Node to return */
+ sqlite3_context *pCtx, /* Return value for this function */
+ sqlite3_value **aReplace /* Array of replacement values */
+){
+ switch( pNode->eType ){
+ default: {
+ assert( pNode->eType==JSON_NULL );
+ sqlite3_result_null(pCtx);
+ break;
+ }
+ case JSON_TRUE: {
+ sqlite3_result_int(pCtx, 1);
+ break;
+ }
+ case JSON_FALSE: {
+ sqlite3_result_int(pCtx, 0);
+ break;
+ }
+ case JSON_INT: {
+ sqlite3_int64 i = 0;
+ const char *z = pNode->u.zJContent;
+ if( z[0]=='-' ){ z++; }
+ while( z[0]>='0' && z[0]<='9' ){
+ unsigned v = *(z++) - '0';
+ if( i>=LARGEST_INT64/10 ){
+ if( i>LARGEST_INT64/10 ) goto int_as_real;
+ if( z[0]>='0' && z[0]<='9' ) goto int_as_real;
+ if( v==9 ) goto int_as_real;
+ if( v==8 ){
+ if( pNode->u.zJContent[0]=='-' ){
+ sqlite3_result_int64(pCtx, SMALLEST_INT64);
+ goto int_done;
+ }else{
+ goto int_as_real;
+ }
+ }
+ }
+ i = i*10 + v;
+ }
+ if( pNode->u.zJContent[0]=='-' ){ i = -i; }
+ sqlite3_result_int64(pCtx, i);
+ int_done:
+ break;
+ int_as_real: /* fall through to real */;
+ }
+ case JSON_REAL: {
+ double r;
+#ifdef SQLITE_AMALGAMATION
+ const char *z = pNode->u.zJContent;
+ sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
+#else
+ r = strtod(pNode->u.zJContent, 0);
+#endif
+ sqlite3_result_double(pCtx, r);
+ break;
+ }
+ case JSON_STRING: {
+#if 0 /* Never happens because JNODE_RAW is only set by json_set(),
+ ** json_insert() and json_replace() and those routines do not
+ ** call jsonReturn() */
+ if( pNode->jnFlags & JNODE_RAW ){
+ sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n,
+ SQLITE_TRANSIENT);
+ }else
+#endif
+ assert( (pNode->jnFlags & JNODE_RAW)==0 );
+ if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
+ /* JSON formatted without any backslash-escapes */
+ sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2,
+ SQLITE_TRANSIENT);
+ }else{
+ /* Translate JSON formatted string into raw text */
+ u32 i;
+ u32 n = pNode->n;
+ const char *z = pNode->u.zJContent;
+ char *zOut;
+ u32 j;
+ zOut = sqlite3_malloc( n+1 );
+ if( zOut==0 ){
+ sqlite3_result_error_nomem(pCtx);
+ break;
+ }
+ for(i=1, j=0; i<n-1; i++){
+ char c = z[i];
+ if( c!='\\' ){
+ zOut[j++] = c;
+ }else{
+ c = z[++i];
+ if( c=='u' ){
+ u32 v = 0, k;
+ for(k=0; k<4; i++, k++){
+ assert( i<n-2 );
+ c = z[i+1];
+ assert( safe_isxdigit(c) );
+ if( c<='9' ) v = v*16 + c - '0';
+ else if( c<='F' ) v = v*16 + c - 'A' + 10;
+ else v = v*16 + c - 'a' + 10;
+ }
+ if( v==0 ) break;
+ if( v<=0x7f ){
+ zOut[j++] = (char)v;
+ }else if( v<=0x7ff ){
+ zOut[j++] = (char)(0xc0 | (v>>6));
+ zOut[j++] = 0x80 | (v&0x3f);
+ }else{
+ zOut[j++] = (char)(0xe0 | (v>>12));
+ zOut[j++] = 0x80 | ((v>>6)&0x3f);
+ zOut[j++] = 0x80 | (v&0x3f);
+ }
+ }else{
+ if( c=='b' ){
+ c = '\b';
+ }else if( c=='f' ){
+ c = '\f';
+ }else if( c=='n' ){
+ c = '\n';
+ }else if( c=='r' ){
+ c = '\r';
+ }else if( c=='t' ){
+ c = '\t';
+ }
+ zOut[j++] = c;
+ }
+ }
+ }
+ zOut[j] = 0;
+ sqlite3_result_text(pCtx, zOut, j, sqlite3_free);
+ }
+ break;
+ }
+ case JSON_ARRAY:
+ case JSON_OBJECT: {
+ jsonReturnJson(pNode, pCtx, aReplace);
+ break;
+ }
+ }
+}
+
+/* Forward reference */
+static int jsonParseAddNode(JsonParse*,u32,u32,const char*);
+
+/*
+** A macro to hint to the compiler that a function should not be
+** inlined.
+*/
+#if defined(__GNUC__)
+# define JSON_NOINLINE __attribute__((noinline))
+#elif defined(_MSC_VER) && _MSC_VER>=1310
+# define JSON_NOINLINE __declspec(noinline)
+#else
+# define JSON_NOINLINE
+#endif
+
+
+static JSON_NOINLINE int jsonParseAddNodeExpand(
+ JsonParse *pParse, /* Append the node to this object */
+ u32 eType, /* Node type */
+ u32 n, /* Content size or sub-node count */
+ const char *zContent /* Content */
+){
+ u32 nNew;
+ JsonNode *pNew;
+ assert( pParse->nNode>=pParse->nAlloc );
+ if( pParse->oom ) return -1;
+ nNew = pParse->nAlloc*2 + 10;
+ pNew = sqlite3_realloc64(pParse->aNode, sizeof(JsonNode)*nNew);
+ if( pNew==0 ){
+ pParse->oom = 1;
+ return -1;
+ }
+ pParse->nAlloc = nNew;
+ pParse->aNode = pNew;
+ assert( pParse->nNode<pParse->nAlloc );
+ return jsonParseAddNode(pParse, eType, n, zContent);
+}
+
+/*
+** Create a new JsonNode instance based on the arguments and append that
+** instance to the JsonParse. Return the index in pParse->aNode[] of the
+** new node, or -1 if a memory allocation fails.
+*/
+static int jsonParseAddNode(
+ JsonParse *pParse, /* Append the node to this object */
+ u32 eType, /* Node type */
+ u32 n, /* Content size or sub-node count */
+ const char *zContent /* Content */
+){
+ JsonNode *p;
+ if( pParse->nNode>=pParse->nAlloc ){
+ return jsonParseAddNodeExpand(pParse, eType, n, zContent);
+ }
+ p = &pParse->aNode[pParse->nNode];
+ p->eType = (u8)eType;
+ p->jnFlags = 0;
+ p->n = n;
+ p->u.zJContent = zContent;
+ return pParse->nNode++;
+}
+
+/*
+** Return true if z[] begins with 4 (or more) hexadecimal digits
+*/
+static int jsonIs4Hex(const char *z){
+ int i;
+ for(i=0; i<4; i++) if( !safe_isxdigit(z[i]) ) return 0;
+ return 1;
+}
+
+/*
+** Parse a single JSON value which begins at pParse->zJson[i]. Return the
+** index of the first character past the end of the value parsed.
+**
+** Return negative for a syntax error. Special cases: return -2 if the
+** first non-whitespace character is '}' and return -3 if the first
+** non-whitespace character is ']'.
+*/
+static int jsonParseValue(JsonParse *pParse, u32 i){
+ char c;
+ u32 j;
+ int iThis;
+ int x;
+ JsonNode *pNode;
+ const char *z = pParse->zJson;
+ while( safe_isspace(z[i]) ){ i++; }
+ if( (c = z[i])=='{' ){
+ /* Parse object */
+ iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
+ if( iThis<0 ) return -1;
+ for(j=i+1;;j++){
+ while( safe_isspace(z[j]) ){ j++; }
+ if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
+ x = jsonParseValue(pParse, j);
+ if( x<0 ){
+ pParse->iDepth--;
+ if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
+ return -1;
+ }
+ if( pParse->oom ) return -1;
+ pNode = &pParse->aNode[pParse->nNode-1];
+ if( pNode->eType!=JSON_STRING ) return -1;
+ pNode->jnFlags |= JNODE_LABEL;
+ j = x;
+ while( safe_isspace(z[j]) ){ j++; }
+ if( z[j]!=':' ) return -1;
+ j++;
+ x = jsonParseValue(pParse, j);
+ pParse->iDepth--;
+ if( x<0 ) return -1;
+ j = x;
+ while( safe_isspace(z[j]) ){ j++; }
+ c = z[j];
+ if( c==',' ) continue;
+ if( c!='}' ) return -1;
+ break;
+ }
+ pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
+ return j+1;
+ }else if( c=='[' ){
+ /* Parse array */
+ iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
+ if( iThis<0 ) return -1;
+ for(j=i+1;;j++){
+ while( safe_isspace(z[j]) ){ j++; }
+ if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
+ x = jsonParseValue(pParse, j);
+ pParse->iDepth--;
+ if( x<0 ){
+ if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
+ return -1;
+ }
+ j = x;
+ while( safe_isspace(z[j]) ){ j++; }
+ c = z[j];
+ if( c==',' ) continue;
+ if( c!=']' ) return -1;
+ break;
+ }
+ pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
+ return j+1;
+ }else if( c=='"' ){
+ /* Parse string */
+ u8 jnFlags = 0;
+ j = i+1;
+ for(;;){
+ c = z[j];
+ if( (c & ~0x1f)==0 ){
+ /* Control characters are not allowed in strings */
+ return -1;
+ }
+ if( c=='\\' ){
+ c = z[++j];
+ if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
+ || c=='n' || c=='r' || c=='t'
+ || (c=='u' && jsonIs4Hex(z+j+1)) ){
+ jnFlags = JNODE_ESCAPE;
+ }else{
+ return -1;
+ }
+ }else if( c=='"' ){
+ break;
+ }
+ j++;
+ }
+ jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]);
+ if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags;
+ return j+1;
+ }else if( c=='n'
+ && strncmp(z+i,"null",4)==0
+ && !safe_isalnum(z[i+4]) ){
+ jsonParseAddNode(pParse, JSON_NULL, 0, 0);
+ return i+4;
+ }else if( c=='t'
+ && strncmp(z+i,"true",4)==0
+ && !safe_isalnum(z[i+4]) ){
+ jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
+ return i+4;
+ }else if( c=='f'
+ && strncmp(z+i,"false",5)==0
+ && !safe_isalnum(z[i+5]) ){
+ jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
+ return i+5;
+ }else if( c=='-' || (c>='0' && c<='9') ){
+ /* Parse number */
+ u8 seenDP = 0;
+ u8 seenE = 0;
+ assert( '-' < '0' );
+ if( c<='0' ){
+ j = c=='-' ? i+1 : i;
+ if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1;
+ }
+ j = i+1;
+ for(;; j++){
+ c = z[j];
+ if( c>='0' && c<='9' ) continue;
+ if( c=='.' ){
+ if( z[j-1]=='-' ) return -1;
+ if( seenDP ) return -1;
+ seenDP = 1;
+ continue;
+ }
+ if( c=='e' || c=='E' ){
+ if( z[j-1]<'0' ) return -1;
+ if( seenE ) return -1;
+ seenDP = seenE = 1;
+ c = z[j+1];
+ if( c=='+' || c=='-' ){
+ j++;
+ c = z[j+1];
+ }
+ if( c<'0' || c>'9' ) return -1;
+ continue;
+ }
+ break;
+ }
+ if( z[j-1]<'0' ) return -1;
+ jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT,
+ j - i, &z[i]);
+ return j;
+ }else if( c=='}' ){
+ return -2; /* End of {...} */
+ }else if( c==']' ){
+ return -3; /* End of [...] */
+ }else if( c==0 ){
+ return 0; /* End of file */
+ }else{
+ return -1; /* Syntax error */
+ }
+}
+
+/*
+** Parse a complete JSON string. Return 0 on success or non-zero if there
+** are any errors. If an error occurs, free all memory associated with
+** pParse.
+**
+** pParse is uninitialized when this routine is called.
+*/
+static int jsonParse(
+ JsonParse *pParse, /* Initialize and fill this JsonParse object */
+ sqlite3_context *pCtx, /* Report errors here */
+ const char *zJson /* Input JSON text to be parsed */
+){
+ int i;
+ memset(pParse, 0, sizeof(*pParse));
+ if( zJson==0 ) return 1;
+ pParse->zJson = zJson;
+ i = jsonParseValue(pParse, 0);
+ if( pParse->oom ) i = -1;
+ if( i>0 ){
+ assert( pParse->iDepth==0 );
+ while( safe_isspace(zJson[i]) ) i++;
+ if( zJson[i] ) i = -1;
+ }
+ if( i<=0 ){
+ if( pCtx!=0 ){
+ if( pParse->oom ){
+ sqlite3_result_error_nomem(pCtx);
+ }else{
+ sqlite3_result_error(pCtx, "malformed JSON", -1);
+ }
+ }
+ jsonParseReset(pParse);
+ return 1;
+ }
+ return 0;
+}
+
+/* Mark node i of pParse as being a child of iParent. Call recursively
+** to fill in all the descendants of node i.
+*/
+static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){
+ JsonNode *pNode = &pParse->aNode[i];
+ u32 j;
+ pParse->aUp[i] = iParent;
+ switch( pNode->eType ){
+ case JSON_ARRAY: {
+ for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){
+ jsonParseFillInParentage(pParse, i+j, i);
+ }
+ break;
+ }
+ case JSON_OBJECT: {
+ for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){
+ pParse->aUp[i+j] = i;
+ jsonParseFillInParentage(pParse, i+j+1, i);
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+}
+
+/*
+** Compute the parentage of all nodes in a completed parse.
+*/
+static int jsonParseFindParents(JsonParse *pParse){
+ u32 *aUp;
+ assert( pParse->aUp==0 );
+ aUp = pParse->aUp = sqlite3_malloc( sizeof(u32)*pParse->nNode );
+ if( aUp==0 ){
+ pParse->oom = 1;
+ return SQLITE_NOMEM;
+ }
+ jsonParseFillInParentage(pParse, 0, 0);
+ return SQLITE_OK;
+}
+
+/*
+** Magic number used for the JSON parse cache in sqlite3_get_auxdata()
+*/
+#define JSON_CACHE_ID (-429938) /* First cache entry */
+#define JSON_CACHE_SZ 4 /* Max number of cache entries */
+
+/*
+** Obtain a complete parse of the JSON found in the first argument
+** of the argv array. Use the sqlite3_get_auxdata() cache for this
+** parse if it is available. If the cache is not available or if it
+** is no longer valid, parse the JSON again and return the new parse,
+** and also register the new parse so that it will be available for
+** future sqlite3_get_auxdata() calls.
+*/
+static JsonParse *jsonParseCached(
+ sqlite3_context *pCtx,
+ sqlite3_value **argv,
+ sqlite3_context *pErrCtx
+){
+ const char *zJson = (const char*)sqlite3_value_text(argv[0]);
+ int nJson = sqlite3_value_bytes(argv[0]);
+ JsonParse *p;
+ JsonParse *pMatch = 0;
+ int iKey;
+ int iMinKey = 0;
+ u32 iMinHold = 0xffffffff;
+ u32 iMaxHold = 0;
+ if( zJson==0 ) return 0;
+ for(iKey=0; iKey<JSON_CACHE_SZ; iKey++){
+ p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iKey);
+ if( p==0 ){
+ iMinKey = iKey;
+ break;
+ }
+ if( pMatch==0
+ && p->nJson==nJson
+ && memcmp(p->zJson,zJson,nJson)==0
+ ){
+ p->nErr = 0;
+ pMatch = p;
+ }else if( p->iHold<iMinHold ){
+ iMinHold = p->iHold;
+ iMinKey = iKey;
+ }
+ if( p->iHold>iMaxHold ){
+ iMaxHold = p->iHold;
+ }
+ }
+ if( pMatch ){
+ pMatch->nErr = 0;
+ pMatch->iHold = iMaxHold+1;
+ return pMatch;
+ }
+ p = sqlite3_malloc( sizeof(*p) + nJson + 1 );
+ if( p==0 ){
+ sqlite3_result_error_nomem(pCtx);
+ return 0;
+ }
+ memset(p, 0, sizeof(*p));
+ p->zJson = (char*)&p[1];
+ memcpy((char*)p->zJson, zJson, nJson+1);
+ if( jsonParse(p, pErrCtx, p->zJson) ){
+ sqlite3_free(p);
+ return 0;
+ }
+ p->nJson = nJson;
+ p->iHold = iMaxHold+1;
+ sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p,
+ (void(*)(void*))jsonParseFree);
+ return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey);
+}
+
+/*
+** Compare the OBJECT label at pNode against zKey,nKey. Return true on
+** a match.
+*/
+static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){
+ if( pNode->jnFlags & JNODE_RAW ){
+ if( pNode->n!=nKey ) return 0;
+ return strncmp(pNode->u.zJContent, zKey, nKey)==0;
+ }else{
+ if( pNode->n!=nKey+2 ) return 0;
+ return strncmp(pNode->u.zJContent+1, zKey, nKey)==0;
+ }
+}
+
+/* forward declaration */
+static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**);
+
+/*
+** Search along zPath to find the node specified. Return a pointer
+** to that node, or NULL if zPath is malformed or if there is no such
+** node.
+**
+** If pApnd!=0, then try to append new nodes to complete zPath if it is
+** possible to do so and if no existing node corresponds to zPath. If
+** new nodes are appended *pApnd is set to 1.
+*/
+static JsonNode *jsonLookupStep(
+ JsonParse *pParse, /* The JSON to search */
+ u32 iRoot, /* Begin the search at this node */
+ const char *zPath, /* The path to search */
+ int *pApnd, /* Append nodes to complete path if not NULL */
+ const char **pzErr /* Make *pzErr point to any syntax error in zPath */
+){
+ u32 i, j, nKey;
+ const char *zKey;
+ JsonNode *pRoot = &pParse->aNode[iRoot];
+ if( zPath[0]==0 ) return pRoot;
+ if( pRoot->jnFlags & JNODE_REPLACE ) return 0;
+ if( zPath[0]=='.' ){
+ if( pRoot->eType!=JSON_OBJECT ) return 0;
+ zPath++;
+ if( zPath[0]=='"' ){
+ zKey = zPath + 1;
+ for(i=1; zPath[i] && zPath[i]!='"'; i++){}
+ nKey = i-1;
+ if( zPath[i] ){
+ i++;
+ }else{
+ *pzErr = zPath;
+ return 0;
+ }
+ }else{
+ zKey = zPath;
+ for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){}
+ nKey = i;
+ }
+ if( nKey==0 ){
+ *pzErr = zPath;
+ return 0;
+ }
+ j = 1;
+ for(;;){
+ while( j<=pRoot->n ){
+ if( jsonLabelCompare(pRoot+j, zKey, nKey) ){
+ return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr);
+ }
+ j++;
+ j += jsonNodeSize(&pRoot[j]);
+ }
+ if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
+ iRoot += pRoot->u.iAppend;
+ pRoot = &pParse->aNode[iRoot];
+ j = 1;
+ }
+ if( pApnd ){
+ u32 iStart, iLabel;
+ JsonNode *pNode;
+ iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
+ iLabel = jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
+ zPath += i;
+ pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
+ if( pParse->oom ) return 0;
+ if( pNode ){
+ pRoot = &pParse->aNode[iRoot];
+ pRoot->u.iAppend = iStart - iRoot;
+ pRoot->jnFlags |= JNODE_APPEND;
+ pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
+ }
+ return pNode;
+ }
+ }else if( zPath[0]=='[' && safe_isdigit(zPath[1]) ){
+ if( pRoot->eType!=JSON_ARRAY ) return 0;
+ i = 0;
+ j = 1;
+ while( safe_isdigit(zPath[j]) ){
+ i = i*10 + zPath[j] - '0';
+ j++;
+ }
+ if( zPath[j]!=']' ){
+ *pzErr = zPath;
+ return 0;
+ }
+ zPath += j + 1;
+ j = 1;
+ for(;;){
+ while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){
+ if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--;
+ j += jsonNodeSize(&pRoot[j]);
+ }
+ if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
+ iRoot += pRoot->u.iAppend;
+ pRoot = &pParse->aNode[iRoot];
+ j = 1;
+ }
+ if( j<=pRoot->n ){
+ return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr);
+ }
+ if( i==0 && pApnd ){
+ u32 iStart;
+ JsonNode *pNode;
+ iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0);
+ pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
+ if( pParse->oom ) return 0;
+ if( pNode ){
+ pRoot = &pParse->aNode[iRoot];
+ pRoot->u.iAppend = iStart - iRoot;
+ pRoot->jnFlags |= JNODE_APPEND;
+ }
+ return pNode;
+ }
+ }else{
+ *pzErr = zPath;
+ }
+ return 0;
+}
+
+/*
+** Append content to pParse that will complete zPath. Return a pointer
+** to the inserted node, or return NULL if the append fails.
+*/
+static JsonNode *jsonLookupAppend(
+ JsonParse *pParse, /* Append content to the JSON parse */
+ const char *zPath, /* Description of content to append */
+ int *pApnd, /* Set this flag to 1 */
+ const char **pzErr /* Make this point to any syntax error */
+){
+ *pApnd = 1;
+ if( zPath[0]==0 ){
+ jsonParseAddNode(pParse, JSON_NULL, 0, 0);
+ return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1];
+ }
+ if( zPath[0]=='.' ){
+ jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
+ }else if( strncmp(zPath,"[0]",3)==0 ){
+ jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
+ }else{
+ return 0;
+ }
+ if( pParse->oom ) return 0;
+ return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr);
+}
+
+/*
+** Return the text of a syntax error message on a JSON path. Space is
+** obtained from sqlite3_malloc().
+*/
+static char *jsonPathSyntaxError(const char *zErr){
+ return sqlite3_mprintf("JSON path error near '%q'", zErr);
+}
+
+/*
+** Do a node lookup using zPath. Return a pointer to the node on success.
+** Return NULL if not found or if there is an error.
+**
+** On an error, write an error message into pCtx and increment the
+** pParse->nErr counter.
+**
+** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if
+** nodes are appended.
+*/
+static JsonNode *jsonLookup(
+ JsonParse *pParse, /* The JSON to search */
+ const char *zPath, /* The path to search */
+ int *pApnd, /* Append nodes to complete path if not NULL */
+ sqlite3_context *pCtx /* Report errors here, if not NULL */
+){
+ const char *zErr = 0;
+ JsonNode *pNode = 0;
+ char *zMsg;
+
+ if( zPath==0 ) return 0;
+ if( zPath[0]!='$' ){
+ zErr = zPath;
+ goto lookup_err;
+ }
+ zPath++;
+ pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr);
+ if( zErr==0 ) return pNode;
+
+lookup_err:
+ pParse->nErr++;
+ assert( zErr!=0 && pCtx!=0 );
+ zMsg = jsonPathSyntaxError(zErr);
+ if( zMsg ){
+ sqlite3_result_error(pCtx, zMsg, -1);
+ sqlite3_free(zMsg);
+ }else{
+ sqlite3_result_error_nomem(pCtx);
+ }
+ return 0;
+}
+
+
+/*
+** Report the wrong number of arguments for json_insert(), json_replace()
+** or json_set().
+*/
+static void jsonWrongNumArgs(
+ sqlite3_context *pCtx,
+ const char *zFuncName
+){
+ char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments",
+ zFuncName);
+ sqlite3_result_error(pCtx, zMsg, -1);
+ sqlite3_free(zMsg);
+}
+
+/*
+** Mark all NULL entries in the Object passed in as JNODE_REMOVE.
+*/
+static void jsonRemoveAllNulls(JsonNode *pNode){
+ int i, n;
+ assert( pNode->eType==JSON_OBJECT );
+ n = pNode->n;
+ for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){
+ switch( pNode[i].eType ){
+ case JSON_NULL:
+ pNode[i].jnFlags |= JNODE_REMOVE;
+ break;
+ case JSON_OBJECT:
+ jsonRemoveAllNulls(&pNode[i]);
+ break;
+ }
+ }
+}
+
+
+/****************************************************************************
+** SQL functions used for testing and debugging
+****************************************************************************/
+
+#ifdef SQLITE_DEBUG
+/*
+** The json_parse(JSON) function returns a string which describes
+** a parse of the JSON provided. Or it returns NULL if JSON is not
+** well-formed.
+*/
+static void jsonParseFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonString s; /* Output string - not real JSON */
+ JsonParse x; /* The parse */
+ u32 i;
+
+ assert( argc==1 );
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+ jsonParseFindParents(&x);
+ jsonInit(&s, ctx);
+ for(i=0; i<x.nNode; i++){
+ const char *zType;
+ if( x.aNode[i].jnFlags & JNODE_LABEL ){
+ assert( x.aNode[i].eType==JSON_STRING );
+ zType = "label";
+ }else{
+ zType = jsonType[x.aNode[i].eType];
+ }
+ jsonPrintf(100, &s,"node %3u: %7s n=%-4d up=%-4d",
+ i, zType, x.aNode[i].n, x.aUp[i]);
+ if( x.aNode[i].u.zJContent!=0 ){
+ jsonAppendRaw(&s, " ", 1);
+ jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n);
+ }
+ jsonAppendRaw(&s, "\n", 1);
+ }
+ jsonParseReset(&x);
+ jsonResult(&s);
+}
+
+/*
+** The json_test1(JSON) function return true (1) if the input is JSON
+** text generated by another json function. It returns (0) if the input
+** is not known to be JSON.
+*/
+static void jsonTest1Func(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ UNUSED_PARAM(argc);
+ sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE);
+}
+#endif /* SQLITE_DEBUG */
+
+/****************************************************************************
+** Scalar SQL function implementations
+****************************************************************************/
+
+/*
+** Implementation of the json_QUOTE(VALUE) function. Return a JSON value
+** corresponding to the SQL value input. Mostly this means putting
+** double-quotes around strings and returning the unquoted string "null"
+** when given a NULL input.
+*/
+static void jsonQuoteFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonString jx;
+ UNUSED_PARAM(argc);
+
+ jsonInit(&jx, ctx);
+ jsonAppendValue(&jx, argv[0]);
+ jsonResult(&jx);
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+}
+
+/*
+** Implementation of the json_array(VALUE,...) function. Return a JSON
+** array that contains all values given in arguments. Or if any argument
+** is a BLOB, throw an error.
+*/
+static void jsonArrayFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ int i;
+ JsonString jx;
+
+ jsonInit(&jx, ctx);
+ jsonAppendChar(&jx, '[');
+ for(i=0; i<argc; i++){
+ jsonAppendSeparator(&jx);
+ jsonAppendValue(&jx, argv[i]);
+ }
+ jsonAppendChar(&jx, ']');
+ jsonResult(&jx);
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+}
+
+
+/*
+** json_array_length(JSON)
+** json_array_length(JSON, PATH)
+**
+** Return the number of elements in the top-level JSON array.
+** Return 0 if the input is not a well-formed JSON array.
+*/
+static void jsonArrayLengthFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse *p; /* The parse */
+ sqlite3_int64 n = 0;
+ u32 i;
+ JsonNode *pNode;
+
+ p = jsonParseCached(ctx, argv, ctx);
+ if( p==0 ) return;
+ assert( p->nNode );
+ if( argc==2 ){
+ const char *zPath = (const char*)sqlite3_value_text(argv[1]);
+ pNode = jsonLookup(p, zPath, 0, ctx);
+ }else{
+ pNode = p->aNode;
+ }
+ if( pNode==0 ){
+ return;
+ }
+ if( pNode->eType==JSON_ARRAY ){
+ assert( (pNode->jnFlags & JNODE_APPEND)==0 );
+ for(i=1; i<=pNode->n; n++){
+ i += jsonNodeSize(&pNode[i]);
+ }
+ }
+ sqlite3_result_int64(ctx, n);
+}
+
+/*
+** json_extract(JSON, PATH, ...)
+**
+** Return the element described by PATH. Return NULL if there is no
+** PATH element. If there are multiple PATHs, then return a JSON array
+** with the result from each path. Throw an error if the JSON or any PATH
+** is malformed.
+*/
+static void jsonExtractFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse *p; /* The parse */
+ JsonNode *pNode;
+ const char *zPath;
+ JsonString jx;
+ int i;
+
+ if( argc<2 ) return;
+ p = jsonParseCached(ctx, argv, ctx);
+ if( p==0 ) return;
+ jsonInit(&jx, ctx);
+ jsonAppendChar(&jx, '[');
+ for(i=1; i<argc; i++){
+ zPath = (const char*)sqlite3_value_text(argv[i]);
+ pNode = jsonLookup(p, zPath, 0, ctx);
+ if( p->nErr ) break;
+ if( argc>2 ){
+ jsonAppendSeparator(&jx);
+ if( pNode ){
+ jsonRenderNode(pNode, &jx, 0);
+ }else{
+ jsonAppendRaw(&jx, "null", 4);
+ }
+ }else if( pNode ){
+ jsonReturn(pNode, ctx, 0);
+ }
+ }
+ if( argc>2 && i==argc ){
+ jsonAppendChar(&jx, ']');
+ jsonResult(&jx);
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+ }
+ jsonReset(&jx);
+}
+
+/* This is the RFC 7396 MergePatch algorithm.
+*/
+static JsonNode *jsonMergePatch(
+ JsonParse *pParse, /* The JSON parser that contains the TARGET */
+ u32 iTarget, /* Node of the TARGET in pParse */
+ JsonNode *pPatch /* The PATCH */
+){
+ u32 i, j;
+ u32 iRoot;
+ JsonNode *pTarget;
+ if( pPatch->eType!=JSON_OBJECT ){
+ return pPatch;
+ }
+ assert( iTarget>=0 && iTarget<pParse->nNode );
+ pTarget = &pParse->aNode[iTarget];
+ assert( (pPatch->jnFlags & JNODE_APPEND)==0 );
+ if( pTarget->eType!=JSON_OBJECT ){
+ jsonRemoveAllNulls(pPatch);
+ return pPatch;
+ }
+ iRoot = iTarget;
+ for(i=1; i<pPatch->n; i += jsonNodeSize(&pPatch[i+1])+1){
+ u32 nKey;
+ const char *zKey;
+ assert( pPatch[i].eType==JSON_STRING );
+ assert( pPatch[i].jnFlags & JNODE_LABEL );
+ nKey = pPatch[i].n;
+ zKey = pPatch[i].u.zJContent;
+ assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
+ for(j=1; j<pTarget->n; j += jsonNodeSize(&pTarget[j+1])+1 ){
+ assert( pTarget[j].eType==JSON_STRING );
+ assert( pTarget[j].jnFlags & JNODE_LABEL );
+ assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
+ if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){
+ if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break;
+ if( pPatch[i+1].eType==JSON_NULL ){
+ pTarget[j+1].jnFlags |= JNODE_REMOVE;
+ }else{
+ JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]);
+ if( pNew==0 ) return 0;
+ pTarget = &pParse->aNode[iTarget];
+ if( pNew!=&pTarget[j+1] ){
+ pTarget[j+1].u.pPatch = pNew;
+ pTarget[j+1].jnFlags |= JNODE_PATCH;
+ }
+ }
+ break;
+ }
+ }
+ if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){
+ int iStart, iPatch;
+ iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
+ jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
+ iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
+ if( pParse->oom ) return 0;
+ jsonRemoveAllNulls(pPatch);
+ pTarget = &pParse->aNode[iTarget];
+ pParse->aNode[iRoot].jnFlags |= JNODE_APPEND;
+ pParse->aNode[iRoot].u.iAppend = iStart - iRoot;
+ iRoot = iStart;
+ pParse->aNode[iPatch].jnFlags |= JNODE_PATCH;
+ pParse->aNode[iPatch].u.pPatch = &pPatch[i+1];
+ }
+ }
+ return pTarget;
+}
+
+/*
+** Implementation of the json_mergepatch(JSON1,JSON2) function. Return a JSON
+** object that is the result of running the RFC 7396 MergePatch() algorithm
+** on the two arguments.
+*/
+static void jsonPatchFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse x; /* The JSON that is being patched */
+ JsonParse y; /* The patch */
+ JsonNode *pResult; /* The result of the merge */
+
+ UNUSED_PARAM(argc);
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+ if( jsonParse(&y, ctx, (const char*)sqlite3_value_text(argv[1])) ){
+ jsonParseReset(&x);
+ return;
+ }
+ pResult = jsonMergePatch(&x, 0, y.aNode);
+ assert( pResult!=0 || x.oom );
+ if( pResult ){
+ jsonReturnJson(pResult, ctx, 0);
+ }else{
+ sqlite3_result_error_nomem(ctx);
+ }
+ jsonParseReset(&x);
+ jsonParseReset(&y);
+}
+
+
+/*
+** Implementation of the json_object(NAME,VALUE,...) function. Return a JSON
+** object that contains all name/value given in arguments. Or if any name
+** is not a string or if any value is a BLOB, throw an error.
+*/
+static void jsonObjectFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ int i;
+ JsonString jx;
+ const char *z;
+ u32 n;
+
+ if( argc&1 ){
+ sqlite3_result_error(ctx, "json_object() requires an even number "
+ "of arguments", -1);
+ return;
+ }
+ jsonInit(&jx, ctx);
+ jsonAppendChar(&jx, '{');
+ for(i=0; i<argc; i+=2){
+ if( sqlite3_value_type(argv[i])!=SQLITE_TEXT ){
+ sqlite3_result_error(ctx, "json_object() labels must be TEXT", -1);
+ jsonReset(&jx);
+ return;
+ }
+ jsonAppendSeparator(&jx);
+ z = (const char*)sqlite3_value_text(argv[i]);
+ n = (u32)sqlite3_value_bytes(argv[i]);
+ jsonAppendString(&jx, z, n);
+ jsonAppendChar(&jx, ':');
+ jsonAppendValue(&jx, argv[i+1]);
+ }
+ jsonAppendChar(&jx, '}');
+ jsonResult(&jx);
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+}
+
+
+/*
+** json_remove(JSON, PATH, ...)
+**
+** Remove the named elements from JSON and return the result. malformed
+** JSON or PATH arguments result in an error.
+*/
+static void jsonRemoveFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse x; /* The parse */
+ JsonNode *pNode;
+ const char *zPath;
+ u32 i;
+
+ if( argc<1 ) return;
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+ assert( x.nNode );
+ for(i=1; i<(u32)argc; i++){
+ zPath = (const char*)sqlite3_value_text(argv[i]);
+ if( zPath==0 ) goto remove_done;
+ pNode = jsonLookup(&x, zPath, 0, ctx);
+ if( x.nErr ) goto remove_done;
+ if( pNode ) pNode->jnFlags |= JNODE_REMOVE;
+ }
+ if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){
+ jsonReturnJson(x.aNode, ctx, 0);
+ }
+remove_done:
+ jsonParseReset(&x);
+}
+
+/*
+** json_replace(JSON, PATH, VALUE, ...)
+**
+** Replace the value at PATH with VALUE. If PATH does not already exist,
+** this routine is a no-op. If JSON or PATH is malformed, throw an error.
+*/
+static void jsonReplaceFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse x; /* The parse */
+ JsonNode *pNode;
+ const char *zPath;
+ u32 i;
+
+ if( argc<1 ) return;
+ if( (argc&1)==0 ) {
+ jsonWrongNumArgs(ctx, "replace");
+ return;
+ }
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+ assert( x.nNode );
+ for(i=1; i<(u32)argc; i+=2){
+ zPath = (const char*)sqlite3_value_text(argv[i]);
+ pNode = jsonLookup(&x, zPath, 0, ctx);
+ if( x.nErr ) goto replace_err;
+ if( pNode ){
+ pNode->jnFlags |= (u8)JNODE_REPLACE;
+ pNode->u.iReplace = i + 1;
+ }
+ }
+ if( x.aNode[0].jnFlags & JNODE_REPLACE ){
+ sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
+ }else{
+ jsonReturnJson(x.aNode, ctx, argv);
+ }
+replace_err:
+ jsonParseReset(&x);
+}
+
+/*
+** json_set(JSON, PATH, VALUE, ...)
+**
+** Set the value at PATH to VALUE. Create the PATH if it does not already
+** exist. Overwrite existing values that do exist.
+** If JSON or PATH is malformed, throw an error.
+**
+** json_insert(JSON, PATH, VALUE, ...)
+**
+** Create PATH and initialize it to VALUE. If PATH already exists, this
+** routine is a no-op. If JSON or PATH is malformed, throw an error.
+*/
+static void jsonSetFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse x; /* The parse */
+ JsonNode *pNode;
+ const char *zPath;
+ u32 i;
+ int bApnd;
+ int bIsSet = *(int*)sqlite3_user_data(ctx);
+
+ if( argc<1 ) return;
+ if( (argc&1)==0 ) {
+ jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert");
+ return;
+ }
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+ assert( x.nNode );
+ for(i=1; i<(u32)argc; i+=2){
+ zPath = (const char*)sqlite3_value_text(argv[i]);
+ bApnd = 0;
+ pNode = jsonLookup(&x, zPath, &bApnd, ctx);
+ if( x.oom ){
+ sqlite3_result_error_nomem(ctx);
+ goto jsonSetDone;
+ }else if( x.nErr ){
+ goto jsonSetDone;
+ }else if( pNode && (bApnd || bIsSet) ){
+ pNode->jnFlags |= (u8)JNODE_REPLACE;
+ pNode->u.iReplace = i + 1;
+ }
+ }
+ if( x.aNode[0].jnFlags & JNODE_REPLACE ){
+ sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
+ }else{
+ jsonReturnJson(x.aNode, ctx, argv);
+ }
+jsonSetDone:
+ jsonParseReset(&x);
+}
+
+/*
+** json_type(JSON)
+** json_type(JSON, PATH)
+**
+** Return the top-level "type" of a JSON string. Throw an error if
+** either the JSON or PATH inputs are not well-formed.
+*/
+static void jsonTypeFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse *p; /* The parse */
+ const char *zPath;
+ JsonNode *pNode;
+
+ p = jsonParseCached(ctx, argv, ctx);
+ if( p==0 ) return;
+ if( argc==2 ){
+ zPath = (const char*)sqlite3_value_text(argv[1]);
+ pNode = jsonLookup(p, zPath, 0, ctx);
+ }else{
+ pNode = p->aNode;
+ }
+ if( pNode ){
+ sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC);
+ }
+}
+
+/*
+** json_valid(JSON)
+**
+** Return 1 if JSON is a well-formed JSON string according to RFC-7159.
+** Return 0 otherwise.
+*/
+static void jsonValidFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse *p; /* The parse */
+ UNUSED_PARAM(argc);
+ p = jsonParseCached(ctx, argv, 0);
+ sqlite3_result_int(ctx, p!=0);
+}
+
+
+/****************************************************************************
+** Aggregate SQL function implementations
+****************************************************************************/
+/*
+** json_group_array(VALUE)
+**
+** Return a JSON array composed of all values in the aggregate.
+*/
+static void jsonArrayStep(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonString *pStr;
+ UNUSED_PARAM(argc);
+ pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
+ if( pStr ){
+ if( pStr->zBuf==0 ){
+ jsonInit(pStr, ctx);
+ jsonAppendChar(pStr, '[');
+ }else if( pStr->nUsed>1 ){
+ jsonAppendChar(pStr, ',');
+ pStr->pCtx = ctx;
+ }
+ jsonAppendValue(pStr, argv[0]);
+ }
+}
+static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){
+ JsonString *pStr;
+ pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
+ if( pStr ){
+ pStr->pCtx = ctx;
+ jsonAppendChar(pStr, ']');
+ if( pStr->bErr ){
+ if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
+ assert( pStr->bStatic );
+ }else if( isFinal ){
+ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
+ pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
+ pStr->bStatic = 1;
+ }else{
+ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
+ pStr->nUsed--;
+ }
+ }else{
+ sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC);
+ }
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+}
+static void jsonArrayValue(sqlite3_context *ctx){
+ jsonArrayCompute(ctx, 0);
+}
+static void jsonArrayFinal(sqlite3_context *ctx){
+ jsonArrayCompute(ctx, 1);
+}
+
+#ifndef SQLITE_OMIT_WINDOWFUNC
+/*
+** This method works for both json_group_array() and json_group_object().
+** It works by removing the first element of the group by searching forward
+** to the first comma (",") that is not within a string and deleting all
+** text through that comma.
+*/
+static void jsonGroupInverse(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ unsigned int i;
+ int inStr = 0;
+ int nNest = 0;
+ char *z;
+ char c;
+ JsonString *pStr;
+ UNUSED_PARAM(argc);
+ UNUSED_PARAM(argv);
+ pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
+#ifdef NEVER
+ /* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will
+ ** always have been called to initalize it */
+ if( NEVER(!pStr) ) return;
+#endif
+ z = pStr->zBuf;
+ for(i=1; (c = z[i])!=',' || inStr || nNest; i++){
+ if( i>=pStr->nUsed ){
+ pStr->nUsed = 1;
+ return;
+ }
+ if( c=='"' ){
+ inStr = !inStr;
+ }else if( c=='\\' ){
+ i++;
+ }else if( !inStr ){
+ if( c=='{' || c=='[' ) nNest++;
+ if( c=='}' || c==']' ) nNest--;
+ }
+ }
+ pStr->nUsed -= i;
+ memmove(&z[1], &z[i+1], (size_t)pStr->nUsed-1);
+}
+#else
+# define jsonGroupInverse 0
+#endif
+
+
+/*
+** json_group_obj(NAME,VALUE)
+**
+** Return a JSON object composed of all names and values in the aggregate.
+*/
+static void jsonObjectStep(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonString *pStr;
+ const char *z;
+ u32 n;
+ UNUSED_PARAM(argc);
+ pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
+ if( pStr ){
+ if( pStr->zBuf==0 ){
+ jsonInit(pStr, ctx);
+ jsonAppendChar(pStr, '{');
+ }else if( pStr->nUsed>1 ){
+ jsonAppendChar(pStr, ',');
+ pStr->pCtx = ctx;
+ }
+ z = (const char*)sqlite3_value_text(argv[0]);
+ n = (u32)sqlite3_value_bytes(argv[0]);
+ jsonAppendString(pStr, z, n);
+ jsonAppendChar(pStr, ':');
+ jsonAppendValue(pStr, argv[1]);
+ }
+}
+static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
+ JsonString *pStr;
+ pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
+ if( pStr ){
+ jsonAppendChar(pStr, '}');
+ if( pStr->bErr ){
+ if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
+ assert( pStr->bStatic );
+ }else if( isFinal ){
+ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
+ pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
+ pStr->bStatic = 1;
+ }else{
+ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
+ pStr->nUsed--;
+ }
+ }else{
+ sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC);
+ }
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+}
+static void jsonObjectValue(sqlite3_context *ctx){
+ jsonObjectCompute(ctx, 0);
+}
+static void jsonObjectFinal(sqlite3_context *ctx){
+ jsonObjectCompute(ctx, 1);
+}
+
+
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/****************************************************************************
+** The json_each virtual table
+****************************************************************************/
+typedef struct JsonEachCursor JsonEachCursor;
+struct JsonEachCursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ u32 iRowid; /* The rowid */
+ u32 iBegin; /* The first node of the scan */
+ u32 i; /* Index in sParse.aNode[] of current row */
+ u32 iEnd; /* EOF when i equals or exceeds this value */
+ u8 eType; /* Type of top-level element */
+ u8 bRecursive; /* True for json_tree(). False for json_each() */
+ char *zJson; /* Input JSON */
+ char *zRoot; /* Path by which to filter zJson */
+ JsonParse sParse; /* Parse of the input JSON */
+};
+
+/* Constructor for the json_each virtual table */
+static int jsonEachConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ sqlite3_vtab *pNew;
+ int rc;
+
+/* Column numbers */
+#define JEACH_KEY 0
+#define JEACH_VALUE 1
+#define JEACH_TYPE 2
+#define JEACH_ATOM 3
+#define JEACH_ID 4
+#define JEACH_PARENT 5
+#define JEACH_FULLKEY 6
+#define JEACH_PATH 7
+/* The xBestIndex method assumes that the JSON and ROOT columns are
+** the last two columns in the table. Should this ever changes, be
+** sure to update the xBestIndex method. */
+#define JEACH_JSON 8
+#define JEACH_ROOT 9
+
+ UNUSED_PARAM(pzErr);
+ UNUSED_PARAM(argv);
+ UNUSED_PARAM(argc);
+ UNUSED_PARAM(pAux);
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path,"
+ "json HIDDEN,root HIDDEN)");
+ if( rc==SQLITE_OK ){
+ pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ }
+ return rc;
+}
+
+/* destructor for json_each virtual table */
+static int jsonEachDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/* constructor for a JsonEachCursor object for json_each(). */
+static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ JsonEachCursor *pCur;
+
+ UNUSED_PARAM(p);
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/* constructor for a JsonEachCursor object for json_tree(). */
+static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ int rc = jsonEachOpenEach(p, ppCursor);
+ if( rc==SQLITE_OK ){
+ JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor;
+ pCur->bRecursive = 1;
+ }
+ return rc;
+}
+
+/* Reset a JsonEachCursor back to its original state. Free any memory
+** held. */
+static void jsonEachCursorReset(JsonEachCursor *p){
+ sqlite3_free(p->zJson);
+ sqlite3_free(p->zRoot);
+ jsonParseReset(&p->sParse);
+ p->iRowid = 0;
+ p->i = 0;
+ p->iEnd = 0;
+ p->eType = 0;
+ p->zJson = 0;
+ p->zRoot = 0;
+}
+
+/* Destructor for a jsonEachCursor object */
+static int jsonEachClose(sqlite3_vtab_cursor *cur){
+ JsonEachCursor *p = (JsonEachCursor*)cur;
+ jsonEachCursorReset(p);
+ sqlite3_free(cur);
+ return SQLITE_OK;
+}
+
+/* Return TRUE if the jsonEachCursor object has been advanced off the end
+** of the JSON object */
+static int jsonEachEof(sqlite3_vtab_cursor *cur){
+ JsonEachCursor *p = (JsonEachCursor*)cur;
+ return p->i >= p->iEnd;
+}
+
+/* Advance the cursor to the next element for json_tree() */
+static int jsonEachNext(sqlite3_vtab_cursor *cur){
+ JsonEachCursor *p = (JsonEachCursor*)cur;
+ if( p->bRecursive ){
+ if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++;
+ p->i++;
+ p->iRowid++;
+ if( p->i<p->iEnd ){
+ u32 iUp = p->sParse.aUp[p->i];
+ JsonNode *pUp = &p->sParse.aNode[iUp];
+ p->eType = pUp->eType;
+ if( pUp->eType==JSON_ARRAY ){
+ if( iUp==p->i-1 ){
+ pUp->u.iKey = 0;
+ }else{
+ pUp->u.iKey++;
+ }
+ }
+ }
+ }else{
+ switch( p->eType ){
+ case JSON_ARRAY: {
+ p->i += jsonNodeSize(&p->sParse.aNode[p->i]);
+ p->iRowid++;
+ break;
+ }
+ case JSON_OBJECT: {
+ p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]);
+ p->iRowid++;
+ break;
+ }
+ default: {
+ p->i = p->iEnd;
+ break;
+ }
+ }
+ }
+ return SQLITE_OK;
+}
+
+/* Append the name of the path for element i to pStr
+*/
+static void jsonEachComputePath(
+ JsonEachCursor *p, /* The cursor */
+ JsonString *pStr, /* Write the path here */
+ u32 i /* Path to this element */
+){
+ JsonNode *pNode, *pUp;
+ u32 iUp;
+ if( i==0 ){
+ jsonAppendChar(pStr, '$');
+ return;
+ }
+ iUp = p->sParse.aUp[i];
+ jsonEachComputePath(p, pStr, iUp);
+ pNode = &p->sParse.aNode[i];
+ pUp = &p->sParse.aNode[iUp];
+ if( pUp->eType==JSON_ARRAY ){
+ jsonPrintf(30, pStr, "[%d]", pUp->u.iKey);
+ }else{
+ assert( pUp->eType==JSON_OBJECT );
+ if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--;
+ assert( pNode->eType==JSON_STRING );
+ assert( pNode->jnFlags & JNODE_LABEL );
+ jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1);
+ }
+}
+
+/* Return the value of a column */
+static int jsonEachColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ JsonEachCursor *p = (JsonEachCursor*)cur;
+ JsonNode *pThis = &p->sParse.aNode[p->i];
+ switch( i ){
+ case JEACH_KEY: {
+ if( p->i==0 ) break;
+ if( p->eType==JSON_OBJECT ){
+ jsonReturn(pThis, ctx, 0);
+ }else if( p->eType==JSON_ARRAY ){
+ u32 iKey;
+ if( p->bRecursive ){
+ if( p->iRowid==0 ) break;
+ iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey;
+ }else{
+ iKey = p->iRowid;
+ }
+ sqlite3_result_int64(ctx, (sqlite3_int64)iKey);
+ }
+ break;
+ }
+ case JEACH_VALUE: {
+ if( pThis->jnFlags & JNODE_LABEL ) pThis++;
+ jsonReturn(pThis, ctx, 0);
+ break;
+ }
+ case JEACH_TYPE: {
+ if( pThis->jnFlags & JNODE_LABEL ) pThis++;
+ sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC);
+ break;
+ }
+ case JEACH_ATOM: {
+ if( pThis->jnFlags & JNODE_LABEL ) pThis++;
+ if( pThis->eType>=JSON_ARRAY ) break;
+ jsonReturn(pThis, ctx, 0);
+ break;
+ }
+ case JEACH_ID: {
+ sqlite3_result_int64(ctx,
+ (sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0));
+ break;
+ }
+ case JEACH_PARENT: {
+ if( p->i>p->iBegin && p->bRecursive ){
+ sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]);
+ }
+ break;
+ }
+ case JEACH_FULLKEY: {
+ JsonString x;
+ jsonInit(&x, ctx);
+ if( p->bRecursive ){
+ jsonEachComputePath(p, &x, p->i);
+ }else{
+ if( p->zRoot ){
+ jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot));
+ }else{
+ jsonAppendChar(&x, '$');
+ }
+ if( p->eType==JSON_ARRAY ){
+ jsonPrintf(30, &x, "[%d]", p->iRowid);
+ }else if( p->eType==JSON_OBJECT ){
+ jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1);
+ }
+ }
+ jsonResult(&x);
+ break;
+ }
+ case JEACH_PATH: {
+ if( p->bRecursive ){
+ JsonString x;
+ jsonInit(&x, ctx);
+ jsonEachComputePath(p, &x, p->sParse.aUp[p->i]);
+ jsonResult(&x);
+ break;
+ }
+ /* For json_each() path and root are the same so fall through
+ ** into the root case */
+ }
+ default: {
+ const char *zRoot = p->zRoot;
+ if( zRoot==0 ) zRoot = "$";
+ sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
+ break;
+ }
+ case JEACH_JSON: {
+ assert( i==JEACH_JSON );
+ sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/* Return the current rowid value */
+static int jsonEachRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ JsonEachCursor *p = (JsonEachCursor*)cur;
+ *pRowid = p->iRowid;
+ return SQLITE_OK;
+}
+
+/* The query strategy is to look for an equality constraint on the json
+** column. Without such a constraint, the table cannot operate. idxNum is
+** 1 if the constraint is found, 3 if the constraint and zRoot are found,
+** and 0 otherwise.
+*/
+static int jsonEachBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int i; /* Loop counter or computed array index */
+ int aIdx[2]; /* Index of constraints for JSON and ROOT */
+ int unusableMask = 0; /* Mask of unusable JSON and ROOT constraints */
+ int idxMask = 0; /* Mask of usable == constraints JSON and ROOT */
+ const struct sqlite3_index_constraint *pConstraint;
+
+ /* This implementation assumes that JSON and ROOT are the last two
+ ** columns in the table */
+ assert( JEACH_ROOT == JEACH_JSON+1 );
+ UNUSED_PARAM(tab);
+ aIdx[0] = aIdx[1] = -1;
+ pConstraint = pIdxInfo->aConstraint;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
+ int iCol;
+ int iMask;
+ if( pConstraint->iColumn < JEACH_JSON ) continue;
+ iCol = pConstraint->iColumn - JEACH_JSON;
+ assert( iCol==0 || iCol==1 );
+ iMask = 1 << iCol;
+ if( pConstraint->usable==0 ){
+ unusableMask |= iMask;
+ }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ aIdx[iCol] = i;
+ idxMask |= iMask;
+ }
+ }
+ if( (unusableMask & ~idxMask)!=0 ){
+ /* If there are any unusable constraints on JSON or ROOT, then reject
+ ** this entire plan */
+ return SQLITE_CONSTRAINT;
+ }
+ if( aIdx[0]<0 ){
+ /* No JSON input. Leave estimatedCost at the huge value that it was
+ ** initialized to to discourage the query planner from selecting this
+ ** plan. */
+ pIdxInfo->idxNum = 0;
+ }else{
+ pIdxInfo->estimatedCost = 1.0;
+ i = aIdx[0];
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ if( aIdx[1]<0 ){
+ pIdxInfo->idxNum = 1; /* Only JSON supplied. Plan 1 */
+ }else{
+ i = aIdx[1];
+ pIdxInfo->aConstraintUsage[i].argvIndex = 2;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ pIdxInfo->idxNum = 3; /* Both JSON and ROOT are supplied. Plan 3 */
+ }
+ }
+ return SQLITE_OK;
+}
+
+/* Start a search on a new JSON string */
+static int jsonEachFilter(
+ sqlite3_vtab_cursor *cur,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ JsonEachCursor *p = (JsonEachCursor*)cur;
+ const char *z;
+ const char *zRoot = 0;
+ size_t n;
+
+ UNUSED_PARAM(idxStr);
+ UNUSED_PARAM(argc);
+ jsonEachCursorReset(p);
+ if( idxNum==0 ) return SQLITE_OK;
+ z = (const char*)sqlite3_value_text(argv[0]);
+ if( z==0 ) return SQLITE_OK;
+ n = (size_t)sqlite3_value_bytes(argv[0]);
+ p->zJson = sqlite3_malloc( n+1 );
+ if( p->zJson==0 ) return SQLITE_NOMEM;
+ memcpy(p->zJson, z, n+1);
+ if( jsonParse(&p->sParse, 0, p->zJson) ){
+ int rc = SQLITE_NOMEM;
+ if( p->sParse.oom==0 ){
+ sqlite3_free(cur->pVtab->zErrMsg);
+ cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON");
+ if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR;
+ }
+ jsonEachCursorReset(p);
+ return rc;
+ }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){
+ jsonEachCursorReset(p);
+ return SQLITE_NOMEM;
+ }else{
+ JsonNode *pNode = 0;
+ if( idxNum==3 ){
+ const char *zErr = 0;
+ zRoot = (const char*)sqlite3_value_text(argv[1]);
+ if( zRoot==0 ) return SQLITE_OK;
+ n = (size_t)sqlite3_value_bytes(argv[1]);
+ p->zRoot = sqlite3_malloc( n+1 );
+ if( p->zRoot==0 ) return SQLITE_NOMEM;
+ memcpy(p->zRoot, zRoot, n+1);
+ if( zRoot[0]!='$' ){
+ zErr = zRoot;
+ }else{
+ pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr);
+ }
+ if( zErr ){
+ sqlite3_free(cur->pVtab->zErrMsg);
+ cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr);
+ jsonEachCursorReset(p);
+ return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
+ }else if( pNode==0 ){
+ return SQLITE_OK;
+ }
+ }else{
+ pNode = p->sParse.aNode;
+ }
+ p->iBegin = p->i = (int)(pNode - p->sParse.aNode);
+ p->eType = pNode->eType;
+ if( p->eType>=JSON_ARRAY ){
+ pNode->u.iKey = 0;
+ p->iEnd = p->i + pNode->n + 1;
+ if( p->bRecursive ){
+ p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType;
+ if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){
+ p->i--;
+ }
+ }else{
+ p->i++;
+ }
+ }else{
+ p->iEnd = p->i+1;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/* The methods of the json_each virtual table */
+static const sqlite3_module jsonEachModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ jsonEachConnect, /* xConnect */
+ jsonEachBestIndex, /* xBestIndex */
+ jsonEachDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ jsonEachOpenEach, /* xOpen - open a cursor */
+ jsonEachClose, /* xClose - close a cursor */
+ jsonEachFilter, /* xFilter - configure scan constraints */
+ jsonEachNext, /* xNext - advance a cursor */
+ jsonEachEof, /* xEof - check for end of scan */
+ jsonEachColumn, /* xColumn - read data */
+ jsonEachRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
+};
+
+/* The methods of the json_tree virtual table. */
+static const sqlite3_module jsonTreeModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ jsonEachConnect, /* xConnect */
+ jsonEachBestIndex, /* xBestIndex */
+ jsonEachDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ jsonEachOpenTree, /* xOpen - open a cursor */
+ jsonEachClose, /* xClose - close a cursor */
+ jsonEachFilter, /* xFilter - configure scan constraints */
+ jsonEachNext, /* xNext - advance a cursor */
+ jsonEachEof, /* xEof - check for end of scan */
+ jsonEachColumn, /* xColumn - read data */
+ jsonEachRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
+};
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+/****************************************************************************
+** The following routines are the only publically visible identifiers in this
+** file. Call the following routines in order to register the various SQL
+** functions and the virtual table implemented by this file.
+****************************************************************************/
+
+int sqlite3Json1Init(sqlite3 *db){
+ int rc = SQLITE_OK;
+ unsigned int i;
+ static const struct {
+ const char *zName;
+ int nArg;
+ int flag;
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
+ } aFunc[] = {
+ { "json", 1, 0, jsonRemoveFunc },
+ { "json_array", -1, 0, jsonArrayFunc },
+ { "json_array_length", 1, 0, jsonArrayLengthFunc },
+ { "json_array_length", 2, 0, jsonArrayLengthFunc },
+ { "json_extract", -1, 0, jsonExtractFunc },
+ { "json_insert", -1, 0, jsonSetFunc },
+ { "json_object", -1, 0, jsonObjectFunc },
+ { "json_patch", 2, 0, jsonPatchFunc },
+ { "json_quote", 1, 0, jsonQuoteFunc },
+ { "json_remove", -1, 0, jsonRemoveFunc },
+ { "json_replace", -1, 0, jsonReplaceFunc },
+ { "json_set", -1, 1, jsonSetFunc },
+ { "json_type", 1, 0, jsonTypeFunc },
+ { "json_type", 2, 0, jsonTypeFunc },
+ { "json_valid", 1, 0, jsonValidFunc },
+
+#if SQLITE_DEBUG
+ /* DEBUG and TESTING functions */
+ { "json_parse", 1, 0, jsonParseFunc },
+ { "json_test1", 1, 0, jsonTest1Func },
+#endif
+ };
+ static const struct {
+ const char *zName;
+ int nArg;
+ void (*xStep)(sqlite3_context*,int,sqlite3_value**);
+ void (*xFinal)(sqlite3_context*);
+ void (*xValue)(sqlite3_context*);
+ } aAgg[] = {
+ { "json_group_array", 1,
+ jsonArrayStep, jsonArrayFinal, jsonArrayValue },
+ { "json_group_object", 2,
+ jsonObjectStep, jsonObjectFinal, jsonObjectValue },
+ };
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ static const struct {
+ const char *zName;
+ const sqlite3_module *pModule;
+ } aMod[] = {
+ { "json_each", &jsonEachModule },
+ { "json_tree", &jsonTreeModule },
+ };
+#endif
+ for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
+ rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
+ SQLITE_UTF8 | SQLITE_DETERMINISTIC,
+ (void*)&aFunc[i].flag,
+ aFunc[i].xFunc, 0, 0);
+ }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
+ rc = sqlite3_create_window_function(db, aAgg[i].zName, aAgg[i].nArg,
+ SQLITE_SUBTYPE | SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+ aAgg[i].xStep, aAgg[i].xFinal,
+ aAgg[i].xValue, jsonGroupInverse, 0);
+ }
+#endif
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
+ rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0);
+ }
+#endif
+ return rc;
+}
+
+
+#ifndef SQLITE_CORE
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_json_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ return sqlite3Json1Init(db);
+}
+#endif
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) */
--- origsrc/sqlite-autoconf-3300000/memstat.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/memstat.c 2019-10-08 13:42:19.152513700 +0200
@@ -0,0 +1,428 @@
+/*
+** 2018-09-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 demonstrates an eponymous virtual table that returns information
+** from sqlite3_status64() and sqlite3_db_status().
+**
+** Usage example:
+**
+** .load ./memstat
+** .mode quote
+** .header on
+** SELECT * FROM memstat;
+*/
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_MEMSTATVTAB)
+#if !defined(SQLITEINT_H)
+#include "sqlite3ext.h"
+#endif
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/* memstat_vtab is a subclass of sqlite3_vtab which will
+** serve as the underlying representation of a memstat virtual table
+*/
+typedef struct memstat_vtab memstat_vtab;
+struct memstat_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this memstat vtab */
+};
+
+/* memstat_cursor is a subclass of sqlite3_vtab_cursor which will
+** serve as the underlying representation of a cursor that scans
+** over rows of the result
+*/
+typedef struct memstat_cursor memstat_cursor;
+struct memstat_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this cursor */
+ int iRowid; /* Current row in aMemstatColumn[] */
+ int iDb; /* Which schema we are looking at */
+ int nDb; /* Number of schemas */
+ char **azDb; /* Names of all schemas */
+ sqlite3_int64 aVal[2]; /* Result values */
+};
+
+/*
+** The memstatConnect() method is invoked to create a new
+** memstat_vtab that describes the memstat virtual table.
+**
+** Think of this routine as the constructor for memstat_vtab objects.
+**
+** All this routine needs to do is:
+**
+** (1) Allocate the memstat_vtab object and initialize all fields.
+**
+** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
+** result set of queries against memstat will look like.
+*/
+static int memstatConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ memstat_vtab *pNew;
+ int rc;
+
+/* Column numbers */
+#define MSV_COLUMN_NAME 0 /* Name of quantity being measured */
+#define MSV_COLUMN_SCHEMA 1 /* schema name */
+#define MSV_COLUMN_VALUE 2 /* Current value */
+#define MSV_COLUMN_HIWTR 3 /* Highwater mark */
+
+ rc = sqlite3_declare_vtab(db,"CREATE TABLE x(name,schema,value,hiwtr)");
+ if( rc==SQLITE_OK ){
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->db = db;
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for memstat_cursor objects.
+*/
+static int memstatDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new memstat_cursor object.
+*/
+static int memstatOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ memstat_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ pCur->db = ((memstat_vtab*)p)->db;
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Clear all the schema names from a cursor
+*/
+static void memstatClearSchema(memstat_cursor *pCur){
+ int i;
+ if( pCur->azDb==0 ) return;
+ for(i=0; i<pCur->nDb; i++){
+ sqlite3_free(pCur->azDb[i]);
+ }
+ sqlite3_free(pCur->azDb);
+ pCur->azDb = 0;
+ pCur->nDb = 0;
+}
+
+/*
+** Fill in the azDb[] array for the cursor.
+*/
+static int memstatFindSchemas(memstat_cursor *pCur){
+ sqlite3_stmt *pStmt = 0;
+ int rc;
+ if( pCur->nDb ) return SQLITE_OK;
+ rc = sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pStmt, 0);
+ if( rc ){
+ sqlite3_finalize(pStmt);
+ return rc;
+ }
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ char **az, *z;
+ az = sqlite3_realloc64(pCur->azDb, sizeof(char*)*(pCur->nDb+1));
+ if( az==0 ){
+ memstatClearSchema(pCur);
+ return SQLITE_NOMEM;
+ }
+ pCur->azDb = az;
+ z = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
+ if( z==0 ){
+ memstatClearSchema(pCur);
+ return SQLITE_NOMEM;
+ }
+ pCur->azDb[pCur->nDb] = z;
+ pCur->nDb++;
+ }
+ sqlite3_finalize(pStmt);
+ return SQLITE_OK;
+}
+
+
+/*
+** Destructor for a memstat_cursor.
+*/
+static int memstatClose(sqlite3_vtab_cursor *cur){
+ memstat_cursor *pCur = (memstat_cursor*)cur;
+ memstatClearSchema(pCur);
+ sqlite3_free(cur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Allowed values for aMemstatColumn[].eType
+*/
+#define MSV_GSTAT 0 /* sqlite3_status64() information */
+#define MSV_DB 1 /* sqlite3_db_status() information */
+#define MSV_ZIPVFS 2 /* ZIPVFS file-control with 64-bit return */
+
+/*
+** An array of quantities that can be measured and reported by
+** this virtual table
+*/
+static const struct MemstatColumns {
+ const char *zName; /* Symbolic name */
+ unsigned char eType; /* Type of interface */
+ unsigned char mNull; /* Bitmask of which columns are NULL */
+ /* 2: dbname, 4: current, 8: hiwtr */
+ int eOp; /* Opcode */
+} aMemstatColumn[] = {
+ {"MEMORY_USED", MSV_GSTAT, 2, SQLITE_STATUS_MEMORY_USED },
+ {"MALLOC_SIZE", MSV_GSTAT, 6, SQLITE_STATUS_MALLOC_SIZE },
+ {"MALLOC_COUNT", MSV_GSTAT, 2, SQLITE_STATUS_MALLOC_COUNT },
+ {"PAGECACHE_USED", MSV_GSTAT, 2, SQLITE_STATUS_PAGECACHE_USED },
+ {"PAGECACHE_OVERFLOW", MSV_GSTAT, 2, SQLITE_STATUS_PAGECACHE_OVERFLOW },
+ {"PAGECACHE_SIZE", MSV_GSTAT, 6, SQLITE_STATUS_PAGECACHE_SIZE },
+ {"PARSER_STACK", MSV_GSTAT, 6, SQLITE_STATUS_PARSER_STACK },
+ {"DB_LOOKASIDE_USED", MSV_DB, 2, SQLITE_DBSTATUS_LOOKASIDE_USED },
+ {"DB_LOOKASIDE_HIT", MSV_DB, 6, SQLITE_DBSTATUS_LOOKASIDE_HIT },
+ {"DB_LOOKASIDE_MISS_SIZE", MSV_DB, 6, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE},
+ {"DB_LOOKASIDE_MISS_FULL", MSV_DB, 6, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL},
+ {"DB_CACHE_USED", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_USED },
+#if SQLITE_VERSION_NUMBER >= 3140000
+ {"DB_CACHE_USED_SHARED", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_USED_SHARED },
+#endif
+ {"DB_SCHEMA_USED", MSV_DB, 10, SQLITE_DBSTATUS_SCHEMA_USED },
+ {"DB_STMT_USED", MSV_DB, 10, SQLITE_DBSTATUS_STMT_USED },
+ {"DB_CACHE_HIT", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_HIT },
+ {"DB_CACHE_MISS", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_MISS },
+ {"DB_CACHE_WRITE", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_WRITE },
+#if SQLITE_VERSION_NUMBER >= 3230000
+ {"DB_CACHE_SPILL", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_SPILL },
+#endif
+ {"DB_DEFERRED_FKS", MSV_DB, 10, SQLITE_DBSTATUS_DEFERRED_FKS },
+#ifdef SQLITE_ENABLE_ZIPVFS
+ {"ZIPVFS_CACHE_USED", MSV_ZIPVFS, 8, 231454 },
+ {"ZIPVFS_CACHE_HIT", MSV_ZIPVFS, 8, 231455 },
+ {"ZIPVFS_CACHE_MISS", MSV_ZIPVFS, 8, 231456 },
+ {"ZIPVFS_CACHE_WRITE", MSV_ZIPVFS, 8, 231457 },
+ {"ZIPVFS_DIRECT_READ", MSV_ZIPVFS, 8, 231458 },
+ {"ZIPVFS_DIRECT_BYTES", MSV_ZIPVFS, 8, 231459 },
+#endif /* SQLITE_ENABLE_ZIPVFS */
+};
+#define MSV_NROW (sizeof(aMemstatColumn)/sizeof(aMemstatColumn[0]))
+
+/*
+** Advance a memstat_cursor to its next row of output.
+*/
+static int memstatNext(sqlite3_vtab_cursor *cur){
+ memstat_cursor *pCur = (memstat_cursor*)cur;
+ int i;
+ assert( pCur->iRowid<=MSV_NROW );
+ while(1){
+ i = (int)pCur->iRowid - 1;
+ if( i<0 || (aMemstatColumn[i].mNull & 2)!=0 || (++pCur->iDb)>=pCur->nDb ){
+ pCur->iRowid++;
+ if( pCur->iRowid>MSV_NROW ) return SQLITE_OK; /* End of the table */
+ pCur->iDb = 0;
+ i++;
+ }
+ pCur->aVal[0] = 0;
+ pCur->aVal[1] = 0;
+ switch( aMemstatColumn[i].eType ){
+ case MSV_GSTAT: {
+ if( sqlite3_libversion_number()>=3010000 ){
+ sqlite3_status64(aMemstatColumn[i].eOp,
+ &pCur->aVal[0], &pCur->aVal[1],0);
+ }else{
+ int xCur, xHiwtr;
+ sqlite3_status(aMemstatColumn[i].eOp, &xCur, &xHiwtr, 0);
+ pCur->aVal[0] = xCur;
+ pCur->aVal[1] = xHiwtr;
+ }
+ break;
+ }
+ case MSV_DB: {
+ int xCur, xHiwtr;
+ sqlite3_db_status(pCur->db, aMemstatColumn[i].eOp, &xCur, &xHiwtr, 0);
+ pCur->aVal[0] = xCur;
+ pCur->aVal[1] = xHiwtr;
+ break;
+ }
+ case MSV_ZIPVFS: {
+ int rc;
+ rc = sqlite3_file_control(pCur->db, pCur->azDb[pCur->iDb],
+ aMemstatColumn[i].eOp, (void*)&pCur->aVal[0]);
+ if( rc!=SQLITE_OK ) continue;
+ break;
+ }
+ }
+ break;
+ }
+ return SQLITE_OK;
+}
+
+
+/*
+** Return values of columns for the row at which the memstat_cursor
+** is currently pointing.
+*/
+static int memstatColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int iCol /* Which column to return */
+){
+ memstat_cursor *pCur = (memstat_cursor*)cur;
+ int i;
+ assert( pCur->iRowid>0 && pCur->iRowid<=MSV_NROW );
+ i = (int)pCur->iRowid - 1;
+ if( (aMemstatColumn[i].mNull & (1<<iCol))!=0 ){
+ return SQLITE_OK;
+ }
+ switch( iCol ){
+ case MSV_COLUMN_NAME: {
+ sqlite3_result_text(ctx, aMemstatColumn[i].zName, -1, SQLITE_STATIC);
+ break;
+ }
+ case MSV_COLUMN_SCHEMA: {
+ sqlite3_result_text(ctx, pCur->azDb[pCur->iDb], -1, 0);
+ break;
+ }
+ case MSV_COLUMN_VALUE: {
+ sqlite3_result_int64(ctx, pCur->aVal[0]);
+ break;
+ }
+ case MSV_COLUMN_HIWTR: {
+ sqlite3_result_int64(ctx, pCur->aVal[1]);
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** rowid is the same as the output value.
+*/
+static int memstatRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ memstat_cursor *pCur = (memstat_cursor*)cur;
+ *pRowid = pCur->iRowid*1000 + pCur->iDb;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int memstatEof(sqlite3_vtab_cursor *cur){
+ memstat_cursor *pCur = (memstat_cursor*)cur;
+ return pCur->iRowid>MSV_NROW;
+}
+
+/*
+** This method is called to "rewind" the memstat_cursor object back
+** to the first row of output. This method is always called at least
+** once prior to any call to memstatColumn() or memstatRowid() or
+** memstatEof().
+*/
+static int memstatFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ memstat_cursor *pCur = (memstat_cursor *)pVtabCursor;
+ int rc = memstatFindSchemas(pCur);
+ if( rc ) return rc;
+ pCur->iRowid = 0;
+ pCur->iDb = 0;
+ return memstatNext(pVtabCursor);
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the memstat virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+*/
+static int memstatBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ pIdxInfo->estimatedCost = (double)500;
+ pIdxInfo->estimatedRows = 500;
+ return SQLITE_OK;
+}
+
+/*
+** This following structure defines all the methods for the
+** memstat virtual table.
+*/
+static const sqlite3_module memstatModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ memstatConnect, /* xConnect */
+ memstatBestIndex, /* xBestIndex */
+ memstatDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ memstatOpen, /* xOpen - open a cursor */
+ memstatClose, /* xClose - close a cursor */
+ memstatFilter, /* xFilter - configure scan constraints */
+ memstatNext, /* xNext - advance a cursor */
+ memstatEof, /* xEof - check for end of scan */
+ memstatColumn, /* xColumn - read data */
+ memstatRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0, /* xShadowName */
+};
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+int sqlite3MemstatVtabInit(sqlite3 *db){
+ int rc = SQLITE_OK;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3_create_module(db, "sqlite_memstat", &memstatModule, 0);
+#endif
+ return rc;
+}
+
+#ifndef SQLITE_CORE
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_memstat_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3MemstatVtabInit(db);
+#endif
+ return rc;
+}
+#endif /* SQLITE_CORE */
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_MEMSTATVTAB) */
--- origsrc/sqlite-autoconf-3300000/memtrace.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/memtrace.c 2019-10-08 13:42:19.156431100 +0200
@@ -0,0 +1,108 @@
+/*
+** 2019-01-21
+**
+** 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 implements an extension that uses the SQLITE_CONFIG_MALLOC
+** mechanism to add a tracing layer on top of SQLite. If this extension
+** is registered prior to sqlite3_initialize(), it will cause all memory
+** allocation activities to be logged on standard output, or to some other
+** FILE specified by the initializer.
+**
+** This file needs to be compiled into the application that uses it.
+**
+** This extension is used to implement the --memtrace option of the
+** command-line shell.
+*/
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+/* The original memory allocation routines */
+static sqlite3_mem_methods memtraceBase;
+static FILE *memtraceOut;
+
+/* Methods that trace memory allocations */
+static void *memtraceMalloc(int n){
+ if( memtraceOut ){
+ fprintf(memtraceOut, "MEMTRACE: allocate %d bytes\n",
+ memtraceBase.xRoundup(n));
+ }
+ return memtraceBase.xMalloc(n);
+}
+static void memtraceFree(void *p){
+ if( p==0 ) return;
+ if( memtraceOut ){
+ fprintf(memtraceOut, "MEMTRACE: free %d bytes\n", memtraceBase.xSize(p));
+ }
+ memtraceBase.xFree(p);
+}
+static void *memtraceRealloc(void *p, int n){
+ if( p==0 ) return memtraceMalloc(n);
+ if( n==0 ){
+ memtraceFree(p);
+ return 0;
+ }
+ if( memtraceOut ){
+ fprintf(memtraceOut, "MEMTRACE: resize %d -> %d bytes\n",
+ memtraceBase.xSize(p), memtraceBase.xRoundup(n));
+ }
+ return memtraceBase.xRealloc(p, n);
+}
+static int memtraceSize(void *p){
+ return memtraceBase.xSize(p);
+}
+static int memtraceRoundup(int n){
+ return memtraceBase.xRoundup(n);
+}
+static int memtraceInit(void *p){
+ return memtraceBase.xInit(p);
+}
+static void memtraceShutdown(void *p){
+ memtraceBase.xShutdown(p);
+}
+
+/* The substitute memory allocator */
+static sqlite3_mem_methods ersaztMethods = {
+ memtraceMalloc,
+ memtraceFree,
+ memtraceRealloc,
+ memtraceSize,
+ memtraceRoundup,
+ memtraceInit,
+ memtraceShutdown,
+ 0
+};
+
+/* Begin tracing memory allocations to out. */
+int sqlite3MemTraceActivate(FILE *out){
+ int rc = SQLITE_OK;
+ if( memtraceBase.xMalloc==0 ){
+ rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memtraceBase);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &ersaztMethods);
+ }
+ }
+ memtraceOut = out;
+ return rc;
+}
+
+/* Deactivate memory tracing */
+int sqlite3MemTraceDeactivate(void){
+ int rc = SQLITE_OK;
+ if( memtraceBase.xMalloc!=0 ){
+ rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memtraceBase);
+ if( rc==SQLITE_OK ){
+ memset(&memtraceBase, 0, sizeof(memtraceBase));
+ }
+ }
+ memtraceOut = 0;
+ return rc;
+}
--- origsrc/sqlite-autoconf-3300000/memvfs.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/memvfs.c 2019-10-08 13:42:19.161300700 +0200
@@ -0,0 +1,594 @@
+/*
+** 2016-09-07
+**
+** 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 is an in-memory VFS implementation. The application supplies
+** a chunk of memory to hold the database file.
+**
+** Because there is place to store a rollback or wal journal, the database
+** must use one of journal_mode=MEMORY or journal_mode=NONE.
+**
+** USAGE:
+**
+** sqlite3_open_v2("file:/whatever?ptr=0xf05538&sz=14336&max=65536", &db,
+** SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI,
+** "memvfs");
+**
+** These are the query parameters:
+**
+** ptr= The address of the memory buffer that holds the database.
+**
+** sz= The current size the database file
+**
+** maxsz= The maximum size of the database. In other words, the
+** amount of space allocated for the ptr= buffer.
+**
+** freeonclose= If true, then sqlite3_free() is called on the ptr=
+** value when the connection closes.
+**
+** The ptr= and sz= query parameters are required. If maxsz= is omitted,
+** then it defaults to the sz= value. Parameter values can be in either
+** decimal or hexadecimal. The filename in the URI is ignored.
+*/
+#include <sqlite3ext.h>
+SQLITE_EXTENSION_INIT1
+#include <string.h>
+#include <assert.h>
+
+
+/*
+** Forward declaration of objects used by this utility
+*/
+typedef struct sqlite3_vfs MemVfs;
+typedef struct MemFile MemFile;
+
+/* Access to a lower-level VFS that (might) implement dynamic loading,
+** access to randomness, etc.
+*/
+#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
+
+/* An open file */
+struct MemFile {
+ sqlite3_file base; /* IO methods */
+ sqlite3_int64 sz; /* Size of the file */
+ sqlite3_int64 szMax; /* Space allocated to aData */
+ unsigned char *aData; /* content of the file */
+ int bFreeOnClose; /* Invoke sqlite3_free() on aData at close */
+};
+
+/*
+** Methods for MemFile
+*/
+static int memClose(sqlite3_file*);
+static int memRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
+static int memWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
+static int memTruncate(sqlite3_file*, sqlite3_int64 size);
+static int memSync(sqlite3_file*, int flags);
+static int memFileSize(sqlite3_file*, sqlite3_int64 *pSize);
+static int memLock(sqlite3_file*, int);
+static int memUnlock(sqlite3_file*, int);
+static int memCheckReservedLock(sqlite3_file*, int *pResOut);
+static int memFileControl(sqlite3_file*, int op, void *pArg);
+static int memSectorSize(sqlite3_file*);
+static int memDeviceCharacteristics(sqlite3_file*);
+static int memShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
+static int memShmLock(sqlite3_file*, int offset, int n, int flags);
+static void memShmBarrier(sqlite3_file*);
+static int memShmUnmap(sqlite3_file*, int deleteFlag);
+static int memFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
+static int memUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
+
+/*
+** Methods for MemVfs
+*/
+static int memOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
+static int memDelete(sqlite3_vfs*, const char *zName, int syncDir);
+static int memAccess(sqlite3_vfs*, const char *zName, int flags, int *);
+static int memFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
+static void *memDlOpen(sqlite3_vfs*, const char *zFilename);
+static void memDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
+static void (*memDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
+static void memDlClose(sqlite3_vfs*, void*);
+static int memRandomness(sqlite3_vfs*, int nByte, char *zOut);
+static int memSleep(sqlite3_vfs*, int microseconds);
+static int memCurrentTime(sqlite3_vfs*, double*);
+static int memGetLastError(sqlite3_vfs*, int, char *);
+static int memCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
+
+static sqlite3_vfs mem_vfs = {
+ 2, /* iVersion */
+ 0, /* szOsFile (set when registered) */
+ 1024, /* mxPathname */
+ 0, /* pNext */
+ "memvfs", /* zName */
+ 0, /* pAppData (set when registered) */
+ memOpen, /* xOpen */
+ memDelete, /* xDelete */
+ memAccess, /* xAccess */
+ memFullPathname, /* xFullPathname */
+ memDlOpen, /* xDlOpen */
+ memDlError, /* xDlError */
+ memDlSym, /* xDlSym */
+ memDlClose, /* xDlClose */
+ memRandomness, /* xRandomness */
+ memSleep, /* xSleep */
+ memCurrentTime, /* xCurrentTime */
+ memGetLastError, /* xGetLastError */
+ memCurrentTimeInt64 /* xCurrentTimeInt64 */
+};
+
+static const sqlite3_io_methods mem_io_methods = {
+ 3, /* iVersion */
+ memClose, /* xClose */
+ memRead, /* xRead */
+ memWrite, /* xWrite */
+ memTruncate, /* xTruncate */
+ memSync, /* xSync */
+ memFileSize, /* xFileSize */
+ memLock, /* xLock */
+ memUnlock, /* xUnlock */
+ memCheckReservedLock, /* xCheckReservedLock */
+ memFileControl, /* xFileControl */
+ memSectorSize, /* xSectorSize */
+ memDeviceCharacteristics, /* xDeviceCharacteristics */
+ memShmMap, /* xShmMap */
+ memShmLock, /* xShmLock */
+ memShmBarrier, /* xShmBarrier */
+ memShmUnmap, /* xShmUnmap */
+ memFetch, /* xFetch */
+ memUnfetch /* xUnfetch */
+};
+
+
+
+/*
+** Close an mem-file.
+**
+** The pData pointer is owned by the application, so there is nothing
+** to free.
+*/
+static int memClose(sqlite3_file *pFile){
+ MemFile *p = (MemFile *)pFile;
+ if( p->bFreeOnClose ) sqlite3_free(p->aData);
+ return SQLITE_OK;
+}
+
+/*
+** Read data from an mem-file.
+*/
+static int memRead(
+ sqlite3_file *pFile,
+ void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ MemFile *p = (MemFile *)pFile;
+ memcpy(zBuf, p->aData+iOfst, iAmt);
+ return SQLITE_OK;
+}
+
+/*
+** Write data to an mem-file.
+*/
+static int memWrite(
+ sqlite3_file *pFile,
+ const void *z,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ MemFile *p = (MemFile *)pFile;
+ if( iOfst+iAmt>p->sz ){
+ if( iOfst+iAmt>p->szMax ) return SQLITE_FULL;
+ if( iOfst>p->sz ) memset(p->aData+p->sz, 0, iOfst-p->sz);
+ p->sz = iOfst+iAmt;
+ }
+ memcpy(p->aData+iOfst, z, iAmt);
+ return SQLITE_OK;
+}
+
+/*
+** Truncate an mem-file.
+*/
+static int memTruncate(sqlite3_file *pFile, sqlite_int64 size){
+ MemFile *p = (MemFile *)pFile;
+ if( size>p->sz ){
+ if( size>p->szMax ) return SQLITE_FULL;
+ memset(p->aData+p->sz, 0, size-p->sz);
+ }
+ p->sz = size;
+ return SQLITE_OK;
+}
+
+/*
+** Sync an mem-file.
+*/
+static int memSync(sqlite3_file *pFile, int flags){
+ return SQLITE_OK;
+}
+
+/*
+** Return the current file-size of an mem-file.
+*/
+static int memFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
+ MemFile *p = (MemFile *)pFile;
+ *pSize = p->sz;
+ return SQLITE_OK;
+}
+
+/*
+** Lock an mem-file.
+*/
+static int memLock(sqlite3_file *pFile, int eLock){
+ return SQLITE_OK;
+}
+
+/*
+** Unlock an mem-file.
+*/
+static int memUnlock(sqlite3_file *pFile, int eLock){
+ return SQLITE_OK;
+}
+
+/*
+** Check if another file-handle holds a RESERVED lock on an mem-file.
+*/
+static int memCheckReservedLock(sqlite3_file *pFile, int *pResOut){
+ *pResOut = 0;
+ return SQLITE_OK;
+}
+
+/*
+** File control method. For custom operations on an mem-file.
+*/
+static int memFileControl(sqlite3_file *pFile, int op, void *pArg){
+ MemFile *p = (MemFile *)pFile;
+ int rc = SQLITE_NOTFOUND;
+ if( op==SQLITE_FCNTL_VFSNAME ){
+ *(char**)pArg = sqlite3_mprintf("mem(%p,%lld)", p->aData, p->sz);
+ rc = SQLITE_OK;
+ }
+ return rc;
+}
+
+/*
+** Return the sector-size in bytes for an mem-file.
+*/
+static int memSectorSize(sqlite3_file *pFile){
+ return 1024;
+}
+
+/*
+** Return the device characteristic flags supported by an mem-file.
+*/
+static int memDeviceCharacteristics(sqlite3_file *pFile){
+ return SQLITE_IOCAP_ATOMIC |
+ SQLITE_IOCAP_POWERSAFE_OVERWRITE |
+ SQLITE_IOCAP_SAFE_APPEND |
+ SQLITE_IOCAP_SEQUENTIAL;
+}
+
+/* Create a shared memory file mapping */
+static int memShmMap(
+ sqlite3_file *pFile,
+ int iPg,
+ int pgsz,
+ int bExtend,
+ void volatile **pp
+){
+ return SQLITE_IOERR_SHMMAP;
+}
+
+/* Perform locking on a shared-memory segment */
+static int memShmLock(sqlite3_file *pFile, int offset, int n, int flags){
+ return SQLITE_IOERR_SHMLOCK;
+}
+
+/* Memory barrier operation on shared memory */
+static void memShmBarrier(sqlite3_file *pFile){
+ return;
+}
+
+/* Unmap a shared memory segment */
+static int memShmUnmap(sqlite3_file *pFile, int deleteFlag){
+ return SQLITE_OK;
+}
+
+/* Fetch a page of a memory-mapped file */
+static int memFetch(
+ sqlite3_file *pFile,
+ sqlite3_int64 iOfst,
+ int iAmt,
+ void **pp
+){
+ MemFile *p = (MemFile *)pFile;
+ *pp = (void*)(p->aData + iOfst);
+ return SQLITE_OK;
+}
+
+/* Release a memory-mapped page */
+static int memUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
+ return SQLITE_OK;
+}
+
+/*
+** Open an mem file handle.
+*/
+static int memOpen(
+ sqlite3_vfs *pVfs,
+ const char *zName,
+ sqlite3_file *pFile,
+ int flags,
+ int *pOutFlags
+){
+ MemFile *p = (MemFile*)pFile;
+ memset(p, 0, sizeof(*p));
+ if( (flags & SQLITE_OPEN_MAIN_DB)==0 ) return SQLITE_CANTOPEN;
+ p->aData = (unsigned char*)(size_t)sqlite3_uri_int64(zName,"ptr",0);
+ if( p->aData==0 ) return SQLITE_CANTOPEN;
+ p->sz = sqlite3_uri_int64(zName,"sz",0);
+ if( p->sz<0 ) return SQLITE_CANTOPEN;
+ p->szMax = sqlite3_uri_int64(zName,"max",p->sz);
+ if( p->szMax<p->sz ) return SQLITE_CANTOPEN;
+ p->bFreeOnClose = sqlite3_uri_boolean(zName,"freeonclose",0);
+ pFile->pMethods = &mem_io_methods;
+ return SQLITE_OK;
+}
+
+/*
+** Delete the file located at zPath. If the dirSync argument is true,
+** ensure the file-system modifications are synced to disk before
+** returning.
+*/
+static int memDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+ return SQLITE_IOERR_DELETE;
+}
+
+/*
+** Test for access permissions. Return true if the requested permission
+** is available, or false otherwise.
+*/
+static int memAccess(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int flags,
+ int *pResOut
+){
+ *pResOut = 0;
+ return SQLITE_OK;
+}
+
+/*
+** Populate buffer zOut with the full canonical pathname corresponding
+** to the pathname in zPath. zOut is guaranteed to point to a buffer
+** of at least (INST_MAX_PATHNAME+1) bytes.
+*/
+static int memFullPathname(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int nOut,
+ char *zOut
+){
+ sqlite3_snprintf(nOut, zOut, "%s", zPath);
+ return SQLITE_OK;
+}
+
+/*
+** Open the dynamic library located at zPath and return a handle.
+*/
+static void *memDlOpen(sqlite3_vfs *pVfs, const char *zPath){
+ return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
+}
+
+/*
+** Populate the buffer zErrMsg (size nByte bytes) with a human readable
+** utf-8 string describing the most recent error encountered associated
+** with dynamic libraries.
+*/
+static void memDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
+ ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
+}
+
+/*
+** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
+*/
+static void (*memDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
+ return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
+}
+
+/*
+** Close the dynamic library handle pHandle.
+*/
+static void memDlClose(sqlite3_vfs *pVfs, void *pHandle){
+ ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
+}
+
+/*
+** Populate the buffer pointed to by zBufOut with nByte bytes of
+** random data.
+*/
+static int memRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
+ return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
+}
+
+/*
+** Sleep for nMicro microseconds. Return the number of microseconds
+** actually slept.
+*/
+static int memSleep(sqlite3_vfs *pVfs, int nMicro){
+ return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
+}
+
+/*
+** Return the current time as a Julian Day number in *pTimeOut.
+*/
+static int memCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
+ return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
+}
+
+static int memGetLastError(sqlite3_vfs *pVfs, int a, char *b){
+ return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
+}
+static int memCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
+ return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);
+}
+
+#ifdef MEMVFS_TEST
+/*
+** memvfs_from_file(FILENAME, MAXSIZE)
+**
+** This an SQL function used to help in testing the memvfs VFS. The
+** function reads the content of a file into memory and then returns
+** a URI that can be handed to ATTACH to attach the memory buffer as
+** a database. Example:
+**
+** ATTACH memvfs_from_file('test.db',1048576) AS inmem;
+**
+** The optional MAXSIZE argument gives the size of the memory allocation
+** used to hold the database. If omitted, it defaults to the size of the
+** file on disk.
+*/
+#include <stdio.h>
+static void memvfsFromFileFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ unsigned char *p;
+ size_t sz;
+ size_t szMax;
+ FILE *in;
+ const char *zFilename = (const char*)sqlite3_value_text(argv[0]);
+ char *zUri;
+
+ if( zFilename==0 ) return;
+ in = fopen(zFilename, "rb");
+ if( in==0 ) return;
+ fseek(in, 0, SEEK_END);
+ szMax = sz = ftell(in);
+ rewind(in);
+ if( argc>=2 ){
+ szMax = sqlite3_value_int64(argv[1]);
+ if( szMax<sz ) szMax = sz;
+ }
+ p = sqlite3_malloc( szMax );
+ if( p==0 ){
+ fclose(in);
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+ fread(p, sz, 1, in);
+ fclose(in);
+ zUri = sqlite3_mprintf(
+ "file:/mem?vfs=memvfs&ptr=%lld&sz=%lld&max=%lld&freeonclose=1",
+ (sqlite3_int64)p, (sqlite3_int64)sz, (sqlite3_int64)szMax);
+ sqlite3_result_text(context, zUri, -1, sqlite3_free);
+}
+#endif /* MEMVFS_TEST */
+
+#ifdef MEMVFS_TEST
+/*
+** memvfs_to_file(SCHEMA, FILENAME)
+**
+** The schema identified by SCHEMA must be a memvfs database. Write
+** the content of this database into FILENAME.
+*/
+static void memvfsToFileFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ MemFile *p = 0;
+ FILE *out;
+ int rc;
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ sqlite3_vfs *pVfs = 0;
+ const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
+ const char *zFilename = (const char*)sqlite3_value_text(argv[1]);
+
+ if( zFilename==0 ) return;
+ out = fopen(zFilename, "wb");
+ if( out==0 ) return;
+ rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_VFS_POINTER, &pVfs);
+ if( rc || pVfs==0 ) return;
+ if( strcmp(pVfs->zName,"memvfs")!=0 ) return;
+ rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p);
+ if( rc ) return;
+ fwrite(p->aData, 1, (size_t)p->sz, out);
+ fclose(out);
+}
+#endif /* MEMVFS_TEST */
+
+#ifdef MEMVFS_TEST
+/* Called for each new database connection */
+static int memvfsRegister(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const struct sqlite3_api_routines *pThunk
+){
+ sqlite3_create_function(db, "memvfs_from_file", 1, SQLITE_UTF8, 0,
+ memvfsFromFileFunc, 0, 0);
+ sqlite3_create_function(db, "memvfs_from_file", 2, SQLITE_UTF8, 0,
+ memvfsFromFileFunc, 0, 0);
+ sqlite3_create_function(db, "memvfs_to_file", 2, SQLITE_UTF8, 0,
+ memvfsToFileFunc, 0, 0);
+ return SQLITE_OK;
+}
+#endif /* MEMVFS_TEST */
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+/*
+** This routine is called when the extension is loaded.
+** Register the new VFS.
+*/
+int sqlite3_memvfs_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ mem_vfs.pAppData = sqlite3_vfs_find(0);
+ mem_vfs.szOsFile = sizeof(MemFile);
+ rc = sqlite3_vfs_register(&mem_vfs, 1);
+#ifdef MEMVFS_TEST
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_auto_extension((void(*)(void))memvfsRegister);
+ }
+ if( rc==SQLITE_OK ){
+ rc = memvfsRegister(db, pzErrMsg, pApi);
+ }
+#endif
+ if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ mem_vfs.pAppData = sqlite3_vfs_find(0);
+ mem_vfs.szOsFile = sizeof(MemFile);
+ rc = sqlite3_vfs_register(&mem_vfs, 1);
+#ifdef MEMVFS_TEST
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_auto_extension((void(*)(void))memvfsRegister);
+ }
+#endif
+ if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
+ return rc;
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/mmapwarm.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/mmapwarm.c 2019-10-08 13:42:19.165219200 +0200
@@ -0,0 +1,107 @@
+/*
+** 2017-09-18
+**
+** 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.
+**
+*************************************************************************
+**
+*/
+
+#include "sqlite3.h"
+
+
+/*
+** This function is used to touch each page of a mapping of a memory
+** mapped SQLite database. Assuming that the system has sufficient free
+** memory and supports sufficiently large mappings, this causes the OS
+** to cache the entire database in main memory, making subsequent
+** database accesses faster.
+**
+** If the second parameter to this function is not NULL, it is the name of
+** the specific database to operate on (i.e. "main" or the name of an
+** attached database).
+**
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
+** It is not considered an error if the file is not memory-mapped, or if
+** the mapping does not span the entire file. If an error does occur, a
+** transaction may be left open on the database file.
+**
+** It is illegal to call this function when the database handle has an
+** open transaction. SQLITE_MISUSE is returned in this case.
+*/
+int sqlite3_mmap_warm(sqlite3 *db, const char *zDb){
+ int rc = SQLITE_OK;
+ char *zSql = 0;
+ int pgsz = 0;
+ int nTotal = 0;
+
+ if( 0==sqlite3_get_autocommit(db) ) return SQLITE_MISUSE;
+
+ /* Open a read-only transaction on the file in question */
+ zSql = sqlite3_mprintf("BEGIN; SELECT * FROM %s%q%ssqlite_master",
+ (zDb ? "'" : ""), (zDb ? zDb : ""), (zDb ? "'." : "")
+ );
+ if( zSql==0 ) return SQLITE_NOMEM;
+ rc = sqlite3_exec(db, zSql, 0, 0, 0);
+ sqlite3_free(zSql);
+
+ /* Find the SQLite page size of the file */
+ if( rc==SQLITE_OK ){
+ zSql = sqlite3_mprintf("PRAGMA %s%q%spage_size",
+ (zDb ? "'" : ""), (zDb ? zDb : ""), (zDb ? "'." : "")
+ );
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ sqlite3_stmt *pPgsz = 0;
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pPgsz, 0);
+ sqlite3_free(zSql);
+ if( rc==SQLITE_OK ){
+ if( sqlite3_step(pPgsz)==SQLITE_ROW ){
+ pgsz = sqlite3_column_int(pPgsz, 0);
+ }
+ rc = sqlite3_finalize(pPgsz);
+ }
+ if( rc==SQLITE_OK && pgsz==0 ){
+ rc = SQLITE_ERROR;
+ }
+ }
+ }
+
+ /* Touch each mmap'd page of the file */
+ if( rc==SQLITE_OK ){
+ int rc2;
+ sqlite3_file *pFd = 0;
+ rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFd);
+ if( rc==SQLITE_OK && pFd->pMethods->iVersion>=3 ){
+ sqlite3_int64 iPg = 1;
+ sqlite3_io_methods const *p = pFd->pMethods;
+ while( 1 ){
+ unsigned char *pMap;
+ rc = p->xFetch(pFd, pgsz*iPg, pgsz, (void**)&pMap);
+ if( rc!=SQLITE_OK || pMap==0 ) break;
+
+ nTotal += pMap[0];
+ nTotal += pMap[pgsz-1];
+
+ rc = p->xUnfetch(pFd, pgsz*iPg, (void*)pMap);
+ if( rc!=SQLITE_OK ) break;
+ iPg++;
+ }
+ sqlite3_log(SQLITE_OK,
+ "sqlite3_mmap_warm_cache: Warmed up %d pages of %s", iPg==1?0:iPg,
+ sqlite3_db_filename(db, zDb)
+ );
+ }
+
+ rc2 = sqlite3_exec(db, "END", 0, 0, 0);
+ if( rc==SQLITE_OK ) rc = rc2;
+ }
+
+ return rc;
+}
--- origsrc/sqlite-autoconf-3300000/nextchar.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/nextchar.c 2019-10-08 13:42:19.170087700 +0200
@@ -0,0 +1,333 @@
+/*
+** 2013-02-28
+**
+** 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 code to implement the next_char(A,T,F,W,C) SQL function.
+**
+** The next_char(A,T,F,W,C) function finds all valid "next" characters for
+** string A given the vocabulary in T.F. If the W value exists and is a
+** non-empty string, then it is an SQL expression that limits the entries
+** in T.F that will be considered. If C exists and is a non-empty string,
+** then it is the name of the collating sequence to use for comparison. If
+**
+** Only the first three arguments are required. If the C parameter is
+** omitted or is NULL or is an empty string, then the default collating
+** sequence of T.F is used for comparision. If the W parameter is omitted
+** or is NULL or is an empty string, then no filtering of the output is
+** done.
+**
+** The T.F column should be indexed using collation C or else this routine
+** will be quite slow.
+**
+** For example, suppose an application has a dictionary like this:
+**
+** CREATE TABLE dictionary(word TEXT UNIQUE);
+**
+** Further suppose that for user keypad entry, it is desired to disable
+** (gray out) keys that are not valid as the next character. If the
+** the user has previously entered (say) 'cha' then to find all allowed
+** next characters (and thereby determine when keys should not be grayed
+** out) run the following query:
+**
+** SELECT next_char('cha','dictionary','word');
+**
+** IMPLEMENTATION NOTES:
+**
+** The next_char function is implemented using recursive SQL that makes
+** use of the table name and column name as part of a query. If either
+** the table name or column name are keywords or contain special characters,
+** then they should be escaped. For example:
+**
+** SELECT next_char('cha','[dictionary]','[word]');
+**
+** This also means that the table name can be a subquery:
+**
+** SELECT next_char('cha','(SELECT word AS w FROM dictionary)','w');
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <string.h>
+
+/*
+** A structure to hold context of the next_char() computation across
+** nested function calls.
+*/
+typedef struct nextCharContext nextCharContext;
+struct nextCharContext {
+ sqlite3 *db; /* Database connection */
+ sqlite3_stmt *pStmt; /* Prepared statement used to query */
+ const unsigned char *zPrefix; /* Prefix to scan */
+ int nPrefix; /* Size of zPrefix in bytes */
+ int nAlloc; /* Space allocated to aResult */
+ int nUsed; /* Space used in aResult */
+ unsigned int *aResult; /* Array of next characters */
+ int mallocFailed; /* True if malloc fails */
+ int otherError; /* True for any other failure */
+};
+
+/*
+** Append a result character if the character is not already in the
+** result.
+*/
+static void nextCharAppend(nextCharContext *p, unsigned c){
+ int i;
+ for(i=0; i<p->nUsed; i++){
+ if( p->aResult[i]==c ) return;
+ }
+ if( p->nUsed+1 > p->nAlloc ){
+ unsigned int *aNew;
+ int n = p->nAlloc*2 + 30;
+ aNew = sqlite3_realloc64(p->aResult, n*sizeof(unsigned int));
+ if( aNew==0 ){
+ p->mallocFailed = 1;
+ return;
+ }else{
+ p->aResult = aNew;
+ p->nAlloc = n;
+ }
+ }
+ p->aResult[p->nUsed++] = c;
+}
+
+/*
+** Write a character into z[] as UTF8. Return the number of bytes needed
+** to hold the character
+*/
+static int writeUtf8(unsigned char *z, unsigned c){
+ if( c<0x00080 ){
+ z[0] = (unsigned char)(c&0xff);
+ return 1;
+ }
+ if( c<0x00800 ){
+ z[0] = 0xC0 + (unsigned char)((c>>6)&0x1F);
+ z[1] = 0x80 + (unsigned char)(c & 0x3F);
+ return 2;
+ }
+ if( c<0x10000 ){
+ z[0] = 0xE0 + (unsigned char)((c>>12)&0x0F);
+ z[1] = 0x80 + (unsigned char)((c>>6) & 0x3F);
+ z[2] = 0x80 + (unsigned char)(c & 0x3F);
+ return 3;
+ }
+ z[0] = 0xF0 + (unsigned char)((c>>18) & 0x07);
+ z[1] = 0x80 + (unsigned char)((c>>12) & 0x3F);
+ z[2] = 0x80 + (unsigned char)((c>>6) & 0x3F);
+ z[3] = 0x80 + (unsigned char)(c & 0x3F);
+ return 4;
+}
+
+/*
+** Read a UTF8 character out of z[] and write it into *pOut. Return
+** the number of bytes in z[] that were used to construct the character.
+*/
+static int readUtf8(const unsigned char *z, unsigned *pOut){
+ static const unsigned char validBits[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
+ };
+ unsigned c = z[0];
+ if( c<0xc0 ){
+ *pOut = c;
+ return 1;
+ }else{
+ int n = 1;
+ c = validBits[c-0xc0];
+ while( (z[n] & 0xc0)==0x80 ){
+ c = (c<<6) + (0x3f & z[n++]);
+ }
+ if( c<0x80 || (c&0xFFFFF800)==0xD800 || (c&0xFFFFFFFE)==0xFFFE ){
+ c = 0xFFFD;
+ }
+ *pOut = c;
+ return n;
+ }
+}
+
+/*
+** The nextCharContext structure has been set up. Add all "next" characters
+** to the result set.
+*/
+static void findNextChars(nextCharContext *p){
+ unsigned cPrev = 0;
+ unsigned char zPrev[8];
+ int n, rc;
+
+ for(;;){
+ sqlite3_bind_text(p->pStmt, 1, (char*)p->zPrefix, p->nPrefix,
+ SQLITE_STATIC);
+ n = writeUtf8(zPrev, cPrev+1);
+ sqlite3_bind_text(p->pStmt, 2, (char*)zPrev, n, SQLITE_STATIC);
+ rc = sqlite3_step(p->pStmt);
+ if( rc==SQLITE_DONE ){
+ sqlite3_reset(p->pStmt);
+ return;
+ }else if( rc!=SQLITE_ROW ){
+ p->otherError = rc;
+ return;
+ }else{
+ const unsigned char *zOut = sqlite3_column_text(p->pStmt, 0);
+ unsigned cNext;
+ n = readUtf8(zOut+p->nPrefix, &cNext);
+ sqlite3_reset(p->pStmt);
+ nextCharAppend(p, cNext);
+ cPrev = cNext;
+ if( p->mallocFailed ) return;
+ }
+ }
+}
+
+
+/*
+** next_character(A,T,F,W)
+**
+** Return a string composted of all next possible characters after
+** A for elements of T.F. If W is supplied, then it is an SQL expression
+** that limits the elements in T.F that are considered.
+*/
+static void nextCharFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ nextCharContext c;
+ const unsigned char *zTable = sqlite3_value_text(argv[1]);
+ const unsigned char *zField = sqlite3_value_text(argv[2]);
+ const unsigned char *zWhere;
+ const unsigned char *zCollName;
+ char *zWhereClause = 0;
+ char *zColl = 0;
+ char *zSql;
+ int rc;
+
+ memset(&c, 0, sizeof(c));
+ c.db = sqlite3_context_db_handle(context);
+ c.zPrefix = sqlite3_value_text(argv[0]);
+ c.nPrefix = sqlite3_value_bytes(argv[0]);
+ if( zTable==0 || zField==0 || c.zPrefix==0 ) return;
+ if( argc>=4
+ && (zWhere = sqlite3_value_text(argv[3]))!=0
+ && zWhere[0]!=0
+ ){
+ zWhereClause = sqlite3_mprintf("AND (%s)", zWhere);
+ if( zWhereClause==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+ }else{
+ zWhereClause = "";
+ }
+ if( argc>=5
+ && (zCollName = sqlite3_value_text(argv[4]))!=0
+ && zCollName[0]!=0
+ ){
+ zColl = sqlite3_mprintf("collate \"%w\"", zCollName);
+ if( zColl==0 ){
+ sqlite3_result_error_nomem(context);
+ if( zWhereClause[0] ) sqlite3_free(zWhereClause);
+ return;
+ }
+ }else{
+ zColl = "";
+ }
+ zSql = sqlite3_mprintf(
+ "SELECT %s FROM %s"
+ " WHERE %s>=(?1 || ?2) %s"
+ " AND %s<=(?1 || char(1114111)) %s" /* 1114111 == 0x10ffff */
+ " %s"
+ " ORDER BY 1 %s ASC LIMIT 1",
+ zField, zTable, zField, zColl, zField, zColl, zWhereClause, zColl
+ );
+ if( zWhereClause[0] ) sqlite3_free(zWhereClause);
+ if( zColl[0] ) sqlite3_free(zColl);
+ if( zSql==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+
+ rc = sqlite3_prepare_v2(c.db, zSql, -1, &c.pStmt, 0);
+ sqlite3_free(zSql);
+ if( rc ){
+ sqlite3_result_error(context, sqlite3_errmsg(c.db), -1);
+ return;
+ }
+ findNextChars(&c);
+ if( c.mallocFailed ){
+ sqlite3_result_error_nomem(context);
+ }else{
+ unsigned char *pRes;
+ pRes = sqlite3_malloc( c.nUsed*4 + 1 );
+ if( pRes==0 ){
+ sqlite3_result_error_nomem(context);
+ }else{
+ int i;
+ int n = 0;
+ for(i=0; i<c.nUsed; i++){
+ n += writeUtf8(pRes+n, c.aResult[i]);
+ }
+ pRes[n] = 0;
+ sqlite3_result_text(context, (const char*)pRes, n, sqlite3_free);
+ }
+ }
+ sqlite3_finalize(c.pStmt);
+ sqlite3_free(c.aResult);
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_nextchar_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "next_char", 3, SQLITE_UTF8, 0,
+ nextCharFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "next_char", 4, SQLITE_UTF8, 0,
+ nextCharFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "next_char", 5, SQLITE_UTF8, 0,
+ nextCharFunc, 0, 0);
+ }
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "next_char", 3, SQLITE_UTF8, 0,
+ nextCharFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "next_char", 4, SQLITE_UTF8, 0,
+ nextCharFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "next_char", 5, SQLITE_UTF8, 0,
+ nextCharFunc, 0, 0);
+ }
+ return rc;
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/normalize.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/normalize.c 2019-10-08 13:42:19.174969200 +0200
@@ -0,0 +1,707 @@
+/*
+** 2018-01-08
+**
+** 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 code to implement the sqlite3_normalize() function.
+**
+** char *sqlite3_normalize(const char *zSql);
+**
+** This function takes an SQL string as input and returns a "normalized"
+** version of that string in memory obtained from sqlite3_malloc64(). The
+** caller is responsible for ensuring that the returned memory is freed.
+**
+** If a memory allocation error occurs, this routine returns NULL.
+**
+** The normalization consists of the following transformations:
+**
+** (1) Convert every literal (string, blob literal, numeric constant,
+** or "NULL" constant) into a ?
+**
+** (2) Remove all superfluous whitespace, including comments. Change
+** all required whitespace to a single space character.
+**
+** (3) Lowercase all ASCII characters.
+**
+** (4) If an IN or NOT IN operator is followed by a list of 1 or more
+** values, convert that list into "(?,?,?)".
+**
+** The purpose of normalization is two-fold:
+**
+** (1) Sanitize queries by removing potentially private or sensitive
+** information contained in literals.
+**
+** (2) Identify structurally identical queries by comparing their
+** normalized forms.
+**
+** Command-Line Utility
+** --------------------
+**
+** This file also contains code for a command-line utility that converts
+** SQL queries in text files into their normalized forms. To build the
+** command-line program, compile this file with -DSQLITE_NORMALIZE_CLI
+** and link it against the SQLite library.
+*/
+#include <sqlite3.h>
+#include <string.h>
+
+/*
+** Implementation note:
+**
+** Much of the tokenizer logic is copied out of the tokenize.c source file
+** of SQLite. That logic could be simplified for this particular application,
+** but that would impose a risk of introducing subtle errors. It is best to
+** keep the code as close to the original as possible.
+**
+** The tokenize code is in sync with the SQLite core as of 2018-01-08.
+** Any future changes to the core tokenizer might require corresponding
+** adjustments to the tokenizer logic in this module.
+*/
+
+
+/* Character classes for tokenizing
+**
+** In the sqlite3GetToken() function, a switch() on aiClass[c] is implemented
+** using a lookup table, whereas a switch() directly on c uses a binary search.
+** The lookup table is much faster. To maximize speed, and to ensure that
+** a lookup table is used, all of the classes need to be small integers and
+** all of them need to be used within the switch.
+*/
+#define CC_X 0 /* The letter 'x', or start of BLOB literal */
+#define CC_KYWD 1 /* Alphabetics or '_'. Usable in a keyword */
+#define CC_ID 2 /* unicode characters usable in IDs */
+#define CC_DIGIT 3 /* Digits */
+#define CC_DOLLAR 4 /* '$' */
+#define CC_VARALPHA 5 /* '@', '#', ':'. Alphabetic SQL variables */
+#define CC_VARNUM 6 /* '?'. Numeric SQL variables */
+#define CC_SPACE 7 /* Space characters */
+#define CC_QUOTE 8 /* '"', '\'', or '`'. String literals, quoted ids */
+#define CC_QUOTE2 9 /* '['. [...] style quoted ids */
+#define CC_PIPE 10 /* '|'. Bitwise OR or concatenate */
+#define CC_MINUS 11 /* '-'. Minus or SQL-style comment */
+#define CC_LT 12 /* '<'. Part of < or <= or <> */
+#define CC_GT 13 /* '>'. Part of > or >= */
+#define CC_EQ 14 /* '='. Part of = or == */
+#define CC_BANG 15 /* '!'. Part of != */
+#define CC_SLASH 16 /* '/'. / or c-style comment */
+#define CC_LP 17 /* '(' */
+#define CC_RP 18 /* ')' */
+#define CC_SEMI 19 /* ';' */
+#define CC_PLUS 20 /* '+' */
+#define CC_STAR 21 /* '*' */
+#define CC_PERCENT 22 /* '%' */
+#define CC_COMMA 23 /* ',' */
+#define CC_AND 24 /* '&' */
+#define CC_TILDA 25 /* '~' */
+#define CC_DOT 26 /* '.' */
+#define CC_ILLEGAL 27 /* Illegal character */
+
+static const unsigned char aiClass[] = {
+/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */
+/* 0x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 27, 7, 7, 27, 27,
+/* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+/* 2x */ 7, 15, 8, 5, 4, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16,
+/* 3x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 19, 12, 14, 13, 6,
+/* 4x */ 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 9, 27, 27, 27, 1,
+/* 6x */ 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 7x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 27, 10, 27, 25, 27,
+/* 8x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+/* 9x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+/* Ax */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+/* Bx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+/* Cx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+/* Dx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+/* Ex */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+/* Fx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
+};
+
+/* An array to map all upper-case characters into their corresponding
+** lower-case character.
+**
+** SQLite only considers US-ASCII (or EBCDIC) characters. We do not
+** handle case conversions for the UTF character set since the tables
+** involved are nearly as big or bigger than SQLite itself.
+*/
+static const unsigned char sqlite3UpperToLower[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
+ 104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
+ 122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
+ 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
+ 126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+ 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
+ 162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
+ 180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
+ 198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
+ 216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
+ 234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
+ 252,253,254,255
+};
+
+/*
+** The following 256 byte lookup table is used to support SQLites built-in
+** equivalents to the following standard library functions:
+**
+** isspace() 0x01
+** isalpha() 0x02
+** isdigit() 0x04
+** isalnum() 0x06
+** isxdigit() 0x08
+** toupper() 0x20
+** SQLite identifier character 0x40
+** Quote character 0x80
+**
+** Bit 0x20 is set if the mapped character requires translation to upper
+** case. i.e. if the character is a lower-case ASCII character.
+** If x is a lower-case ASCII character, then its upper-case equivalent
+** is (x - 0x20). Therefore toupper() can be implemented as:
+**
+** (x & ~(map[x]&0x20))
+**
+** The equivalent of tolower() is implemented using the sqlite3UpperToLower[]
+** array. tolower() is used more often than toupper() by SQLite.
+**
+** Bit 0x40 is set if the character is non-alphanumeric and can be used in an
+** SQLite identifier. Identifiers are alphanumerics, "_", "$", and any
+** non-ASCII UTF character. Hence the test for whether or not a character is
+** part of an identifier is 0x46.
+*/
+static const unsigned char sqlite3CtypeMap[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00..07 ........ */
+ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10..17 ........ */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18..1f ........ */
+ 0x01, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x80, /* 20..27 !"#$%&' */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28..2f ()*+,-./ */
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, /* 30..37 01234567 */
+ 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38..3f 89:;<=>? */
+
+ 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02, /* 40..47 @ABCDEFG */
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 48..4f HIJKLMNO */
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 50..57 PQRSTUVW */
+ 0x02, 0x02, 0x02, 0x80, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */
+ 0x80, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 68..6f hijklmno */
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 70..77 pqrstuvw */
+ 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, /* 78..7f xyz{|}~. */
+
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 80..87 ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 88..8f ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 90..97 ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 98..9f ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a0..a7 ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a8..af ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b0..b7 ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b8..bf ........ */
+
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c0..c7 ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c8..cf ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d0..d7 ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d8..df ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e0..e7 ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e8..ef ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */
+};
+#define sqlite3Toupper(x) ((x)&~(sqlite3CtypeMap[(unsigned char)(x)]&0x20))
+#define sqlite3Isspace(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x01)
+#define sqlite3Isalnum(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x06)
+#define sqlite3Isalpha(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x02)
+#define sqlite3Isdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x04)
+#define sqlite3Isxdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x08)
+#define sqlite3Tolower(x) (sqlite3UpperToLower[(unsigned char)(x)])
+#define sqlite3Isquote(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x80)
+
+
+/*
+** If X is a character that can be used in an identifier then
+** IdChar(X) will be true. Otherwise it is false.
+**
+** For ASCII, any character with the high-order bit set is
+** allowed in an identifier. For 7-bit characters,
+** sqlite3IsIdChar[X] must be 1.
+**
+** For EBCDIC, the rules are more complex but have the same
+** end result.
+**
+** Ticket #1066. the SQL standard does not allow '$' in the
+** middle of identifiers. But many SQL implementations do.
+** SQLite will allow '$' in identifiers for compatibility.
+** But the feature is undocumented.
+*/
+#define IdChar(C) ((sqlite3CtypeMap[(unsigned char)C]&0x46)!=0)
+
+/*
+** Ignore testcase() macros
+*/
+#define testcase(X)
+
+/*
+** Token values
+*/
+#define TK_SPACE 0
+#define TK_NAME 1
+#define TK_LITERAL 2
+#define TK_PUNCT 3
+#define TK_ERROR 4
+
+#define TK_MINUS TK_PUNCT
+#define TK_LP TK_PUNCT
+#define TK_RP TK_PUNCT
+#define TK_SEMI TK_PUNCT
+#define TK_PLUS TK_PUNCT
+#define TK_STAR TK_PUNCT
+#define TK_SLASH TK_PUNCT
+#define TK_REM TK_PUNCT
+#define TK_EQ TK_PUNCT
+#define TK_LE TK_PUNCT
+#define TK_NE TK_PUNCT
+#define TK_LSHIFT TK_PUNCT
+#define TK_LT TK_PUNCT
+#define TK_GE TK_PUNCT
+#define TK_RSHIFT TK_PUNCT
+#define TK_GT TK_PUNCT
+#define TK_GE TK_PUNCT
+#define TK_BITOR TK_PUNCT
+#define TK_CONCAT TK_PUNCT
+#define TK_COMMA TK_PUNCT
+#define TK_BITAND TK_PUNCT
+#define TK_BITNOT TK_PUNCT
+#define TK_STRING TK_LITERAL
+#define TK_ID TK_NAME
+#define TK_ILLEGAL TK_ERROR
+#define TK_DOT TK_PUNCT
+#define TK_INTEGER TK_LITERAL
+#define TK_FLOAT TK_LITERAL
+#define TK_VARIABLE TK_LITERAL
+#define TK_BLOB TK_LITERAL
+
+/*
+** Return the length (in bytes) of the token that begins at z[0].
+** Store the token type in *tokenType before returning.
+*/
+static int sqlite3GetToken(const unsigned char *z, int *tokenType){
+ int i, c;
+ switch( aiClass[*z] ){ /* Switch on the character-class of the first byte
+ ** of the token. See the comment on the CC_ defines
+ ** above. */
+ case CC_SPACE: {
+ for(i=1; sqlite3Isspace(z[i]); i++){}
+ *tokenType = TK_SPACE;
+ return i;
+ }
+ case CC_MINUS: {
+ if( z[1]=='-' ){
+ for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
+ *tokenType = TK_SPACE;
+ return i;
+ }
+ *tokenType = TK_MINUS;
+ return 1;
+ }
+ case CC_LP: {
+ *tokenType = TK_LP;
+ return 1;
+ }
+ case CC_RP: {
+ *tokenType = TK_RP;
+ return 1;
+ }
+ case CC_SEMI: {
+ *tokenType = TK_SEMI;
+ return 1;
+ }
+ case CC_PLUS: {
+ *tokenType = TK_PLUS;
+ return 1;
+ }
+ case CC_STAR: {
+ *tokenType = TK_STAR;
+ return 1;
+ }
+ case CC_SLASH: {
+ if( z[1]!='*' || z[2]==0 ){
+ *tokenType = TK_SLASH;
+ return 1;
+ }
+ for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){}
+ if( c ) i++;
+ *tokenType = TK_SPACE;
+ return i;
+ }
+ case CC_PERCENT: {
+ *tokenType = TK_REM;
+ return 1;
+ }
+ case CC_EQ: {
+ *tokenType = TK_EQ;
+ return 1 + (z[1]=='=');
+ }
+ case CC_LT: {
+ if( (c=z[1])=='=' ){
+ *tokenType = TK_LE;
+ return 2;
+ }else if( c=='>' ){
+ *tokenType = TK_NE;
+ return 2;
+ }else if( c=='<' ){
+ *tokenType = TK_LSHIFT;
+ return 2;
+ }else{
+ *tokenType = TK_LT;
+ return 1;
+ }
+ }
+ case CC_GT: {
+ if( (c=z[1])=='=' ){
+ *tokenType = TK_GE;
+ return 2;
+ }else if( c=='>' ){
+ *tokenType = TK_RSHIFT;
+ return 2;
+ }else{
+ *tokenType = TK_GT;
+ return 1;
+ }
+ }
+ case CC_BANG: {
+ if( z[1]!='=' ){
+ *tokenType = TK_ILLEGAL;
+ return 1;
+ }else{
+ *tokenType = TK_NE;
+ return 2;
+ }
+ }
+ case CC_PIPE: {
+ if( z[1]!='|' ){
+ *tokenType = TK_BITOR;
+ return 1;
+ }else{
+ *tokenType = TK_CONCAT;
+ return 2;
+ }
+ }
+ case CC_COMMA: {
+ *tokenType = TK_COMMA;
+ return 1;
+ }
+ case CC_AND: {
+ *tokenType = TK_BITAND;
+ return 1;
+ }
+ case CC_TILDA: {
+ *tokenType = TK_BITNOT;
+ return 1;
+ }
+ case CC_QUOTE: {
+ int delim = z[0];
+ testcase( delim=='`' );
+ testcase( delim=='\'' );
+ testcase( delim=='"' );
+ for(i=1; (c=z[i])!=0; i++){
+ if( c==delim ){
+ if( z[i+1]==delim ){
+ i++;
+ }else{
+ break;
+ }
+ }
+ }
+ if( c=='\'' ){
+ *tokenType = TK_STRING;
+ return i+1;
+ }else if( c!=0 ){
+ *tokenType = TK_ID;
+ return i+1;
+ }else{
+ *tokenType = TK_ILLEGAL;
+ return i;
+ }
+ }
+ case CC_DOT: {
+ if( !sqlite3Isdigit(z[1]) ){
+ *tokenType = TK_DOT;
+ return 1;
+ }
+ /* If the next character is a digit, this is a floating point
+ ** number that begins with ".". Fall thru into the next case */
+ }
+ case CC_DIGIT: {
+ *tokenType = TK_INTEGER;
+ if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){
+ for(i=3; sqlite3Isxdigit(z[i]); i++){}
+ return i;
+ }
+ for(i=0; sqlite3Isdigit(z[i]); i++){}
+ if( z[i]=='.' ){
+ i++;
+ while( sqlite3Isdigit(z[i]) ){ i++; }
+ *tokenType = TK_FLOAT;
+ }
+ if( (z[i]=='e' || z[i]=='E') &&
+ ( sqlite3Isdigit(z[i+1])
+ || ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2]))
+ )
+ ){
+ i += 2;
+ while( sqlite3Isdigit(z[i]) ){ i++; }
+ *tokenType = TK_FLOAT;
+ }
+ while( IdChar(z[i]) ){
+ *tokenType = TK_ILLEGAL;
+ i++;
+ }
+ return i;
+ }
+ case CC_QUOTE2: {
+ for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){}
+ *tokenType = c==']' ? TK_ID : TK_ILLEGAL;
+ return i;
+ }
+ case CC_VARNUM: {
+ *tokenType = TK_VARIABLE;
+ for(i=1; sqlite3Isdigit(z[i]); i++){}
+ return i;
+ }
+ case CC_DOLLAR:
+ case CC_VARALPHA: {
+ int n = 0;
+ testcase( z[0]=='$' ); testcase( z[0]=='@' );
+ testcase( z[0]==':' ); testcase( z[0]=='#' );
+ *tokenType = TK_VARIABLE;
+ for(i=1; (c=z[i])!=0; i++){
+ if( IdChar(c) ){
+ n++;
+ }else if( c=='(' && n>0 ){
+ do{
+ i++;
+ }while( (c=z[i])!=0 && !sqlite3Isspace(c) && c!=')' );
+ if( c==')' ){
+ i++;
+ }else{
+ *tokenType = TK_ILLEGAL;
+ }
+ break;
+ }else if( c==':' && z[i+1]==':' ){
+ i++;
+ }else{
+ break;
+ }
+ }
+ if( n==0 ) *tokenType = TK_ILLEGAL;
+ return i;
+ }
+ case CC_KYWD: {
+ for(i=1; aiClass[z[i]]<=CC_KYWD; i++){}
+ if( IdChar(z[i]) ){
+ /* This token started out using characters that can appear in keywords,
+ ** but z[i] is a character not allowed within keywords, so this must
+ ** be an identifier instead */
+ i++;
+ break;
+ }
+ *tokenType = TK_ID;
+ return i;
+ }
+ case CC_X: {
+ testcase( z[0]=='x' ); testcase( z[0]=='X' );
+ if( z[1]=='\'' ){
+ *tokenType = TK_BLOB;
+ for(i=2; sqlite3Isxdigit(z[i]); i++){}
+ if( z[i]!='\'' || i%2 ){
+ *tokenType = TK_ILLEGAL;
+ while( z[i] && z[i]!='\'' ){ i++; }
+ }
+ if( z[i] ) i++;
+ return i;
+ }
+ /* If it is not a BLOB literal, then it must be an ID, since no
+ ** SQL keywords start with the letter 'x'. Fall through */
+ }
+ case CC_ID: {
+ i = 1;
+ break;
+ }
+ default: {
+ *tokenType = TK_ILLEGAL;
+ return 1;
+ }
+ }
+ while( IdChar(z[i]) ){ i++; }
+ *tokenType = TK_ID;
+ return i;
+}
+
+char *sqlite3_normalize(const char *zSql){
+ char *z; /* The output string */
+ size_t nZ; /* Size of the output string in bytes */
+ size_t nSql; /* Size of the input string in bytes */
+ int i; /* Next character to read from zSql[] */
+ int j; /* Next slot to fill in on z[] */
+ int tokenType; /* Type of the next token */
+ int n; /* Size of the next token */
+ int k; /* Loop counter */
+
+ nSql = strlen(zSql);
+ nZ = nSql;
+ z = sqlite3_malloc( nZ+2 );
+ if( z==0 ) return 0;
+ for(i=j=0; zSql[i]; i += n){
+ n = sqlite3GetToken((unsigned char*)zSql+i, &tokenType);
+ switch( tokenType ){
+ case TK_SPACE: {
+ break;
+ }
+ case TK_ERROR: {
+ sqlite3_free(z);
+ return 0;
+ }
+ case TK_LITERAL: {
+ z[j++] = '?';
+ break;
+ }
+ case TK_PUNCT:
+ case TK_NAME: {
+ if( n==4 && sqlite3_strnicmp(zSql+i,"NULL",4)==0 ){
+ if( (j>=3 && strncmp(z+j-2,"is",2)==0 && !IdChar(z[j-3]))
+ || (j>=4 && strncmp(z+j-3,"not",3)==0 && !IdChar(z[j-4]))
+ ){
+ /* NULL is a keyword in this case, not a literal value */
+ }else{
+ /* Here the NULL is a literal value */
+ z[j++] = '?';
+ break;
+ }
+ }
+ if( j>0 && IdChar(z[j-1]) && IdChar(zSql[i]) ) z[j++] = ' ';
+ for(k=0; k<n; k++){
+ z[j++] = sqlite3Tolower(zSql[i+k]);
+ }
+ break;
+ }
+ }
+ }
+ while( j>0 && z[j-1]==' ' ){ j--; }
+ if( j>0 && z[j-1]!=';' ){ z[j++] = ';'; }
+ z[j] = 0;
+
+ /* Make a second pass converting "in(...)" where the "..." is not a
+ ** SELECT statement into "in(?,?,?)" */
+ for(i=0; i<j; i=n){
+ char *zIn = strstr(z+i, "in(");
+ int nParen;
+ if( zIn==0 ) break;
+ n = (int)(zIn-z)+3; /* Index of first char past "in(" */
+ if( n && IdChar(zIn[-1]) ) continue;
+ if( strncmp(zIn, "in(select",9)==0 && !IdChar(zIn[9]) ) continue;
+ if( strncmp(zIn, "in(with",7)==0 && !IdChar(zIn[7]) ) continue;
+ for(nParen=1, k=0; z[n+k]; k++){
+ if( z[n+k]=='(' ) nParen++;
+ if( z[n+k]==')' ){
+ nParen--;
+ if( nParen==0 ) break;
+ }
+ }
+ /* k is the number of bytes in the "..." within "in(...)" */
+ if( k<5 ){
+ z = sqlite3_realloc64(z, j+(5-k)+1);
+ if( z==0 ) return 0;
+ memmove(z+n+5, z+n+k, j-(n+k));
+ }else if( k>5 ){
+ memmove(z+n+5, z+n+k, j-(n+k));
+ }
+ j = j-k+5;
+ z[j] = 0;
+ memcpy(z+n, "?,?,?", 5);
+ }
+ return z;
+}
+
+/*
+** For testing purposes, or to build a stand-alone SQL normalizer program,
+** compile this one source file with the -DSQLITE_NORMALIZE_CLI and link
+** it against any SQLite library. The resulting command-line program will
+** run sqlite3_normalize() over the text of all files named on the command-
+** line and show the result on standard output.
+*/
+#ifdef SQLITE_NORMALIZE_CLI
+#include <stdio.h>
+#include <stdlib.h>
+
+/*
+** Break zIn up into separate SQL statements and run sqlite3_normalize()
+** on each one. Print the result of each run.
+*/
+static void normalizeFile(char *zIn){
+ int i;
+ if( zIn==0 ) return;
+ for(i=0; zIn[i]; i++){
+ char cSaved;
+ if( zIn[i]!=';' ) continue;
+ cSaved = zIn[i+1];
+ zIn[i+1] = 0;
+ if( sqlite3_complete(zIn) ){
+ char *zOut = sqlite3_normalize(zIn);
+ if( zOut ){
+ printf("%s\n", zOut);
+ sqlite3_free(zOut);
+ }else{
+ fprintf(stderr, "ERROR: %s\n", zIn);
+ }
+ zIn[i+1] = cSaved;
+ zIn += i+1;
+ i = -1;
+ }else{
+ zIn[i+1] = cSaved;
+ }
+ }
+}
+
+/*
+** The main routine for "sql_normalize". Read files named on the
+** command-line and run the text of each through sqlite3_normalize().
+*/
+int main(int argc, char **argv){
+ int i;
+ FILE *in;
+ char *zBuf = 0;
+ sqlite3_int64 sz, got;
+
+ for(i=1; i<argc; i++){
+ in = fopen(argv[i], "rb");
+ if( in==0 ){
+ fprintf(stderr, "cannot open \"%s\"\n", argv[i]);
+ continue;
+ }
+ fseek(in, 0, SEEK_END);
+ sz = ftell(in);
+ rewind(in);
+ zBuf = sqlite3_realloc64(zBuf, sz+1);
+ if( zBuf==0 ){
+ fprintf(stderr, "failed to malloc for %lld bytes\n", sz);
+ exit(1);
+ }
+ got = fread(zBuf, 1, sz, in);
+ fclose(in);
+ if( got!=sz ){
+ fprintf(stderr, "only able to read %lld of %lld bytes from \"%s\"\n",
+ got, sz, argv[i]);
+ }else{
+ zBuf[got] = 0;
+ normalizeFile(zBuf);
+ }
+ }
+ sqlite3_free(zBuf);
+}
+#endif /* SQLITE_NORMALIZE_CLI */
--- origsrc/sqlite-autoconf-3300000/percentile.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/percentile.c 2019-10-08 13:42:19.179851900 +0200
@@ -0,0 +1,233 @@
+/*
+** 2013-05-28
+**
+** 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 code to implement the percentile(Y,P) SQL function
+** as described below:
+**
+** (1) The percentile(Y,P) function is an aggregate function taking
+** exactly two arguments.
+**
+** (2) If the P argument to percentile(Y,P) is not the same for every
+** row in the aggregate then an error is thrown. The word "same"
+** in the previous sentence means that the value differ by less
+** than 0.001.
+**
+** (3) If the P argument to percentile(Y,P) evaluates to anything other
+** than a number in the range of 0.0 to 100.0 inclusive then an
+** error is thrown.
+**
+** (4) If any Y argument to percentile(Y,P) evaluates to a value that
+** is not NULL and is not numeric then an error is thrown.
+**
+** (5) If any Y argument to percentile(Y,P) evaluates to plus or minus
+** infinity then an error is thrown. (SQLite always interprets NaN
+** values as NULL.)
+**
+** (6) Both Y and P in percentile(Y,P) can be arbitrary expressions,
+** including CASE WHEN expressions.
+**
+** (7) The percentile(Y,P) aggregate is able to handle inputs of at least
+** one million (1,000,000) rows.
+**
+** (8) If there are no non-NULL values for Y, then percentile(Y,P)
+** returns NULL.
+**
+** (9) If there is exactly one non-NULL value for Y, the percentile(Y,P)
+** returns the one Y value.
+**
+** (10) If there N non-NULL values of Y where N is two or more and
+** the Y values are ordered from least to greatest and a graph is
+** drawn from 0 to N-1 such that the height of the graph at J is
+** the J-th Y value and such that straight lines are drawn between
+** adjacent Y values, then the percentile(Y,P) function returns
+** the height of the graph at P*(N-1)/100.
+**
+** (11) The percentile(Y,P) function always returns either a floating
+** point number or NULL.
+**
+** (12) The percentile(Y,P) is implemented as a single C99 source-code
+** file that compiles into a shared-library or DLL that can be loaded
+** into SQLite using the sqlite3_load_extension() interface.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* The following object is the session context for a single percentile()
+** function. We have to remember all input Y values until the very end.
+** Those values are accumulated in the Percentile.a[] array.
+*/
+typedef struct Percentile Percentile;
+struct Percentile {
+ unsigned nAlloc; /* Number of slots allocated for a[] */
+ unsigned nUsed; /* Number of slots actually used in a[] */
+ double rPct; /* 1.0 more than the value for P */
+ double *a; /* Array of Y values */
+};
+
+/*
+** Return TRUE if the input floating-point number is an infinity.
+*/
+static int isInfinity(double r){
+ sqlite3_uint64 u;
+ assert( sizeof(u)==sizeof(r) );
+ memcpy(&u, &r, sizeof(u));
+ return ((u>>52)&0x7ff)==0x7ff;
+}
+
+/*
+** Return TRUE if two doubles differ by 0.001 or less
+*/
+static int sameValue(double a, double b){
+ a -= b;
+ return a>=-0.001 && a<=0.001;
+}
+
+/*
+** The "step" function for percentile(Y,P) is called once for each
+** input row.
+*/
+static void percentStep(sqlite3_context *pCtx, int argc, sqlite3_value **argv){
+ Percentile *p;
+ double rPct;
+ int eType;
+ double y;
+ assert( argc==2 );
+
+ /* Requirement 3: P must be a number between 0 and 100 */
+ eType = sqlite3_value_numeric_type(argv[1]);
+ rPct = sqlite3_value_double(argv[1]);
+ if( (eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT)
+ || rPct<0.0 || rPct>100.0 ){
+ sqlite3_result_error(pCtx, "2nd argument to percentile() is not "
+ "a number between 0.0 and 100.0", -1);
+ return;
+ }
+
+ /* Allocate the session context. */
+ p = (Percentile*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ if( p==0 ) return;
+
+ /* Remember the P value. Throw an error if the P value is different
+ ** from any prior row, per Requirement (2). */
+ if( p->rPct==0.0 ){
+ p->rPct = rPct+1.0;
+ }else if( !sameValue(p->rPct,rPct+1.0) ){
+ sqlite3_result_error(pCtx, "2nd argument to percentile() is not the "
+ "same for all input rows", -1);
+ return;
+ }
+
+ /* Ignore rows for which Y is NULL */
+ eType = sqlite3_value_type(argv[0]);
+ if( eType==SQLITE_NULL ) return;
+
+ /* If not NULL, then Y must be numeric. Otherwise throw an error.
+ ** Requirement 4 */
+ if( eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT ){
+ sqlite3_result_error(pCtx, "1st argument to percentile() is not "
+ "numeric", -1);
+ return;
+ }
+
+ /* Throw an error if the Y value is infinity or NaN */
+ y = sqlite3_value_double(argv[0]);
+ if( isInfinity(y) ){
+ sqlite3_result_error(pCtx, "Inf input to percentile()", -1);
+ return;
+ }
+
+ /* Allocate and store the Y */
+ if( p->nUsed>=p->nAlloc ){
+ unsigned n = p->nAlloc*2 + 250;
+ double *a = sqlite3_realloc64(p->a, sizeof(double)*n);
+ if( a==0 ){
+ sqlite3_free(p->a);
+ memset(p, 0, sizeof(*p));
+ sqlite3_result_error_nomem(pCtx);
+ return;
+ }
+ p->nAlloc = n;
+ p->a = a;
+ }
+ p->a[p->nUsed++] = y;
+}
+
+/*
+** Compare to doubles for sorting using qsort()
+*/
+static int SQLITE_CDECL doubleCmp(const void *pA, const void *pB){
+ double a = *(double*)pA;
+ double b = *(double*)pB;
+ if( a==b ) return 0;
+ if( a<b ) return -1;
+ return +1;
+}
+
+/*
+** Called to compute the final output of percentile() and to clean
+** up all allocated memory.
+*/
+static void percentFinal(sqlite3_context *pCtx){
+ Percentile *p;
+ unsigned i1, i2;
+ double v1, v2;
+ double ix, vx;
+ p = (Percentile*)sqlite3_aggregate_context(pCtx, 0);
+ if( p==0 ) return;
+ if( p->a==0 ) return;
+ if( p->nUsed ){
+ qsort(p->a, p->nUsed, sizeof(double), doubleCmp);
+ ix = (p->rPct-1.0)*(p->nUsed-1)*0.01;
+ i1 = (unsigned)ix;
+ i2 = ix==(double)i1 || i1==p->nUsed-1 ? i1 : i1+1;
+ v1 = p->a[i1];
+ v2 = p->a[i2];
+ vx = v1 + (v2-v1)*(ix-i1);
+ sqlite3_result_double(pCtx, vx);
+ }
+ sqlite3_free(p->a);
+ memset(p, 0, sizeof(*p));
+}
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_percentile_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "percentile", 2, SQLITE_UTF8, 0,
+ 0, percentStep, percentFinal);
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "percentile", 2, SQLITE_UTF8, 0,
+ 0, percentStep, percentFinal);
+ return rc;
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/prefixes.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/prefixes.c 2019-10-08 13:42:19.180828200 +0200
@@ -0,0 +1,319 @@
+/*
+** 2018-04-19
+**
+** 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 implements a table-valued function:
+**
+** prefixes('abcdefg')
+**
+** The function has a single (non-HIDDEN) column named prefix that takes
+** on all prefixes of the string in its argument, including an empty string
+** and the input string itself. The order of prefixes is from longest
+** to shortest.
+*/
+#if !defined(SQLITE_CORE) || !defined(SQLITE_OMIT_VIRTUALTABLE)
+#if !defined(SQLITEINT_H)
+#include "sqlite3ext.h"
+#endif
+SQLITE_EXTENSION_INIT1
+#include <string.h>
+#include <assert.h>
+
+/* prefixes_vtab is a subclass of sqlite3_vtab which is
+** underlying representation of the virtual table
+*/
+typedef struct prefixes_vtab prefixes_vtab;
+struct prefixes_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ /* No additional fields are necessary */
+};
+
+/* prefixes_cursor is a subclass of sqlite3_vtab_cursor which will
+** serve as the underlying representation of a cursor that scans
+** over rows of the result
+*/
+typedef struct prefixes_cursor prefixes_cursor;
+struct prefixes_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3_int64 iRowid; /* The rowid */
+ char *zStr; /* Original string to be prefixed */
+ int nStr; /* Length of the string in bytes */
+};
+
+/*
+** The prefixesConnect() method is invoked to create a new
+** template virtual table.
+**
+** Think of this routine as the constructor for prefixes_vtab objects.
+**
+** All this routine needs to do is:
+**
+** (1) Allocate the prefixes_vtab object and initialize all fields.
+**
+** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
+** result set of queries against the virtual table will look like.
+*/
+static int prefixesConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ prefixes_vtab *pNew;
+ int rc;
+
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE prefixes(prefix TEXT, original_string TEXT HIDDEN)"
+ );
+ if( rc==SQLITE_OK ){
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for prefixes_vtab objects.
+*/
+static int prefixesDisconnect(sqlite3_vtab *pVtab){
+ prefixes_vtab *p = (prefixes_vtab*)pVtab;
+ sqlite3_free(p);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new prefixes_cursor object.
+*/
+static int prefixesOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ prefixes_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Destructor for a prefixes_cursor.
+*/
+static int prefixesClose(sqlite3_vtab_cursor *cur){
+ prefixes_cursor *pCur = (prefixes_cursor*)cur;
+ sqlite3_free(pCur->zStr);
+ sqlite3_free(pCur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a prefixes_cursor to its next row of output.
+*/
+static int prefixesNext(sqlite3_vtab_cursor *cur){
+ prefixes_cursor *pCur = (prefixes_cursor*)cur;
+ pCur->iRowid++;
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the prefixes_cursor
+** is currently pointing.
+*/
+static int prefixesColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ prefixes_cursor *pCur = (prefixes_cursor*)cur;
+ switch( i ){
+ case 0:
+ sqlite3_result_text(ctx, pCur->zStr, pCur->nStr - (int)pCur->iRowid,
+ 0);
+ break;
+ default:
+ sqlite3_result_text(ctx, pCur->zStr, pCur->nStr, 0);
+ break;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** rowid is the same as the output value.
+*/
+static int prefixesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ prefixes_cursor *pCur = (prefixes_cursor*)cur;
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int prefixesEof(sqlite3_vtab_cursor *cur){
+ prefixes_cursor *pCur = (prefixes_cursor*)cur;
+ return pCur->iRowid>pCur->nStr;
+}
+
+/*
+** This method is called to "rewind" the prefixes_cursor object back
+** to the first row of output. This method is always called at least
+** once prior to any call to prefixesColumn() or prefixesRowid() or
+** prefixesEof().
+*/
+static int prefixesFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ prefixes_cursor *pCur = (prefixes_cursor *)pVtabCursor;
+ sqlite3_free(pCur->zStr);
+ if( argc>0 ){
+ pCur->zStr = sqlite3_mprintf("%s", sqlite3_value_text(argv[0]));
+ pCur->nStr = pCur->zStr ? (int)strlen(pCur->zStr) : 0;
+ }else{
+ pCur->zStr = 0;
+ pCur->nStr = 0;
+ }
+ pCur->iRowid = 0;
+ return SQLITE_OK;
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+*/
+static int prefixesBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ /* Search for a usable equality constraint against column 1
+ ** (original_string) and use it if at all possible */
+ int i;
+ const struct sqlite3_index_constraint *p;
+
+ for(i=0, p=pIdxInfo->aConstraint; i<pIdxInfo->nConstraint; i++, p++){
+ if( p->iColumn!=1 ) continue;
+ if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+ if( !p->usable ) continue;
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ pIdxInfo->estimatedCost = (double)10;
+ pIdxInfo->estimatedRows = 10;
+ return SQLITE_OK;
+ }
+ pIdxInfo->estimatedCost = (double)1000000000;
+ pIdxInfo->estimatedRows = 1000000000;
+ return SQLITE_OK;
+}
+
+/*
+** This following structure defines all the methods for the
+** virtual table.
+*/
+static const sqlite3_module prefixesModule = {
+ /* iVersion */ 0,
+ /* xCreate */ 0,
+ /* xConnect */ prefixesConnect,
+ /* xBestIndex */ prefixesBestIndex,
+ /* xDisconnect */ prefixesDisconnect,
+ /* xDestroy */ 0,
+ /* xOpen */ prefixesOpen,
+ /* xClose */ prefixesClose,
+ /* xFilter */ prefixesFilter,
+ /* xNext */ prefixesNext,
+ /* xEof */ prefixesEof,
+ /* xColumn */ prefixesColumn,
+ /* xRowid */ prefixesRowid,
+ /* xUpdate */ 0,
+ /* xBegin */ 0,
+ /* xSync */ 0,
+ /* xCommit */ 0,
+ /* xRollback */ 0,
+ /* xFindMethod */ 0,
+ /* xRename */ 0,
+ /* xSavepoint */ 0,
+ /* xRelease */ 0,
+ /* xRollbackTo */ 0,
+ /* xShadowName */ 0
+};
+
+/*
+** This is a copy of the SQLITE_SKIP_UTF8(zIn) macro in sqliteInt.h.
+**
+** Assuming zIn points to the first byte of a UTF-8 character,
+** advance zIn to point to the first byte of the next UTF-8 character.
+*/
+#define PREFIX_SKIP_UTF8(zIn) { \
+ if( (*(zIn++))>=0xc0 ){ \
+ while( (*zIn & 0xc0)==0x80 ){ zIn++; } \
+ } \
+}
+
+/*
+** Implementation of function prefix_length(). This function accepts two
+** strings as arguments and returns the length in characters (not bytes),
+** of the longest prefix shared by the two strings. For example:
+**
+** prefix_length('abcdxxx', 'abcyy') == 3
+** prefix_length('abcdxxx', 'bcyyy') == 0
+** prefix_length('abcdxxx', 'ab') == 2
+** prefix_length('ab', 'abcd') == 2
+**
+** This function assumes the input is well-formed utf-8. If it is not,
+** it is possible for this function to return -1.
+*/
+static void prefixLengthFunc(
+ sqlite3_context *ctx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ int nByte; /* Number of bytes to compare */
+ int nRet = 0; /* Return value */
+ const unsigned char *zL = sqlite3_value_text(apVal[0]);
+ const unsigned char *zR = sqlite3_value_text(apVal[1]);
+ int nL = sqlite3_value_bytes(apVal[0]);
+ int nR = sqlite3_value_bytes(apVal[1]);
+ int i;
+
+ nByte = (nL > nR ? nL : nR);
+ for(i=0; i<nByte; i++){
+ if( zL[i]!=zR[i] ) break;
+ if( (zL[i] & 0xC0)!=0x80 ) nRet++;
+ }
+
+ if( (zL[i] & 0xC0)==0x80 ) nRet--;
+ sqlite3_result_int(ctx, nRet);
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_prefixes_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ rc = sqlite3_create_module(db, "prefixes", &prefixesModule, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(
+ db, "prefix_length", 2, SQLITE_UTF8, 0, prefixLengthFunc, 0, 0
+ );
+ }
+ return rc;
+}
+#endif /* !defined(SQLITE_CORE) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
--- origsrc/sqlite-autoconf-3300000/rbu.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/rbu.c 2019-03-05 13:14:40.707000000 +0100
@@ -0,0 +1,188 @@
+/*
+** 2014 August 30
+**
+** 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 a command-line application that uses the RBU
+** extension. See the usage() function below for an explanation.
+*/
+
+#include "sqlite3rbu.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+** Print a usage message and exit.
+*/
+void usage(const char *zArgv0){
+ fprintf(stderr,
+"Usage: %s ?OPTIONS? TARGET-DB RBU-DB\n"
+"\n"
+"Where options are:\n"
+"\n"
+" -step NSTEP\n"
+" -statstep NSTATSTEP\n"
+" -vacuum\n"
+" -presql SQL\n"
+"\n"
+" If the -vacuum switch is not present, argument RBU-DB must be an RBU\n"
+" database containing an update suitable for target database TARGET-DB.\n"
+" Or, if -vacuum is specified, then TARGET-DB is a database to vacuum using\n"
+" RBU, and RBU-DB is used as the state database for the vacuum (refer to\n"
+" API documentation for details).\n"
+"\n"
+" If NSTEP is set to less than or equal to zero (the default value), this \n"
+" program attempts to perform the entire update or vacuum operation before\n"
+" exiting\n"
+"\n"
+" If NSTEP is greater than zero, then a maximum of NSTEP calls are made\n"
+" to sqlite3rbu_step(). If the RBU update has not been completely applied\n"
+" after the NSTEP'th call is made, the state is saved in the database RBU-DB\n"
+" and the program exits. Subsequent invocations of this (or any other RBU)\n"
+" application will use this state to resume applying the RBU update to the\n"
+" target db.\n"
+"\n"
+, zArgv0);
+ exit(1);
+}
+
+void report_default_vfs(){
+ sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
+ fprintf(stdout, "default vfs is \"%s\"\n", pVfs->zName);
+}
+
+void report_rbu_vfs(sqlite3rbu *pRbu){
+ sqlite3 *db = sqlite3rbu_db(pRbu, 0);
+ if( db ){
+ char *zName = 0;
+ sqlite3_file_control(db, "main", SQLITE_FCNTL_VFSNAME, &zName);
+ if( zName ){
+ fprintf(stdout, "using vfs \"%s\"\n", zName);
+ }else{
+ fprintf(stdout, "vfs name not available\n");
+ }
+ sqlite3_free(zName);
+ }
+}
+
+int main(int argc, char **argv){
+ int i;
+ const char *zTarget; /* Target database to apply RBU to */
+ const char *zRbu; /* Database containing RBU */
+ char zBuf[200]; /* Buffer for printf() */
+ char *zErrmsg = 0; /* Error message, if any */
+ sqlite3rbu *pRbu; /* RBU handle */
+ int nStep = 0; /* Maximum number of step() calls */
+ int nStatStep = 0; /* Report stats after this many step calls */
+ int bVacuum = 0;
+ const char *zPreSql = 0;
+ int rc = SQLITE_OK;
+ sqlite3_int64 nProgress = 0;
+ int nArgc = argc-2;
+
+ if( argc<3 ) usage(argv[0]);
+ for(i=1; i<nArgc; i++){
+ const char *zArg = argv[i];
+ int nArg = strlen(zArg);
+ if( nArg>1 && nArg<=8 && 0==memcmp(zArg, "-vacuum", nArg) ){
+ bVacuum = 1;
+ }else if( nArg>1 && nArg<=7
+ && 0==memcmp(zArg, "-presql", nArg) && i<nArg-1 ){
+ i++;
+ zPreSql = argv[i];
+ }else if( nArg>1 && nArg<=5 && 0==memcmp(zArg, "-step", nArg) && i<nArg-1 ){
+ i++;
+ nStep = atoi(argv[i]);
+ }else if( nArg>1 && nArg<=9
+ && 0==memcmp(zArg, "-statstep", nArg) && i<nArg-1
+ ){
+ i++;
+ nStatStep = atoi(argv[i]);
+ }else{
+ usage(argv[0]);
+ }
+ }
+
+ zTarget = argv[argc-2];
+ zRbu = argv[argc-1];
+
+ report_default_vfs();
+
+ /* Open an RBU handle. A vacuum handle if -vacuum was specified, or a
+ ** regular RBU update handle otherwise. */
+ if( bVacuum ){
+ pRbu = sqlite3rbu_vacuum(zTarget, zRbu);
+ }else{
+ pRbu = sqlite3rbu_open(zTarget, zRbu, 0);
+ }
+ report_rbu_vfs(pRbu);
+
+ if( zPreSql && pRbu ){
+ sqlite3 *dbMain = sqlite3rbu_db(pRbu, 0);
+ rc = sqlite3_exec(dbMain, zPreSql, 0, 0, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3 *dbRbu = sqlite3rbu_db(pRbu, 1);
+ rc = sqlite3_exec(dbRbu, zPreSql, 0, 0, 0);
+ }
+ }
+
+ /* If nStep is less than or equal to zero, call
+ ** sqlite3rbu_step() until either the RBU has been completely applied
+ ** or an error occurs. Or, if nStep is greater than zero, call
+ ** sqlite3rbu_step() a maximum of nStep times. */
+ if( rc==SQLITE_OK ){
+ for(i=0; (nStep<=0 || i<nStep) && sqlite3rbu_step(pRbu)==SQLITE_OK; i++){
+ if( nStatStep>0 && (i % nStatStep)==0 ){
+ sqlite3_int64 nUsed;
+ sqlite3_int64 nHighwater;
+ sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &nUsed, &nHighwater, 0);
+ fprintf(stdout, "memory used=%lld highwater=%lld", nUsed, nHighwater);
+ if( bVacuum==0 ){
+ int one;
+ int two;
+ sqlite3rbu_bp_progress(pRbu, &one, &two);
+ fprintf(stdout, " progress=%d/%d\n", one, two);
+ }else{
+ fprintf(stdout, "\n");
+ }
+ fflush(stdout);
+ }
+ }
+ nProgress = sqlite3rbu_progress(pRbu);
+ rc = sqlite3rbu_close(pRbu, &zErrmsg);
+ }
+
+ /* Let the user know what happened. */
+ switch( rc ){
+ case SQLITE_OK:
+ sqlite3_snprintf(sizeof(zBuf), zBuf,
+ "SQLITE_OK: rbu update incomplete (%lld operations so far)\n",
+ nProgress
+ );
+ fprintf(stdout, "%s", zBuf);
+ break;
+
+ case SQLITE_DONE:
+ sqlite3_snprintf(sizeof(zBuf), zBuf,
+ "SQLITE_DONE: rbu update completed (%lld operations)\n",
+ nProgress
+ );
+ fprintf(stdout, "%s", zBuf);
+ break;
+
+ default:
+ fprintf(stderr, "error=%d: %s\n", rc, zErrmsg);
+ break;
+ }
+
+ sqlite3_free(zErrmsg);
+ return (rc==SQLITE_OK || rc==SQLITE_DONE) ? 0 : 1;
+}
--- origsrc/sqlite-autoconf-3300000/regexp.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/regexp.c 2019-10-08 13:42:19.185720700 +0200
@@ -0,0 +1,773 @@
+/*
+** 2012-11-13
+**
+** 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.
+**
+******************************************************************************
+**
+** The code in this file implements a compact but reasonably
+** efficient regular-expression matcher for posix extended regular
+** expressions against UTF8 text.
+**
+** This file is an SQLite extension. It registers a single function
+** named "regexp(A,B)" where A is the regular expression and B is the
+** string to be matched. By registering this function, SQLite will also
+** then implement the "B regexp A" operator. Note that with the function
+** the regular expression comes first, but with the operator it comes
+** second.
+**
+** The following regular expression syntax is supported:
+**
+** X* zero or more occurrences of X
+** X+ one or more occurrences of X
+** X? zero or one occurrences of X
+** X{p,q} between p and q occurrences of X
+** (X) match X
+** X|Y X or Y
+** ^X X occurring at the beginning of the string
+** X$ X occurring at the end of the string
+** . Match any single character
+** \c Character c where c is one of \{}()[]|*+?.
+** \c C-language escapes for c in afnrtv. ex: \t or \n
+** \uXXXX Where XXXX is exactly 4 hex digits, unicode value XXXX
+** \xXX Where XX is exactly 2 hex digits, unicode value XX
+** [abc] Any single character from the set abc
+** [^abc] Any single character not in the set abc
+** [a-z] Any single character in the range a-z
+** [^a-z] Any single character not in the range a-z
+** \b Word boundary
+** \w Word character. [A-Za-z0-9_]
+** \W Non-word character
+** \d Digit
+** \D Non-digit
+** \s Whitespace character
+** \S Non-whitespace character
+**
+** A nondeterministic finite automaton (NFA) is used for matching, so the
+** performance is bounded by O(N*M) where N is the size of the regular
+** expression and M is the size of the input string. The matcher never
+** exhibits exponential behavior. Note that the X{p,q} operator expands
+** to p copies of X following by q-p copies of X? and that the size of the
+** regular expression in the O(N*M) performance bound is computed after
+** this expansion.
+*/
+#include <string.h>
+#include <stdlib.h>
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+
+/*
+** The following #defines change the names of some functions implemented in
+** this file to prevent name collisions with C-library functions of the
+** same name.
+*/
+#define re_match sqlite3re_match
+#define re_compile sqlite3re_compile
+#define re_free sqlite3re_free
+
+/* The end-of-input character */
+#define RE_EOF 0 /* End of input */
+
+/* The NFA is implemented as sequence of opcodes taken from the following
+** set. Each opcode has a single integer argument.
+*/
+#define RE_OP_MATCH 1 /* Match the one character in the argument */
+#define RE_OP_ANY 2 /* Match any one character. (Implements ".") */
+#define RE_OP_ANYSTAR 3 /* Special optimized version of .* */
+#define RE_OP_FORK 4 /* Continue to both next and opcode at iArg */
+#define RE_OP_GOTO 5 /* Jump to opcode at iArg */
+#define RE_OP_ACCEPT 6 /* Halt and indicate a successful match */
+#define RE_OP_CC_INC 7 /* Beginning of a [...] character class */
+#define RE_OP_CC_EXC 8 /* Beginning of a [^...] character class */
+#define RE_OP_CC_VALUE 9 /* Single value in a character class */
+#define RE_OP_CC_RANGE 10 /* Range of values in a character class */
+#define RE_OP_WORD 11 /* Perl word character [A-Za-z0-9_] */
+#define RE_OP_NOTWORD 12 /* Not a perl word character */
+#define RE_OP_DIGIT 13 /* digit: [0-9] */
+#define RE_OP_NOTDIGIT 14 /* Not a digit */
+#define RE_OP_SPACE 15 /* space: [ \t\n\r\v\f] */
+#define RE_OP_NOTSPACE 16 /* Not a digit */
+#define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */
+
+/* Each opcode is a "state" in the NFA */
+typedef unsigned short ReStateNumber;
+
+/* Because this is an NFA and not a DFA, multiple states can be active at
+** once. An instance of the following object records all active states in
+** the NFA. The implementation is optimized for the common case where the
+** number of actives states is small.
+*/
+typedef struct ReStateSet {
+ unsigned nState; /* Number of current states */
+ ReStateNumber *aState; /* Current states */
+} ReStateSet;
+
+/* An input string read one character at a time.
+*/
+typedef struct ReInput ReInput;
+struct ReInput {
+ const unsigned char *z; /* All text */
+ int i; /* Next byte to read */
+ int mx; /* EOF when i>=mx */
+};
+
+/* A compiled NFA (or an NFA that is in the process of being compiled) is
+** an instance of the following object.
+*/
+typedef struct ReCompiled ReCompiled;
+struct ReCompiled {
+ ReInput sIn; /* Regular expression text */
+ const char *zErr; /* Error message to return */
+ char *aOp; /* Operators for the virtual machine */
+ int *aArg; /* Arguments to each operator */
+ unsigned (*xNextChar)(ReInput*); /* Next character function */
+ unsigned char zInit[12]; /* Initial text to match */
+ int nInit; /* Number of characters in zInit */
+ unsigned nState; /* Number of entries in aOp[] and aArg[] */
+ unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */
+};
+
+/* Add a state to the given state set if it is not already there */
+static void re_add_state(ReStateSet *pSet, int newState){
+ unsigned i;
+ for(i=0; i<pSet->nState; i++) if( pSet->aState[i]==newState ) return;
+ pSet->aState[pSet->nState++] = (ReStateNumber)newState;
+}
+
+/* Extract the next unicode character from *pzIn and return it. Advance
+** *pzIn to the first byte past the end of the character returned. To
+** be clear: this routine converts utf8 to unicode. This routine is
+** optimized for the common case where the next character is a single byte.
+*/
+static unsigned re_next_char(ReInput *p){
+ unsigned c;
+ if( p->i>=p->mx ) return 0;
+ c = p->z[p->i++];
+ if( c>=0x80 ){
+ if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){
+ c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f);
+ if( c<0x80 ) c = 0xfffd;
+ }else if( (c&0xf0)==0xe0 && p->i+1<p->mx && (p->z[p->i]&0xc0)==0x80
+ && (p->z[p->i+1]&0xc0)==0x80 ){
+ c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f);
+ p->i += 2;
+ if( c<=0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
+ }else if( (c&0xf8)==0xf0 && p->i+3<p->mx && (p->z[p->i]&0xc0)==0x80
+ && (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){
+ c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6)
+ | (p->z[p->i+2]&0x3f);
+ p->i += 3;
+ if( c<=0xffff || c>0x10ffff ) c = 0xfffd;
+ }else{
+ c = 0xfffd;
+ }
+ }
+ return c;
+}
+static unsigned re_next_char_nocase(ReInput *p){
+ unsigned c = re_next_char(p);
+ if( c>='A' && c<='Z' ) c += 'a' - 'A';
+ return c;
+}
+
+/* Return true if c is a perl "word" character: [A-Za-z0-9_] */
+static int re_word_char(int c){
+ return (c>='0' && c<='9') || (c>='a' && c<='z')
+ || (c>='A' && c<='Z') || c=='_';
+}
+
+/* Return true if c is a "digit" character: [0-9] */
+static int re_digit_char(int c){
+ return (c>='0' && c<='9');
+}
+
+/* Return true if c is a perl "space" character: [ \t\r\n\v\f] */
+static int re_space_char(int c){
+ return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f';
+}
+
+/* Run a compiled regular expression on the zero-terminated input
+** string zIn[]. Return true on a match and false if there is no match.
+*/
+int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
+ ReStateSet aStateSet[2], *pThis, *pNext;
+ ReStateNumber aSpace[100];
+ ReStateNumber *pToFree;
+ unsigned int i = 0;
+ unsigned int iSwap = 0;
+ int c = RE_EOF+1;
+ int cPrev = 0;
+ int rc = 0;
+ ReInput in;
+
+ in.z = zIn;
+ in.i = 0;
+ in.mx = nIn>=0 ? nIn : (int)strlen((char const*)zIn);
+
+ /* Look for the initial prefix match, if there is one. */
+ if( pRe->nInit ){
+ unsigned char x = pRe->zInit[0];
+ while( in.i+pRe->nInit<=in.mx
+ && (zIn[in.i]!=x ||
+ strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0)
+ ){
+ in.i++;
+ }
+ if( in.i+pRe->nInit>in.mx ) return 0;
+ }
+
+ if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){
+ pToFree = 0;
+ aStateSet[0].aState = aSpace;
+ }else{
+ pToFree = sqlite3_malloc( sizeof(ReStateNumber)*2*pRe->nState );
+ if( pToFree==0 ) return -1;
+ aStateSet[0].aState = pToFree;
+ }
+ aStateSet[1].aState = &aStateSet[0].aState[pRe->nState];
+ pNext = &aStateSet[1];
+ pNext->nState = 0;
+ re_add_state(pNext, 0);
+ while( c!=RE_EOF && pNext->nState>0 ){
+ cPrev = c;
+ c = pRe->xNextChar(&in);
+ pThis = pNext;
+ pNext = &aStateSet[iSwap];
+ iSwap = 1 - iSwap;
+ pNext->nState = 0;
+ for(i=0; i<pThis->nState; i++){
+ int x = pThis->aState[i];
+ switch( pRe->aOp[x] ){
+ case RE_OP_MATCH: {
+ if( pRe->aArg[x]==c ) re_add_state(pNext, x+1);
+ break;
+ }
+ case RE_OP_ANY: {
+ re_add_state(pNext, x+1);
+ break;
+ }
+ case RE_OP_WORD: {
+ if( re_word_char(c) ) re_add_state(pNext, x+1);
+ break;
+ }
+ case RE_OP_NOTWORD: {
+ if( !re_word_char(c) ) re_add_state(pNext, x+1);
+ break;
+ }
+ case RE_OP_DIGIT: {
+ if( re_digit_char(c) ) re_add_state(pNext, x+1);
+ break;
+ }
+ case RE_OP_NOTDIGIT: {
+ if( !re_digit_char(c) ) re_add_state(pNext, x+1);
+ break;
+ }
+ case RE_OP_SPACE: {
+ if( re_space_char(c) ) re_add_state(pNext, x+1);
+ break;
+ }
+ case RE_OP_NOTSPACE: {
+ if( !re_space_char(c) ) re_add_state(pNext, x+1);
+ break;
+ }
+ case RE_OP_BOUNDARY: {
+ if( re_word_char(c)!=re_word_char(cPrev) ) re_add_state(pThis, x+1);
+ break;
+ }
+ case RE_OP_ANYSTAR: {
+ re_add_state(pNext, x);
+ re_add_state(pThis, x+1);
+ break;
+ }
+ case RE_OP_FORK: {
+ re_add_state(pThis, x+pRe->aArg[x]);
+ re_add_state(pThis, x+1);
+ break;
+ }
+ case RE_OP_GOTO: {
+ re_add_state(pThis, x+pRe->aArg[x]);
+ break;
+ }
+ case RE_OP_ACCEPT: {
+ rc = 1;
+ goto re_match_end;
+ }
+ case RE_OP_CC_INC:
+ case RE_OP_CC_EXC: {
+ int j = 1;
+ int n = pRe->aArg[x];
+ int hit = 0;
+ for(j=1; j>0 && j<n; j++){
+ if( pRe->aOp[x+j]==RE_OP_CC_VALUE ){
+ if( pRe->aArg[x+j]==c ){
+ hit = 1;
+ j = -1;
+ }
+ }else{
+ if( pRe->aArg[x+j]<=c && pRe->aArg[x+j+1]>=c ){
+ hit = 1;
+ j = -1;
+ }else{
+ j++;
+ }
+ }
+ }
+ if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit;
+ if( hit ) re_add_state(pNext, x+n);
+ break;
+ }
+ }
+ }
+ }
+ for(i=0; i<pNext->nState; i++){
+ if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; }
+ }
+re_match_end:
+ sqlite3_free(pToFree);
+ return rc;
+}
+
+/* Resize the opcode and argument arrays for an RE under construction.
+*/
+static int re_resize(ReCompiled *p, int N){
+ char *aOp;
+ int *aArg;
+ aOp = sqlite3_realloc64(p->aOp, N*sizeof(p->aOp[0]));
+ if( aOp==0 ) return 1;
+ p->aOp = aOp;
+ aArg = sqlite3_realloc64(p->aArg, N*sizeof(p->aArg[0]));
+ if( aArg==0 ) return 1;
+ p->aArg = aArg;
+ p->nAlloc = N;
+ return 0;
+}
+
+/* Insert a new opcode and argument into an RE under construction. The
+** insertion point is just prior to existing opcode iBefore.
+*/
+static int re_insert(ReCompiled *p, int iBefore, int op, int arg){
+ int i;
+ if( p->nAlloc<=p->nState && re_resize(p, p->nAlloc*2) ) return 0;
+ for(i=p->nState; i>iBefore; i--){
+ p->aOp[i] = p->aOp[i-1];
+ p->aArg[i] = p->aArg[i-1];
+ }
+ p->nState++;
+ p->aOp[iBefore] = (char)op;
+ p->aArg[iBefore] = arg;
+ return iBefore;
+}
+
+/* Append a new opcode and argument to the end of the RE under construction.
+*/
+static int re_append(ReCompiled *p, int op, int arg){
+ return re_insert(p, p->nState, op, arg);
+}
+
+/* Make a copy of N opcodes starting at iStart onto the end of the RE
+** under construction.
+*/
+static void re_copy(ReCompiled *p, int iStart, int N){
+ if( p->nState+N>=p->nAlloc && re_resize(p, p->nAlloc*2+N) ) return;
+ memcpy(&p->aOp[p->nState], &p->aOp[iStart], N*sizeof(p->aOp[0]));
+ memcpy(&p->aArg[p->nState], &p->aArg[iStart], N*sizeof(p->aArg[0]));
+ p->nState += N;
+}
+
+/* Return true if c is a hexadecimal digit character: [0-9a-fA-F]
+** If c is a hex digit, also set *pV = (*pV)*16 + valueof(c). If
+** c is not a hex digit *pV is unchanged.
+*/
+static int re_hex(int c, int *pV){
+ if( c>='0' && c<='9' ){
+ c -= '0';
+ }else if( c>='a' && c<='f' ){
+ c -= 'a' - 10;
+ }else if( c>='A' && c<='F' ){
+ c -= 'A' - 10;
+ }else{
+ return 0;
+ }
+ *pV = (*pV)*16 + (c & 0xff);
+ return 1;
+}
+
+/* A backslash character has been seen, read the next character and
+** return its interpretation.
+*/
+static unsigned re_esc_char(ReCompiled *p){
+ static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]";
+ static const char zTrans[] = "\a\f\n\r\t\v";
+ int i, v = 0;
+ char c;
+ if( p->sIn.i>=p->sIn.mx ) return 0;
+ c = p->sIn.z[p->sIn.i];
+ if( c=='u' && p->sIn.i+4<p->sIn.mx ){
+ const unsigned char *zIn = p->sIn.z + p->sIn.i;
+ if( re_hex(zIn[1],&v)
+ && re_hex(zIn[2],&v)
+ && re_hex(zIn[3],&v)
+ && re_hex(zIn[4],&v)
+ ){
+ p->sIn.i += 5;
+ return v;
+ }
+ }
+ if( c=='x' && p->sIn.i+2<p->sIn.mx ){
+ const unsigned char *zIn = p->sIn.z + p->sIn.i;
+ if( re_hex(zIn[1],&v)
+ && re_hex(zIn[2],&v)
+ ){
+ p->sIn.i += 3;
+ return v;
+ }
+ }
+ for(i=0; zEsc[i] && zEsc[i]!=c; i++){}
+ if( zEsc[i] ){
+ if( i<6 ) c = zTrans[i];
+ p->sIn.i++;
+ }else{
+ p->zErr = "unknown \\ escape";
+ }
+ return c;
+}
+
+/* Forward declaration */
+static const char *re_subcompile_string(ReCompiled*);
+
+/* Peek at the next byte of input */
+static unsigned char rePeek(ReCompiled *p){
+ return p->sIn.i<p->sIn.mx ? p->sIn.z[p->sIn.i] : 0;
+}
+
+/* Compile RE text into a sequence of opcodes. Continue up to the
+** first unmatched ")" character, then return. If an error is found,
+** return a pointer to the error message string.
+*/
+static const char *re_subcompile_re(ReCompiled *p){
+ const char *zErr;
+ int iStart, iEnd, iGoto;
+ iStart = p->nState;
+ zErr = re_subcompile_string(p);
+ if( zErr ) return zErr;
+ while( rePeek(p)=='|' ){
+ iEnd = p->nState;
+ re_insert(p, iStart, RE_OP_FORK, iEnd + 2 - iStart);
+ iGoto = re_append(p, RE_OP_GOTO, 0);
+ p->sIn.i++;
+ zErr = re_subcompile_string(p);
+ if( zErr ) return zErr;
+ p->aArg[iGoto] = p->nState - iGoto;
+ }
+ return 0;
+}
+
+/* Compile an element of regular expression text (anything that can be
+** an operand to the "|" operator). Return NULL on success or a pointer
+** to the error message if there is a problem.
+*/
+static const char *re_subcompile_string(ReCompiled *p){
+ int iPrev = -1;
+ int iStart;
+ unsigned c;
+ const char *zErr;
+ while( (c = p->xNextChar(&p->sIn))!=0 ){
+ iStart = p->nState;
+ switch( c ){
+ case '|':
+ case '$':
+ case ')': {
+ p->sIn.i--;
+ return 0;
+ }
+ case '(': {
+ zErr = re_subcompile_re(p);
+ if( zErr ) return zErr;
+ if( rePeek(p)!=')' ) return "unmatched '('";
+ p->sIn.i++;
+ break;
+ }
+ case '.': {
+ if( rePeek(p)=='*' ){
+ re_append(p, RE_OP_ANYSTAR, 0);
+ p->sIn.i++;
+ }else{
+ re_append(p, RE_OP_ANY, 0);
+ }
+ break;
+ }
+ case '*': {
+ if( iPrev<0 ) return "'*' without operand";
+ re_insert(p, iPrev, RE_OP_GOTO, p->nState - iPrev + 1);
+ re_append(p, RE_OP_FORK, iPrev - p->nState + 1);
+ break;
+ }
+ case '+': {
+ if( iPrev<0 ) return "'+' without operand";
+ re_append(p, RE_OP_FORK, iPrev - p->nState);
+ break;
+ }
+ case '?': {
+ if( iPrev<0 ) return "'?' without operand";
+ re_insert(p, iPrev, RE_OP_FORK, p->nState - iPrev+1);
+ break;
+ }
+ case '{': {
+ int m = 0, n = 0;
+ int sz, j;
+ if( iPrev<0 ) return "'{m,n}' without operand";
+ while( (c=rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; }
+ n = m;
+ if( c==',' ){
+ p->sIn.i++;
+ n = 0;
+ while( (c=rePeek(p))>='0' && c<='9' ){ n = n*10 + c-'0'; p->sIn.i++; }
+ }
+ if( c!='}' ) return "unmatched '{'";
+ if( n>0 && n<m ) return "n less than m in '{m,n}'";
+ p->sIn.i++;
+ sz = p->nState - iPrev;
+ if( m==0 ){
+ if( n==0 ) return "both m and n are zero in '{m,n}'";
+ re_insert(p, iPrev, RE_OP_FORK, sz+1);
+ n--;
+ }else{
+ for(j=1; j<m; j++) re_copy(p, iPrev, sz);
+ }
+ for(j=m; j<n; j++){
+ re_append(p, RE_OP_FORK, sz+1);
+ re_copy(p, iPrev, sz);
+ }
+ if( n==0 && m>0 ){
+ re_append(p, RE_OP_FORK, -sz);
+ }
+ break;
+ }
+ case '[': {
+ int iFirst = p->nState;
+ if( rePeek(p)=='^' ){
+ re_append(p, RE_OP_CC_EXC, 0);
+ p->sIn.i++;
+ }else{
+ re_append(p, RE_OP_CC_INC, 0);
+ }
+ while( (c = p->xNextChar(&p->sIn))!=0 ){
+ if( c=='[' && rePeek(p)==':' ){
+ return "POSIX character classes not supported";
+ }
+ if( c=='\\' ) c = re_esc_char(p);
+ if( rePeek(p)=='-' ){
+ re_append(p, RE_OP_CC_RANGE, c);
+ p->sIn.i++;
+ c = p->xNextChar(&p->sIn);
+ if( c=='\\' ) c = re_esc_char(p);
+ re_append(p, RE_OP_CC_RANGE, c);
+ }else{
+ re_append(p, RE_OP_CC_VALUE, c);
+ }
+ if( rePeek(p)==']' ){ p->sIn.i++; break; }
+ }
+ if( c==0 ) return "unclosed '['";
+ p->aArg[iFirst] = p->nState - iFirst;
+ break;
+ }
+ case '\\': {
+ int specialOp = 0;
+ switch( rePeek(p) ){
+ case 'b': specialOp = RE_OP_BOUNDARY; break;
+ case 'd': specialOp = RE_OP_DIGIT; break;
+ case 'D': specialOp = RE_OP_NOTDIGIT; break;
+ case 's': specialOp = RE_OP_SPACE; break;
+ case 'S': specialOp = RE_OP_NOTSPACE; break;
+ case 'w': specialOp = RE_OP_WORD; break;
+ case 'W': specialOp = RE_OP_NOTWORD; break;
+ }
+ if( specialOp ){
+ p->sIn.i++;
+ re_append(p, specialOp, 0);
+ }else{
+ c = re_esc_char(p);
+ re_append(p, RE_OP_MATCH, c);
+ }
+ break;
+ }
+ default: {
+ re_append(p, RE_OP_MATCH, c);
+ break;
+ }
+ }
+ iPrev = iStart;
+ }
+ return 0;
+}
+
+/* Free and reclaim all the memory used by a previously compiled
+** regular expression. Applications should invoke this routine once
+** for every call to re_compile() to avoid memory leaks.
+*/
+static void re_free(ReCompiled *pRe){
+ if( pRe ){
+ sqlite3_free(pRe->aOp);
+ sqlite3_free(pRe->aArg);
+ sqlite3_free(pRe);
+ }
+}
+
+/*
+** Compile a textual regular expression in zIn[] into a compiled regular
+** expression suitable for us by re_match() and return a pointer to the
+** compiled regular expression in *ppRe. Return NULL on success or an
+** error message if something goes wrong.
+*/
+static const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){
+ ReCompiled *pRe;
+ const char *zErr;
+ int i, j;
+
+ *ppRe = 0;
+ pRe = sqlite3_malloc( sizeof(*pRe) );
+ if( pRe==0 ){
+ return "out of memory";
+ }
+ memset(pRe, 0, sizeof(*pRe));
+ pRe->xNextChar = noCase ? re_next_char_nocase : re_next_char;
+ if( re_resize(pRe, 30) ){
+ re_free(pRe);
+ return "out of memory";
+ }
+ if( zIn[0]=='^' ){
+ zIn++;
+ }else{
+ re_append(pRe, RE_OP_ANYSTAR, 0);
+ }
+ pRe->sIn.z = (unsigned char*)zIn;
+ pRe->sIn.i = 0;
+ pRe->sIn.mx = (int)strlen(zIn);
+ zErr = re_subcompile_re(pRe);
+ if( zErr ){
+ re_free(pRe);
+ return zErr;
+ }
+ if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){
+ re_append(pRe, RE_OP_MATCH, RE_EOF);
+ re_append(pRe, RE_OP_ACCEPT, 0);
+ *ppRe = pRe;
+ }else if( pRe->sIn.i>=pRe->sIn.mx ){
+ re_append(pRe, RE_OP_ACCEPT, 0);
+ *ppRe = pRe;
+ }else{
+ re_free(pRe);
+ return "unrecognized character";
+ }
+
+ /* The following is a performance optimization. If the regex begins with
+ ** ".*" (if the input regex lacks an initial "^") and afterwards there are
+ ** one or more matching characters, enter those matching characters into
+ ** zInit[]. The re_match() routine can then search ahead in the input
+ ** string looking for the initial match without having to run the whole
+ ** regex engine over the string. Do not worry able trying to match
+ ** unicode characters beyond plane 0 - those are very rare and this is
+ ** just an optimization. */
+ if( pRe->aOp[0]==RE_OP_ANYSTAR ){
+ for(j=0, i=1; j<sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){
+ unsigned x = pRe->aArg[i];
+ if( x<=127 ){
+ pRe->zInit[j++] = (unsigned char)x;
+ }else if( x<=0xfff ){
+ pRe->zInit[j++] = (unsigned char)(0xc0 | (x>>6));
+ pRe->zInit[j++] = 0x80 | (x&0x3f);
+ }else if( x<=0xffff ){
+ pRe->zInit[j++] = (unsigned char)(0xd0 | (x>>12));
+ pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f);
+ pRe->zInit[j++] = 0x80 | (x&0x3f);
+ }else{
+ break;
+ }
+ }
+ if( j>0 && pRe->zInit[j-1]==0 ) j--;
+ pRe->nInit = j;
+ }
+ return pRe->zErr;
+}
+
+/*
+** Implementation of the regexp() SQL function. This function implements
+** the build-in REGEXP operator. The first argument to the function is the
+** pattern and the second argument is the string. So, the SQL statements:
+**
+** A REGEXP B
+**
+** is implemented as regexp(B,A).
+*/
+static void re_sql_func(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ ReCompiled *pRe; /* Compiled regular expression */
+ const char *zPattern; /* The regular expression */
+ const unsigned char *zStr;/* String being searched */
+ const char *zErr; /* Compile error message */
+ int setAux = 0; /* True to invoke sqlite3_set_auxdata() */
+
+ pRe = sqlite3_get_auxdata(context, 0);
+ if( pRe==0 ){
+ zPattern = (const char*)sqlite3_value_text(argv[0]);
+ if( zPattern==0 ) return;
+ zErr = re_compile(&pRe, zPattern, 0);
+ if( zErr ){
+ re_free(pRe);
+ sqlite3_result_error(context, zErr, -1);
+ return;
+ }
+ if( pRe==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+ setAux = 1;
+ }
+ zStr = (const unsigned char*)sqlite3_value_text(argv[1]);
+ if( zStr!=0 ){
+ sqlite3_result_int(context, re_match(pRe, zStr, -1));
+ }
+ if( setAux ){
+ sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free);
+ }
+}
+
+/*
+** Invoke this routine to register the regexp() function with the
+** SQLite database connection.
+*/
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_regexp_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0,
+ re_sql_func, 0, 0);
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0,
+ re_sql_func, 0, 0);
+ return rc;
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/remember.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/remember.c 2019-10-08 13:42:19.190590600 +0200
@@ -0,0 +1,82 @@
+/*
+** 2016-08-09
+**
+** 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 demonstrates how to create an SQL function that is a pass-through
+** for integer values (it returns a copy of its argument) but also saves the
+** value that is passed through into a C-language variable. The address of
+** the C-language variable is supplied as the second argument.
+**
+** This allows, for example, a counter to incremented and the original
+** value retrieved, atomically, using a single statement:
+**
+** UPDATE counterTab SET cnt=remember(cnt,$PTR)+1 WHERE id=$ID
+**
+** Prepare the above statement once. Then to use it, bind the address
+** of the output variable to $PTR using sqlite3_bind_pointer() with a
+** pointer type of "carray" and bind the id of the counter to $ID and
+** run the prepared statement.
+**
+** This implementation of the remember() function uses a "carray"
+** pointer so that it can share pointers with the carray() extension.
+**
+** One can imagine doing similar things with floating-point values and
+** strings, but this demonstration extension will stick to using just
+** integers.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <stddef.h>
+
+/*
+** remember(V,PTR)
+**
+** Return the integer value V. Also save the value of V in a
+** C-language variable whose address is PTR.
+*/
+static void rememberFunc(
+ sqlite3_context *pCtx,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3_int64 v;
+ sqlite3_int64 *ptr;
+ assert( argc==2 );
+ v = sqlite3_value_int64(argv[0]);
+ ptr = sqlite3_value_pointer(argv[1], "carray");
+ if( ptr ) *ptr = v;
+ sqlite3_result_int64(pCtx, v);
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_remember_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ rc = sqlite3_create_function(db, "remember", 2, SQLITE_UTF8, 0,
+ rememberFunc, 0, 0);
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ return sqlite3_remember_init(db, pzErrMsg, pApi);
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/rot13.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/rot13.c 2019-10-08 13:42:19.195472300 +0200
@@ -0,0 +1,123 @@
+/*
+** 2013-05-15
+**
+** 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 SQLite extension implements a rot13() function and a rot13
+** collating sequence.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+
+/*
+** Perform rot13 encoding on a single ASCII character.
+*/
+static unsigned char rot13(unsigned char c){
+ if( c>='a' && c<='z' ){
+ c += 13;
+ if( c>'z' ) c -= 26;
+ }else if( c>='A' && c<='Z' ){
+ c += 13;
+ if( c>'Z' ) c -= 26;
+ }
+ return c;
+}
+
+/*
+** Implementation of the rot13() function.
+**
+** Rotate ASCII alphabetic characters by 13 character positions.
+** Non-ASCII characters are unchanged. rot13(rot13(X)) should always
+** equal X.
+*/
+static void rot13func(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const unsigned char *zIn;
+ size_t nIn;
+ unsigned char *zOut;
+ unsigned char *zToFree = 0;
+ size_t i;
+ unsigned char zTemp[100];
+ assert( argc==1 );
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
+ zIn = (const unsigned char*)sqlite3_value_text(argv[0]);
+ nIn = sqlite3_value_bytes(argv[0]);
+ if( nIn<sizeof(zTemp)-1 ){
+ zOut = zTemp;
+ }else{
+ zOut = zToFree = (unsigned char*)sqlite3_malloc( nIn+1 );
+ if( zOut==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+ }
+ for(i=0; i<nIn; i++) zOut[i] = rot13(zIn[i]);
+ zOut[i] = 0;
+ sqlite3_result_text(context, (char*)zOut, i, SQLITE_TRANSIENT);
+ sqlite3_free(zToFree);
+}
+
+/*
+** Implement the rot13 collating sequence so that if
+**
+** x=y COLLATE rot13
+**
+** Then
+**
+** rot13(x)=rot13(y) COLLATE binary
+*/
+static int rot13CollFunc(
+ void *notUsed,
+ int nKey1, const void *pKey1,
+ int nKey2, const void *pKey2
+){
+ const char *zA = (const char*)pKey1;
+ const char *zB = (const char*)pKey2;
+ int i, x;
+ for(i=0; i<nKey1 && i<nKey2; i++){
+ x = (int)rot13(zA[i]) - (int)rot13(zB[i]);
+ if( x!=0 ) return x;
+ }
+ return nKey1 - nKey2;
+}
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_rot_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "rot13", 1, SQLITE_UTF8, 0,
+ rot13func, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_collation(db, "rot13", SQLITE_UTF8, 0, rot13CollFunc);
+ }
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ return sqlite3_rot_init(db, pzErrMsg, pApi);
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/scrub.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/scrub.c 2019-10-08 13:42:19.196449100 +0200
@@ -0,0 +1,610 @@
+/*
+** 2016-05-05
+**
+** 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 implements a utility function (and a utility program) that
+** makes a copy of an SQLite database while simultaneously zeroing out all
+** deleted content.
+**
+** Normally (when PRAGMA secure_delete=OFF, which is the default) when SQLite
+** deletes content, it does not overwrite the deleted content but rather marks
+** the region of the file that held that content as being reusable. This can
+** cause deleted content to recoverable from the database file. This stale
+** content is removed by the VACUUM command, but VACUUM can be expensive for
+** large databases. When in PRAGMA secure_delete=ON mode, the deleted content
+** is zeroed, but secure_delete=ON has overhead as well.
+**
+** This utility attempts to make a copy of a complete SQLite database where
+** all of the deleted content is zeroed out in the copy, and it attempts to
+** do so while being faster than running VACUUM.
+**
+** Usage:
+**
+** int sqlite3_scrub_backup(
+** const char *zSourceFile, // Source database filename
+** const char *zDestFile, // Destination database filename
+** char **pzErrMsg // Write error message here
+** );
+**
+** Simply call the API above specifying the filename of the source database
+** and the name of the backup copy. The source database must already exist
+** and can be in active use. (A read lock is held during the backup.) The
+** destination file should not previously exist. If the pzErrMsg parameter
+** is non-NULL and if an error occurs, then an error message might be written
+** into memory obtained from sqlite3_malloc() and *pzErrMsg made to point to
+** that error message. But if the error is an OOM, the error might not be
+** reported. The routine always returns non-zero if there is an error.
+**
+** If compiled with -DSCRUB_STANDALONE then a main() procedure is added and
+** this file becomes a standalone program that can be run as follows:
+**
+** ./sqlite3scrub SOURCE DEST
+*/
+#include "sqlite3.h"
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+typedef struct ScrubState ScrubState;
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+
+/* State information for a scrub-and-backup operation */
+struct ScrubState {
+ const char *zSrcFile; /* Name of the source file */
+ const char *zDestFile; /* Name of the destination file */
+ int rcErr; /* Error code */
+ char *zErr; /* Error message text */
+ sqlite3 *dbSrc; /* Source database connection */
+ sqlite3_file *pSrc; /* Source file handle */
+ sqlite3 *dbDest; /* Destination database connection */
+ sqlite3_file *pDest; /* Destination file handle */
+ u32 szPage; /* Page size */
+ u32 szUsable; /* Usable bytes on each page */
+ u32 nPage; /* Number of pages */
+ u32 iLastPage; /* Page number of last page written so far*/
+ u8 *page1; /* Content of page 1 */
+};
+
+/* Store an error message */
+static void scrubBackupErr(ScrubState *p, const char *zFormat, ...){
+ va_list ap;
+ sqlite3_free(p->zErr);
+ va_start(ap, zFormat);
+ p->zErr = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+ if( p->rcErr==0 ) p->rcErr = SQLITE_ERROR;
+}
+
+/* Allocate memory to hold a single page of content */
+static u8 *scrubBackupAllocPage(ScrubState *p){
+ u8 *pPage;
+ if( p->rcErr ) return 0;
+ pPage = sqlite3_malloc( p->szPage );
+ if( pPage==0 ) p->rcErr = SQLITE_NOMEM;
+ return pPage;
+}
+
+/* Read a page from the source database into memory. Use the memory
+** provided by pBuf if not NULL or allocate a new page if pBuf==NULL.
+*/
+static u8 *scrubBackupRead(ScrubState *p, int pgno, u8 *pBuf){
+ int rc;
+ sqlite3_int64 iOff;
+ u8 *pOut = pBuf;
+ if( p->rcErr ) return 0;
+ if( pOut==0 ){
+ pOut = scrubBackupAllocPage(p);
+ if( pOut==0 ) return 0;
+ }
+ iOff = (pgno-1)*(sqlite3_int64)p->szPage;
+ rc = p->pSrc->pMethods->xRead(p->pSrc, pOut, p->szPage, iOff);
+ if( rc!=SQLITE_OK ){
+ if( pBuf==0 ) sqlite3_free(pOut);
+ pOut = 0;
+ scrubBackupErr(p, "read failed for page %d", pgno);
+ p->rcErr = SQLITE_IOERR;
+ }
+ return pOut;
+}
+
+/* Write a page to the destination database */
+static void scrubBackupWrite(ScrubState *p, int pgno, const u8 *pData){
+ int rc;
+ sqlite3_int64 iOff;
+ if( p->rcErr ) return;
+ iOff = (pgno-1)*(sqlite3_int64)p->szPage;
+ rc = p->pDest->pMethods->xWrite(p->pDest, pData, p->szPage, iOff);
+ if( rc!=SQLITE_OK ){
+ scrubBackupErr(p, "write failed for page %d", pgno);
+ p->rcErr = SQLITE_IOERR;
+ }
+ if( (u32)pgno>p->iLastPage ) p->iLastPage = pgno;
+}
+
+/* Prepare a statement against the "db" database. */
+static sqlite3_stmt *scrubBackupPrepare(
+ ScrubState *p, /* Backup context */
+ sqlite3 *db, /* Database to prepare against */
+ const char *zSql /* SQL statement */
+){
+ sqlite3_stmt *pStmt;
+ if( p->rcErr ) return 0;
+ p->rcErr = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+ if( p->rcErr ){
+ scrubBackupErr(p, "SQL error \"%s\" on \"%s\"",
+ sqlite3_errmsg(db), zSql);
+ sqlite3_finalize(pStmt);
+ return 0;
+ }
+ return pStmt;
+}
+
+
+/* Open the source database file */
+static void scrubBackupOpenSrc(ScrubState *p){
+ sqlite3_stmt *pStmt;
+ int rc;
+ /* Open the source database file */
+ p->rcErr = sqlite3_open_v2(p->zSrcFile, &p->dbSrc,
+ SQLITE_OPEN_READWRITE |
+ SQLITE_OPEN_URI | SQLITE_OPEN_PRIVATECACHE, 0);
+ if( p->rcErr ){
+ scrubBackupErr(p, "cannot open source database: %s",
+ sqlite3_errmsg(p->dbSrc));
+ return;
+ }
+ p->rcErr = sqlite3_exec(p->dbSrc, "SELECT 1 FROM sqlite_master; BEGIN;",
+ 0, 0, 0);
+ if( p->rcErr ){
+ scrubBackupErr(p,
+ "cannot start a read transaction on the source database: %s",
+ sqlite3_errmsg(p->dbSrc));
+ return;
+ }
+ rc = sqlite3_wal_checkpoint_v2(p->dbSrc, "main", SQLITE_CHECKPOINT_FULL,
+ 0, 0);
+ if( rc ){
+ scrubBackupErr(p, "cannot checkpoint the source database");
+ return;
+ }
+ pStmt = scrubBackupPrepare(p, p->dbSrc, "PRAGMA page_size");
+ if( pStmt==0 ) return;
+ rc = sqlite3_step(pStmt);
+ if( rc==SQLITE_ROW ){
+ p->szPage = sqlite3_column_int(pStmt, 0);
+ }else{
+ scrubBackupErr(p, "unable to determine the page size");
+ }
+ sqlite3_finalize(pStmt);
+ if( p->rcErr ) return;
+ pStmt = scrubBackupPrepare(p, p->dbSrc, "PRAGMA page_count");
+ if( pStmt==0 ) return;
+ rc = sqlite3_step(pStmt);
+ if( rc==SQLITE_ROW ){
+ p->nPage = sqlite3_column_int(pStmt, 0);
+ }else{
+ scrubBackupErr(p, "unable to determine the size of the source database");
+ }
+ sqlite3_finalize(pStmt);
+ sqlite3_file_control(p->dbSrc, "main", SQLITE_FCNTL_FILE_POINTER, &p->pSrc);
+ if( p->pSrc==0 || p->pSrc->pMethods==0 ){
+ scrubBackupErr(p, "cannot get the source file handle");
+ p->rcErr = SQLITE_ERROR;
+ }
+}
+
+/* Create and open the destination file */
+static void scrubBackupOpenDest(ScrubState *p){
+ sqlite3_stmt *pStmt;
+ int rc;
+ char *zSql;
+ if( p->rcErr ) return;
+ p->rcErr = sqlite3_open_v2(p->zDestFile, &p->dbDest,
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
+ SQLITE_OPEN_URI | SQLITE_OPEN_PRIVATECACHE, 0);
+ if( p->rcErr ){
+ scrubBackupErr(p, "cannot open destination database: %s",
+ sqlite3_errmsg(p->dbDest));
+ return;
+ }
+ zSql = sqlite3_mprintf("PRAGMA page_size(%u);", p->szPage);
+ if( zSql==0 ){
+ p->rcErr = SQLITE_NOMEM;
+ return;
+ }
+ p->rcErr = sqlite3_exec(p->dbDest, zSql, 0, 0, 0);
+ sqlite3_free(zSql);
+ if( p->rcErr ){
+ scrubBackupErr(p,
+ "cannot set the page size on the destination database: %s",
+ sqlite3_errmsg(p->dbDest));
+ return;
+ }
+ sqlite3_exec(p->dbDest, "PRAGMA journal_mode=OFF;", 0, 0, 0);
+ p->rcErr = sqlite3_exec(p->dbDest, "BEGIN EXCLUSIVE;", 0, 0, 0);
+ if( p->rcErr ){
+ scrubBackupErr(p,
+ "cannot start a write transaction on the destination database: %s",
+ sqlite3_errmsg(p->dbDest));
+ return;
+ }
+ pStmt = scrubBackupPrepare(p, p->dbDest, "PRAGMA page_count;");
+ if( pStmt==0 ) return;
+ rc = sqlite3_step(pStmt);
+ if( rc!=SQLITE_ROW ){
+ scrubBackupErr(p, "cannot measure the size of the destination");
+ }else if( sqlite3_column_int(pStmt, 0)>1 ){
+ scrubBackupErr(p, "destination database is not empty - holds %d pages",
+ sqlite3_column_int(pStmt, 0));
+ }
+ sqlite3_finalize(pStmt);
+ sqlite3_file_control(p->dbDest, "main", SQLITE_FCNTL_FILE_POINTER, &p->pDest);
+ if( p->pDest==0 || p->pDest->pMethods==0 ){
+ scrubBackupErr(p, "cannot get the destination file handle");
+ p->rcErr = SQLITE_ERROR;
+ }
+}
+
+/* Read a 32-bit big-endian integer */
+static u32 scrubBackupInt32(const u8 *a){
+ u32 v = a[3];
+ v += ((u32)a[2])<<8;
+ v += ((u32)a[1])<<16;
+ v += ((u32)a[0])<<24;
+ return v;
+}
+
+/* Read a 16-bit big-endian integer */
+static u32 scrubBackupInt16(const u8 *a){
+ return (a[0]<<8) + a[1];
+}
+
+/*
+** Read a varint. Put the value in *pVal and return the number of bytes.
+*/
+static int scrubBackupVarint(const u8 *z, sqlite3_int64 *pVal){
+ sqlite3_int64 v = 0;
+ int i;
+ for(i=0; i<8; i++){
+ v = (v<<7) + (z[i]&0x7f);
+ if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; }
+ }
+ v = (v<<8) + (z[i]&0xff);
+ *pVal = v;
+ return 9;
+}
+
+/*
+** Return the number of bytes in a varint.
+*/
+static int scrubBackupVarintSize(const u8 *z){
+ int i;
+ for(i=0; i<8; i++){
+ if( (z[i]&0x80)==0 ){ return i+1; }
+ }
+ return 9;
+}
+
+/*
+** Copy the freelist trunk page given, and all its descendents,
+** zeroing out as much as possible in the process.
+*/
+static void scrubBackupFreelist(ScrubState *p, int pgno, u32 nFree){
+ u8 *a, *aBuf;
+ u32 n, mx;
+
+ if( p->rcErr ) return;
+ aBuf = scrubBackupAllocPage(p);
+ if( aBuf==0 ) return;
+
+ while( pgno && nFree){
+ a = scrubBackupRead(p, pgno, aBuf);
+ if( a==0 ) break;
+ n = scrubBackupInt32(&a[4]);
+ mx = p->szUsable/4 - 2;
+ if( n<mx ){
+ memset(&a[n*4+8], 0, 4*(mx-n));
+ }
+ scrubBackupWrite(p, pgno, a);
+ pgno = scrubBackupInt32(a);
+#if 0
+ /* There is really no point in copying the freelist leaf pages.
+ ** Simply leave them uninitialized in the destination database. The
+ ** OS filesystem should zero those pages for us automatically.
+ */
+ for(i=0; i<n && nFree; i++){
+ u32 iLeaf = scrubBackupInt32(&a[i*4+8]);
+ if( aZero==0 ){
+ aZero = scrubBackupAllocPage(p);
+ if( aZero==0 ){ pgno = 0; break; }
+ memset(aZero, 0, p->szPage);
+ }
+ scrubBackupWrite(p, iLeaf, aZero);
+ nFree--;
+ }
+#endif
+ }
+ sqlite3_free(aBuf);
+}
+
+/*
+** Copy an overflow chain from source to destination. Zero out any
+** unused tail at the end of the overflow chain.
+*/
+static void scrubBackupOverflow(ScrubState *p, int pgno, u32 nByte){
+ u8 *a, *aBuf;
+
+ aBuf = scrubBackupAllocPage(p);
+ if( aBuf==0 ) return;
+ while( nByte>0 && pgno!=0 ){
+ a = scrubBackupRead(p, pgno, aBuf);
+ if( a==0 ) break;
+ if( nByte >= (p->szUsable)-4 ){
+ nByte -= (p->szUsable) - 4;
+ }else{
+ u32 x = (p->szUsable - 4) - nByte;
+ u32 i = p->szUsable - x;
+ memset(&a[i], 0, x);
+ nByte = 0;
+ }
+ scrubBackupWrite(p, pgno, a);
+ pgno = scrubBackupInt32(a);
+ }
+ sqlite3_free(aBuf);
+}
+
+
+/*
+** Copy B-Tree page pgno, and all of its children, from source to destination.
+** Zero out deleted content during the copy.
+*/
+static void scrubBackupBtree(ScrubState *p, int pgno, int iDepth){
+ u8 *a;
+ u32 i, n, pc;
+ u32 nCell;
+ u32 nPrefix;
+ u32 szHdr;
+ u32 iChild;
+ u8 *aTop;
+ u8 *aCell;
+ u32 x, y;
+ int ln = 0;
+
+
+ if( p->rcErr ) return;
+ if( iDepth>50 ){
+ scrubBackupErr(p, "corrupt: b-tree too deep at page %d", pgno);
+ return;
+ }
+ if( pgno==1 ){
+ a = p->page1;
+ }else{
+ a = scrubBackupRead(p, pgno, 0);
+ if( a==0 ) return;
+ }
+ nPrefix = pgno==1 ? 100 : 0;
+ aTop = &a[nPrefix];
+ szHdr = 8 + 4*(aTop[0]==0x02 || aTop[0]==0x05);
+ aCell = aTop + szHdr;
+ nCell = scrubBackupInt16(&aTop[3]);
+
+ /* Zero out the gap between the cell index and the start of the
+ ** cell content area */
+ x = scrubBackupInt16(&aTop[5]); /* First byte of cell content area */
+ if( x>p->szUsable ){ ln=__LINE__; goto btree_corrupt; }
+ y = szHdr + nPrefix + nCell*2;
+ if( y>x ){ ln=__LINE__; goto btree_corrupt; }
+ if( y<x ) memset(a+y, 0, x-y); /* Zero the gap */
+
+ /* Zero out all the free blocks */
+ pc = scrubBackupInt16(&aTop[1]);
+ if( pc>0 && pc<x ){ ln=__LINE__; goto btree_corrupt; }
+ while( pc ){
+ if( pc>(p->szUsable)-4 ){ ln=__LINE__; goto btree_corrupt; }
+ n = scrubBackupInt16(&a[pc+2]);
+ if( pc+n>(p->szUsable) ){ ln=__LINE__; goto btree_corrupt; }
+ if( n>4 ) memset(&a[pc+4], 0, n-4);
+ x = scrubBackupInt16(&a[pc]);
+ if( x<pc+4 && x>0 ){ ln=__LINE__; goto btree_corrupt; }
+ pc = x;
+ }
+
+ /* Write this one page */
+ scrubBackupWrite(p, pgno, a);
+
+ /* Walk the tree and process child pages */
+ for(i=0; i<nCell; i++){
+ u32 X, M, K, nLocal;
+ sqlite3_int64 P;
+ pc = scrubBackupInt16(&aCell[i*2]);
+ if( pc <= szHdr ){ ln=__LINE__; goto btree_corrupt; }
+ if( pc > p->szUsable-3 ){ ln=__LINE__; goto btree_corrupt; }
+ if( aTop[0]==0x05 || aTop[0]==0x02 ){
+ if( pc+4 > p->szUsable ){ ln=__LINE__; goto btree_corrupt; }
+ iChild = scrubBackupInt32(&a[pc]);
+ pc += 4;
+ scrubBackupBtree(p, iChild, iDepth+1);
+ if( aTop[0]==0x05 ) continue;
+ }
+ pc += scrubBackupVarint(&a[pc], &P);
+ if( pc >= p->szUsable ){ ln=__LINE__; goto btree_corrupt; }
+ if( aTop[0]==0x0d ){
+ X = p->szUsable - 35;
+ }else{
+ X = ((p->szUsable - 12)*64/255) - 23;
+ }
+ if( P<=X ){
+ /* All content is local. No overflow */
+ continue;
+ }
+ M = ((p->szUsable - 12)*32/255)-23;
+ K = M + ((P-M)%(p->szUsable-4));
+ if( aTop[0]==0x0d ){
+ pc += scrubBackupVarintSize(&a[pc]);
+ if( pc > (p->szUsable-4) ){ ln=__LINE__; goto btree_corrupt; }
+ }
+ nLocal = K<=X ? K : M;
+ if( pc+nLocal > p->szUsable-4 ){ ln=__LINE__; goto btree_corrupt; }
+ iChild = scrubBackupInt32(&a[pc+nLocal]);
+ scrubBackupOverflow(p, iChild, (u32)(P-nLocal));
+ }
+
+ /* Walk the right-most tree */
+ if( aTop[0]==0x05 || aTop[0]==0x02 ){
+ iChild = scrubBackupInt32(&aTop[8]);
+ scrubBackupBtree(p, iChild, iDepth+1);
+ }
+
+ /* All done */
+ if( pgno>1 ) sqlite3_free(a);
+ return;
+
+btree_corrupt:
+ scrubBackupErr(p, "corruption on page %d of source database (errid=%d)",
+ pgno, ln);
+ if( pgno>1 ) sqlite3_free(a);
+}
+
+/*
+** Copy all ptrmap pages from source to destination.
+** This routine is only called if the source database is in autovacuum
+** or incremental vacuum mode.
+*/
+static void scrubBackupPtrmap(ScrubState *p){
+ u32 pgno = 2;
+ u32 J = p->szUsable/5;
+ u32 iLock = (1073742335/p->szPage)+1;
+ u8 *a, *pBuf;
+ if( p->rcErr ) return;
+ pBuf = scrubBackupAllocPage(p);
+ if( pBuf==0 ) return;
+ while( pgno<=p->nPage ){
+ a = scrubBackupRead(p, pgno, pBuf);
+ if( a==0 ) break;
+ scrubBackupWrite(p, pgno, a);
+ pgno += J+1;
+ if( pgno==iLock ) pgno++;
+ }
+ sqlite3_free(pBuf);
+}
+
+int sqlite3_scrub_backup(
+ const char *zSrcFile, /* Source file */
+ const char *zDestFile, /* Destination file */
+ char **pzErr /* Write error here if non-NULL */
+){
+ ScrubState s;
+ u32 n, i;
+ sqlite3_stmt *pStmt;
+
+ memset(&s, 0, sizeof(s));
+ s.zSrcFile = zSrcFile;
+ s.zDestFile = zDestFile;
+
+ /* Open both source and destination databases */
+ scrubBackupOpenSrc(&s);
+ scrubBackupOpenDest(&s);
+
+ /* Read in page 1 */
+ s.page1 = scrubBackupRead(&s, 1, 0);
+ if( s.page1==0 ) goto scrub_abort;
+ s.szUsable = s.szPage - s.page1[20];
+
+ /* Copy the freelist */
+ n = scrubBackupInt32(&s.page1[36]);
+ i = scrubBackupInt32(&s.page1[32]);
+ if( n ) scrubBackupFreelist(&s, i, n);
+
+ /* Copy ptrmap pages */
+ n = scrubBackupInt32(&s.page1[52]);
+ if( n ) scrubBackupPtrmap(&s);
+
+ /* Copy all of the btrees */
+ scrubBackupBtree(&s, 1, 0);
+ pStmt = scrubBackupPrepare(&s, s.dbSrc,
+ "SELECT rootpage FROM sqlite_master WHERE coalesce(rootpage,0)>0");
+ if( pStmt==0 ) goto scrub_abort;
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ i = (u32)sqlite3_column_int(pStmt, 0);
+ scrubBackupBtree(&s, i, 0);
+ }
+ sqlite3_finalize(pStmt);
+
+ /* If the last page of the input db file is a free-list leaf, then the
+ ** backup file on disk is still smaller than the size indicated within
+ ** the database header. In this case, write a page of zeroes to the
+ ** last page of the backup database so that SQLite does not mistakenly
+ ** think the db is corrupt. */
+ if( s.iLastPage<s.nPage ){
+ u8 *aZero = scrubBackupAllocPage(&s);
+ if( aZero ){
+ memset(aZero, 0, s.szPage);
+ scrubBackupWrite(&s, s.nPage, aZero);
+ sqlite3_free(aZero);
+ }
+ }
+
+scrub_abort:
+ /* Close the destination database without closing the transaction. If we
+ ** commit, page zero will be overwritten. */
+ sqlite3_close(s.dbDest);
+
+ /* But do close out the read-transaction on the source database */
+ sqlite3_exec(s.dbSrc, "COMMIT;", 0, 0, 0);
+ sqlite3_close(s.dbSrc);
+ sqlite3_free(s.page1);
+ if( pzErr ){
+ *pzErr = s.zErr;
+ }else{
+ sqlite3_free(s.zErr);
+ }
+ return s.rcErr;
+}
+
+#ifdef SCRUB_STANDALONE
+/* Error and warning log */
+static void errorLogCallback(void *pNotUsed, int iErr, const char *zMsg){
+ const char *zType;
+ switch( iErr&0xff ){
+ case SQLITE_WARNING: zType = "WARNING"; break;
+ case SQLITE_NOTICE: zType = "NOTICE"; break;
+ default: zType = "ERROR"; break;
+ }
+ fprintf(stderr, "%s: %s\n", zType, zMsg);
+}
+
+/* The main() routine when this utility is run as a stand-alone program */
+int main(int argc, char **argv){
+ char *zErr = 0;
+ int rc;
+ if( argc!=3 ){
+ fprintf(stderr,"Usage: %s SOURCE DESTINATION\n", argv[0]);
+ exit(1);
+ }
+ sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback, 0);
+ rc = sqlite3_scrub_backup(argv[1], argv[2], &zErr);
+ if( rc==SQLITE_NOMEM ){
+ fprintf(stderr, "%s: out of memory\n", argv[0]);
+ exit(1);
+ }
+ if( zErr ){
+ fprintf(stderr, "%s: %s\n", argv[0], zErr);
+ sqlite3_free(zErr);
+ exit(1);
+ }
+ return 0;
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/series.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/series.c 2019-10-08 13:42:19.201330200 +0200
@@ -0,0 +1,432 @@
+/*
+** 2015-08-18
+**
+** 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 demonstrates how to create a table-valued-function using
+** a virtual table. This demo implements the generate_series() function
+** which gives similar results to the eponymous function in PostgreSQL.
+** Examples:
+**
+** SELECT * FROM generate_series(0,100,5);
+**
+** The query above returns integers from 0 through 100 counting by steps
+** of 5.
+**
+** SELECT * FROM generate_series(0,100);
+**
+** Integers from 0 through 100 with a step size of 1.
+**
+** SELECT * FROM generate_series(20) LIMIT 10;
+**
+** Integers 20 through 29.
+**
+** HOW IT WORKS
+**
+** The generate_series "function" is really a virtual table with the
+** following schema:
+**
+** CREATE TABLE generate_series(
+** value,
+** start HIDDEN,
+** stop HIDDEN,
+** step HIDDEN
+** );
+**
+** Function arguments in queries against this virtual table are translated
+** into equality constraints against successive hidden columns. In other
+** words, the following pairs of queries are equivalent to each other:
+**
+** SELECT * FROM generate_series(0,100,5);
+** SELECT * FROM generate_series WHERE start=0 AND stop=100 AND step=5;
+**
+** SELECT * FROM generate_series(0,100);
+** SELECT * FROM generate_series WHERE start=0 AND stop=100;
+**
+** SELECT * FROM generate_series(20) LIMIT 10;
+** SELECT * FROM generate_series WHERE start=20 LIMIT 10;
+**
+** The generate_series virtual table implementation leaves the xCreate method
+** set to NULL. This means that it is not possible to do a CREATE VIRTUAL
+** TABLE command with "generate_series" as the USING argument. Instead, there
+** is a single generate_series virtual table that is always available without
+** having to be created first.
+**
+** The xBestIndex method looks for equality constraints against the hidden
+** start, stop, and step columns, and if present, it uses those constraints
+** to bound the sequence of generated values. If the equality constraints
+** are missing, it uses 0 for start, 4294967295 for stop, and 1 for step.
+** xBestIndex returns a small cost when both start and stop are available,
+** and a very large cost if either start or stop are unavailable. This
+** encourages the query planner to order joins such that the bounds of the
+** series are well-defined.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+
+/* series_cursor is a subclass of sqlite3_vtab_cursor which will
+** serve as the underlying representation of a cursor that scans
+** over rows of the result
+*/
+typedef struct series_cursor series_cursor;
+struct series_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ int isDesc; /* True to count down rather than up */
+ sqlite3_int64 iRowid; /* The rowid */
+ sqlite3_int64 iValue; /* Current value ("value") */
+ sqlite3_int64 mnValue; /* Mimimum value ("start") */
+ sqlite3_int64 mxValue; /* Maximum value ("stop") */
+ sqlite3_int64 iStep; /* Increment ("step") */
+};
+
+/*
+** The seriesConnect() method is invoked to create a new
+** series_vtab that describes the generate_series virtual table.
+**
+** Think of this routine as the constructor for series_vtab objects.
+**
+** All this routine needs to do is:
+**
+** (1) Allocate the series_vtab object and initialize all fields.
+**
+** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
+** result set of queries against generate_series will look like.
+*/
+static int seriesConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ sqlite3_vtab *pNew;
+ int rc;
+
+/* Column numbers */
+#define SERIES_COLUMN_VALUE 0
+#define SERIES_COLUMN_START 1
+#define SERIES_COLUMN_STOP 2
+#define SERIES_COLUMN_STEP 3
+
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x(value,start hidden,stop hidden,step hidden)");
+ if( rc==SQLITE_OK ){
+ pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for series_cursor objects.
+*/
+static int seriesDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new series_cursor object.
+*/
+static int seriesOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ series_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Destructor for a series_cursor.
+*/
+static int seriesClose(sqlite3_vtab_cursor *cur){
+ sqlite3_free(cur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a series_cursor to its next row of output.
+*/
+static int seriesNext(sqlite3_vtab_cursor *cur){
+ series_cursor *pCur = (series_cursor*)cur;
+ if( pCur->isDesc ){
+ pCur->iValue -= pCur->iStep;
+ }else{
+ pCur->iValue += pCur->iStep;
+ }
+ pCur->iRowid++;
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the series_cursor
+** is currently pointing.
+*/
+static int seriesColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ series_cursor *pCur = (series_cursor*)cur;
+ sqlite3_int64 x = 0;
+ switch( i ){
+ case SERIES_COLUMN_START: x = pCur->mnValue; break;
+ case SERIES_COLUMN_STOP: x = pCur->mxValue; break;
+ case SERIES_COLUMN_STEP: x = pCur->iStep; break;
+ default: x = pCur->iValue; break;
+ }
+ sqlite3_result_int64(ctx, x);
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** first row returned is assigned rowid value 1, and each subsequent
+** row a value 1 more than that of the previous.
+*/
+static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ series_cursor *pCur = (series_cursor*)cur;
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int seriesEof(sqlite3_vtab_cursor *cur){
+ series_cursor *pCur = (series_cursor*)cur;
+ if( pCur->isDesc ){
+ return pCur->iValue < pCur->mnValue;
+ }else{
+ return pCur->iValue > pCur->mxValue;
+ }
+}
+
+/* True to cause run-time checking of the start=, stop=, and/or step=
+** parameters. The only reason to do this is for testing the
+** constraint checking logic for virtual tables in the SQLite core.
+*/
+#ifndef SQLITE_SERIES_CONSTRAINT_VERIFY
+# define SQLITE_SERIES_CONSTRAINT_VERIFY 0
+#endif
+
+/*
+** This method is called to "rewind" the series_cursor object back
+** to the first row of output. This method is always called at least
+** once prior to any call to seriesColumn() or seriesRowid() or
+** seriesEof().
+**
+** The query plan selected by seriesBestIndex is passed in the idxNum
+** parameter. (idxStr is not used in this implementation.) idxNum
+** is a bitmask showing which constraints are available:
+**
+** 1: start=VALUE
+** 2: stop=VALUE
+** 4: step=VALUE
+**
+** Also, if bit 8 is set, that means that the series should be output
+** in descending order rather than in ascending order.
+**
+** This routine should initialize the cursor and position it so that it
+** is pointing at the first row, or pointing off the end of the table
+** (so that seriesEof() will return true) if the table is empty.
+*/
+static int seriesFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ series_cursor *pCur = (series_cursor *)pVtabCursor;
+ int i = 0;
+ if( idxNum & 1 ){
+ pCur->mnValue = sqlite3_value_int64(argv[i++]);
+ }else{
+ pCur->mnValue = 0;
+ }
+ if( idxNum & 2 ){
+ pCur->mxValue = sqlite3_value_int64(argv[i++]);
+ }else{
+ pCur->mxValue = 0xffffffff;
+ }
+ if( idxNum & 4 ){
+ pCur->iStep = sqlite3_value_int64(argv[i++]);
+ if( pCur->iStep<1 ) pCur->iStep = 1;
+ }else{
+ pCur->iStep = 1;
+ }
+ for(i=0; i<argc; i++){
+ if( sqlite3_value_type(argv[i])==SQLITE_NULL ){
+ /* If any of the constraints have a NULL value, then return no rows.
+ ** See ticket https://www.sqlite.org/src/info/fac496b61722daf2 */
+ pCur->mnValue = 1;
+ pCur->mxValue = 0;
+ break;
+ }
+ }
+ if( idxNum & 8 ){
+ pCur->isDesc = 1;
+ pCur->iValue = pCur->mxValue;
+ if( pCur->iStep>0 ){
+ pCur->iValue -= (pCur->mxValue - pCur->mnValue)%pCur->iStep;
+ }
+ }else{
+ pCur->isDesc = 0;
+ pCur->iValue = pCur->mnValue;
+ }
+ pCur->iRowid = 1;
+ return SQLITE_OK;
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the generate_series virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+**
+** In this implementation idxNum is used to represent the
+** query plan. idxStr is unused.
+**
+** The query plan is represented by bits in idxNum:
+**
+** (1) start = $value -- constraint exists
+** (2) stop = $value -- constraint exists
+** (4) step = $value -- constraint exists
+** (8) output in descending order
+*/
+static int seriesBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int i, j; /* Loop over constraints */
+ int idxNum = 0; /* The query plan bitmask */
+ int unusableMask = 0; /* Mask of unusable constraints */
+ int nArg = 0; /* Number of arguments that seriesFilter() expects */
+ int aIdx[3]; /* Constraints on start, stop, and step */
+ const struct sqlite3_index_constraint *pConstraint;
+
+ /* This implementation assumes that the start, stop, and step columns
+ ** are the last three columns in the virtual table. */
+ assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 );
+ assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 );
+ aIdx[0] = aIdx[1] = aIdx[2] = -1;
+ pConstraint = pIdxInfo->aConstraint;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
+ int iCol; /* 0 for start, 1 for stop, 2 for step */
+ int iMask; /* bitmask for those column */
+ if( pConstraint->iColumn<SERIES_COLUMN_START ) continue;
+ iCol = pConstraint->iColumn - SERIES_COLUMN_START;
+ assert( iCol>=0 && iCol<=2 );
+ iMask = 1 << iCol;
+ if( pConstraint->usable==0 ){
+ unusableMask |= iMask;
+ continue;
+ }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ idxNum |= iMask;
+ aIdx[iCol] = i;
+ }
+ }
+ for(i=0; i<3; i++){
+ if( (j = aIdx[i])>=0 ){
+ pIdxInfo->aConstraintUsage[j].argvIndex = ++nArg;
+ pIdxInfo->aConstraintUsage[j].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
+ }
+ }
+ if( (unusableMask & ~idxNum)!=0 ){
+ /* The start, stop, and step columns are inputs. Therefore if there
+ ** are unusable constraints on any of start, stop, or step then
+ ** this plan is unusable */
+ return SQLITE_CONSTRAINT;
+ }
+ if( (idxNum & 3)==3 ){
+ /* Both start= and stop= boundaries are available. This is the
+ ** the preferred case */
+ pIdxInfo->estimatedCost = (double)(2 - ((idxNum&4)!=0));
+ pIdxInfo->estimatedRows = 1000;
+ if( pIdxInfo->nOrderBy==1 ){
+ if( pIdxInfo->aOrderBy[0].desc ) idxNum |= 8;
+ pIdxInfo->orderByConsumed = 1;
+ }
+ }else{
+ /* If either boundary is missing, we have to generate a huge span
+ ** of numbers. Make this case very expensive so that the query
+ ** planner will work hard to avoid it. */
+ pIdxInfo->estimatedRows = 2147483647;
+ }
+ pIdxInfo->idxNum = idxNum;
+ return SQLITE_OK;
+}
+
+/*
+** This following structure defines all the methods for the
+** generate_series virtual table.
+*/
+static const sqlite3_module seriesModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ seriesConnect, /* xConnect */
+ seriesBestIndex, /* xBestIndex */
+ seriesDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ seriesOpen, /* xOpen - open a cursor */
+ seriesClose, /* xClose - close a cursor */
+ seriesFilter, /* xFilter - configure scan constraints */
+ seriesNext, /* xNext - advance a cursor */
+ seriesEof, /* xEof - check for end of scan */
+ seriesColumn, /* xColumn - read data */
+ seriesRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+};
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_series_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( sqlite3_libversion_number()<3008012 ){
+ *pzErrMsg = sqlite3_mprintf(
+ "generate_series() requires SQLite 3.8.12 or later");
+ return SQLITE_ERROR;
+ }
+ rc = sqlite3_create_module(db, "generate_series", &seriesModule, 0);
+#endif
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ return sqlite3_series_init(db, pzErrMsg, pApi);
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/sha1.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/sha1.c 2019-10-08 13:42:19.206211900 +0200
@@ -0,0 +1,416 @@
+/*
+** 2017-01-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 SQLite extension implements functions that compute SHA1 hashes.
+** Two SQL functions are implemented:
+**
+** sha1(X)
+** sha1_query(Y)
+**
+** The sha1(X) function computes the SHA1 hash of the input X, or NULL if
+** X is NULL.
+**
+** The sha1_query(Y) function evalutes all queries in the SQL statements of Y
+** and returns a hash of their results.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+#include <stdarg.h>
+
+/******************************************************************************
+** The Hash Engine
+*/
+/* Context for the SHA1 hash */
+typedef struct SHA1Context SHA1Context;
+struct SHA1Context {
+ unsigned int state[5];
+ unsigned int count[2];
+ unsigned char buffer[64];
+};
+
+
+#if __GNUC__ && (defined(__i386__) || defined(__x86_64__))
+/*
+ * GCC by itself only generates left rotates. Use right rotates if
+ * possible to be kinder to dinky implementations with iterative rotate
+ * instructions.
+ */
+#define SHA_ROT(op, x, k) \
+ ({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; })
+#define rol(x,k) SHA_ROT("roll", x, k)
+#define ror(x,k) SHA_ROT("rorl", x, k)
+
+#else
+/* Generic C equivalent */
+#define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r))
+#define rol(x,k) SHA_ROT(x,k,32-(k))
+#define ror(x,k) SHA_ROT(x,32-(k),k)
+#endif
+
+
+#define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \
+ |(rol(block[i],8)&0x00FF00FF))
+#define blk0be(i) block[i]
+#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
+ ^block[(i+2)&15]^block[i&15],1))
+
+/*
+ * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
+ *
+ * Rl0() for little-endian and Rb0() for big-endian. Endianness is
+ * determined at run-time.
+ */
+#define Rl0(v,w,x,y,z,i) \
+ z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2);
+#define Rb0(v,w,x,y,z,i) \
+ z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v,5);w=ror(w,2);
+#define R1(v,w,x,y,z,i) \
+ z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=ror(w,2);
+#define R2(v,w,x,y,z,i) \
+ z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=ror(w,2);
+#define R3(v,w,x,y,z,i) \
+ z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=ror(w,2);
+#define R4(v,w,x,y,z,i) \
+ z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2);
+
+/*
+ * Hash a single 512-bit block. This is the core of the algorithm.
+ */
+void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]){
+ unsigned int qq[5]; /* a, b, c, d, e; */
+ static int one = 1;
+ unsigned int block[16];
+ memcpy(block, buffer, 64);
+ memcpy(qq,state,5*sizeof(unsigned int));
+
+#define a qq[0]
+#define b qq[1]
+#define c qq[2]
+#define d qq[3]
+#define e qq[4]
+
+ /* Copy p->state[] to working vars */
+ /*
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ */
+
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ if( 1 == *(unsigned char*)&one ){
+ Rl0(a,b,c,d,e, 0); Rl0(e,a,b,c,d, 1); Rl0(d,e,a,b,c, 2); Rl0(c,d,e,a,b, 3);
+ Rl0(b,c,d,e,a, 4); Rl0(a,b,c,d,e, 5); Rl0(e,a,b,c,d, 6); Rl0(d,e,a,b,c, 7);
+ Rl0(c,d,e,a,b, 8); Rl0(b,c,d,e,a, 9); Rl0(a,b,c,d,e,10); Rl0(e,a,b,c,d,11);
+ Rl0(d,e,a,b,c,12); Rl0(c,d,e,a,b,13); Rl0(b,c,d,e,a,14); Rl0(a,b,c,d,e,15);
+ }else{
+ Rb0(a,b,c,d,e, 0); Rb0(e,a,b,c,d, 1); Rb0(d,e,a,b,c, 2); Rb0(c,d,e,a,b, 3);
+ Rb0(b,c,d,e,a, 4); Rb0(a,b,c,d,e, 5); Rb0(e,a,b,c,d, 6); Rb0(d,e,a,b,c, 7);
+ Rb0(c,d,e,a,b, 8); Rb0(b,c,d,e,a, 9); Rb0(a,b,c,d,e,10); Rb0(e,a,b,c,d,11);
+ Rb0(d,e,a,b,c,12); Rb0(c,d,e,a,b,13); Rb0(b,c,d,e,a,14); Rb0(a,b,c,d,e,15);
+ }
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+
+#undef a
+#undef b
+#undef c
+#undef d
+#undef e
+}
+
+
+/* Initialize a SHA1 context */
+static void hash_init(SHA1Context *p){
+ /* SHA1 initialization constants */
+ p->state[0] = 0x67452301;
+ p->state[1] = 0xEFCDAB89;
+ p->state[2] = 0x98BADCFE;
+ p->state[3] = 0x10325476;
+ p->state[4] = 0xC3D2E1F0;
+ p->count[0] = p->count[1] = 0;
+}
+
+/* Add new content to the SHA1 hash */
+static void hash_step(
+ SHA1Context *p, /* Add content to this context */
+ const unsigned char *data, /* Data to be added */
+ unsigned int len /* Number of bytes in data */
+){
+ unsigned int i, j;
+
+ j = p->count[0];
+ if( (p->count[0] += len << 3) < j ){
+ p->count[1] += (len>>29)+1;
+ }
+ j = (j >> 3) & 63;
+ if( (j + len) > 63 ){
+ (void)memcpy(&p->buffer[j], data, (i = 64-j));
+ SHA1Transform(p->state, p->buffer);
+ for(; i + 63 < len; i += 64){
+ SHA1Transform(p->state, &data[i]);
+ }
+ j = 0;
+ }else{
+ i = 0;
+ }
+ (void)memcpy(&p->buffer[j], &data[i], len - i);
+}
+
+/* Compute a string using sqlite3_vsnprintf() and hash it */
+static void hash_step_vformat(
+ SHA1Context *p, /* Add content to this context */
+ const char *zFormat,
+ ...
+){
+ va_list ap;
+ int n;
+ char zBuf[50];
+ va_start(ap, zFormat);
+ sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap);
+ va_end(ap);
+ n = (int)strlen(zBuf);
+ hash_step(p, (unsigned char*)zBuf, n);
+}
+
+
+/* Add padding and compute the message digest. Render the
+** message digest as lower-case hexadecimal and put it into
+** zOut[]. zOut[] must be at least 41 bytes long. */
+static void hash_finish(
+ SHA1Context *p, /* The SHA1 context to finish and render */
+ char *zOut /* Store hexadecimal hash here */
+){
+ unsigned int i;
+ unsigned char finalcount[8];
+ unsigned char digest[20];
+ static const char zEncode[] = "0123456789abcdef";
+
+ for (i = 0; i < 8; i++){
+ finalcount[i] = (unsigned char)((p->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ hash_step(p, (const unsigned char *)"\200", 1);
+ while ((p->count[0] & 504) != 448){
+ hash_step(p, (const unsigned char *)"\0", 1);
+ }
+ hash_step(p, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++){
+ digest[i] = (unsigned char)((p->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ for(i=0; i<20; i++){
+ zOut[i*2] = zEncode[(digest[i]>>4)&0xf];
+ zOut[i*2+1] = zEncode[digest[i] & 0xf];
+ }
+ zOut[i*2]= 0;
+}
+/* End of the hashing logic
+*****************************************************************************/
+
+/*
+** Implementation of the sha1(X) function.
+**
+** Return a lower-case hexadecimal rendering of the SHA1 hash of the
+** argument X. If X is a BLOB, it is hashed as is. For all other
+** types of input, X is converted into a UTF-8 string and the string
+** is hash without the trailing 0x00 terminator. The hash of a NULL
+** value is NULL.
+*/
+static void sha1Func(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ SHA1Context cx;
+ int eType = sqlite3_value_type(argv[0]);
+ int nByte = sqlite3_value_bytes(argv[0]);
+ char zOut[44];
+
+ assert( argc==1 );
+ if( eType==SQLITE_NULL ) return;
+ hash_init(&cx);
+ if( eType==SQLITE_BLOB ){
+ hash_step(&cx, sqlite3_value_blob(argv[0]), nByte);
+ }else{
+ hash_step(&cx, sqlite3_value_text(argv[0]), nByte);
+ }
+ hash_finish(&cx, zOut);
+ sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
+}
+
+/*
+** Implementation of the sha1_query(SQL) function.
+**
+** This function compiles and runs the SQL statement(s) given in the
+** argument. The results are hashed using SHA1 and that hash is returned.
+**
+** The original SQL text is included as part of the hash.
+**
+** The hash is not just a concatenation of the outputs. Each query
+** is delimited and each row and value within the query is delimited,
+** with all values being marked with their datatypes.
+*/
+static void sha1QueryFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ const char *zSql = (const char*)sqlite3_value_text(argv[0]);
+ sqlite3_stmt *pStmt = 0;
+ int nCol; /* Number of columns in the result set */
+ int i; /* Loop counter */
+ int rc;
+ int n;
+ const char *z;
+ SHA1Context cx;
+ char zOut[44];
+
+ assert( argc==1 );
+ if( zSql==0 ) return;
+ hash_init(&cx);
+ while( zSql[0] ){
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
+ if( rc ){
+ char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s",
+ zSql, sqlite3_errmsg(db));
+ sqlite3_finalize(pStmt);
+ sqlite3_result_error(context, zMsg, -1);
+ sqlite3_free(zMsg);
+ return;
+ }
+ if( !sqlite3_stmt_readonly(pStmt) ){
+ char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt));
+ sqlite3_finalize(pStmt);
+ sqlite3_result_error(context, zMsg, -1);
+ sqlite3_free(zMsg);
+ return;
+ }
+ nCol = sqlite3_column_count(pStmt);
+ z = sqlite3_sql(pStmt);
+ n = (int)strlen(z);
+ hash_step_vformat(&cx,"S%d:",n);
+ hash_step(&cx,(unsigned char*)z,n);
+
+ /* Compute a hash over the result of the query */
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ hash_step(&cx,(const unsigned char*)"R",1);
+ for(i=0; i<nCol; i++){
+ switch( sqlite3_column_type(pStmt,i) ){
+ case SQLITE_NULL: {
+ hash_step(&cx, (const unsigned char*)"N",1);
+ break;
+ }
+ case SQLITE_INTEGER: {
+ sqlite3_uint64 u;
+ int j;
+ unsigned char x[9];
+ sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
+ memcpy(&u, &v, 8);
+ for(j=8; j>=1; j--){
+ x[j] = u & 0xff;
+ u >>= 8;
+ }
+ x[0] = 'I';
+ hash_step(&cx, x, 9);
+ break;
+ }
+ case SQLITE_FLOAT: {
+ sqlite3_uint64 u;
+ int j;
+ unsigned char x[9];
+ double r = sqlite3_column_double(pStmt,i);
+ memcpy(&u, &r, 8);
+ for(j=8; j>=1; j--){
+ x[j] = u & 0xff;
+ u >>= 8;
+ }
+ x[0] = 'F';
+ hash_step(&cx,x,9);
+ break;
+ }
+ case SQLITE_TEXT: {
+ int n2 = sqlite3_column_bytes(pStmt, i);
+ const unsigned char *z2 = sqlite3_column_text(pStmt, i);
+ hash_step_vformat(&cx,"T%d:",n2);
+ hash_step(&cx, z2, n2);
+ break;
+ }
+ case SQLITE_BLOB: {
+ int n2 = sqlite3_column_bytes(pStmt, i);
+ const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
+ hash_step_vformat(&cx,"B%d:",n2);
+ hash_step(&cx, z2, n2);
+ break;
+ }
+ }
+ }
+ }
+ sqlite3_finalize(pStmt);
+ }
+ hash_finish(&cx, zOut);
+ sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
+}
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_sha_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "sha1", 1, SQLITE_UTF8, 0,
+ sha1Func, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "sha1_query", 1, SQLITE_UTF8, 0,
+ sha1QueryFunc, 0, 0);
+ }
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ return sqlite3_sha_init(db, pzErrMsg, pApi);
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/shathree.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/shathree.c 2019-10-08 13:42:19.211093400 +0200
@@ -0,0 +1,723 @@
+/*
+** 2017-03-08
+**
+** 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 SQLite extension implements functions that compute SHA3 hashes.
+** Two SQL functions are implemented:
+**
+** sha3(X,SIZE)
+** sha3_query(Y,SIZE)
+**
+** The sha3(X) function computes the SHA3 hash of the input X, or NULL if
+** X is NULL.
+**
+** The sha3_query(Y) function evalutes all queries in the SQL statements of Y
+** and returns a hash of their results.
+**
+** The SIZE argument is optional. If omitted, the SHA3-256 hash algorithm
+** is used. If SIZE is included it must be one of the integers 224, 256,
+** 384, or 512, to determine SHA3 hash variant that is computed.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+#include <stdarg.h>
+typedef sqlite3_uint64 u64;
+
+/******************************************************************************
+** The Hash Engine
+*/
+/*
+** Macros to determine whether the machine is big or little endian,
+** and whether or not that determination is run-time or compile-time.
+**
+** For best performance, an attempt is made to guess at the byte-order
+** using C-preprocessor macros. If that is unsuccessful, or if
+** -DSHA3_BYTEORDER=0 is set, then byte-order is determined
+** at run-time.
+*/
+#ifndef SHA3_BYTEORDER
+# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
+ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
+ defined(__arm__)
+# define SHA3_BYTEORDER 1234
+# elif defined(sparc) || defined(__ppc__)
+# define SHA3_BYTEORDER 4321
+# else
+# define SHA3_BYTEORDER 0
+# endif
+#endif
+
+
+/*
+** State structure for a SHA3 hash in progress
+*/
+typedef struct SHA3Context SHA3Context;
+struct SHA3Context {
+ union {
+ u64 s[25]; /* Keccak state. 5x5 lines of 64 bits each */
+ unsigned char x[1600]; /* ... or 1600 bytes */
+ } u;
+ unsigned nRate; /* Bytes of input accepted per Keccak iteration */
+ unsigned nLoaded; /* Input bytes loaded into u.x[] so far this cycle */
+ unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */
+};
+
+/*
+** A single step of the Keccak mixing function for a 1600-bit state
+*/
+static void KeccakF1600Step(SHA3Context *p){
+ int i;
+ u64 b0, b1, b2, b3, b4;
+ u64 c0, c1, c2, c3, c4;
+ u64 d0, d1, d2, d3, d4;
+ static const u64 RC[] = {
+ 0x0000000000000001ULL, 0x0000000000008082ULL,
+ 0x800000000000808aULL, 0x8000000080008000ULL,
+ 0x000000000000808bULL, 0x0000000080000001ULL,
+ 0x8000000080008081ULL, 0x8000000000008009ULL,
+ 0x000000000000008aULL, 0x0000000000000088ULL,
+ 0x0000000080008009ULL, 0x000000008000000aULL,
+ 0x000000008000808bULL, 0x800000000000008bULL,
+ 0x8000000000008089ULL, 0x8000000000008003ULL,
+ 0x8000000000008002ULL, 0x8000000000000080ULL,
+ 0x000000000000800aULL, 0x800000008000000aULL,
+ 0x8000000080008081ULL, 0x8000000000008080ULL,
+ 0x0000000080000001ULL, 0x8000000080008008ULL
+ };
+# define a00 (p->u.s[0])
+# define a01 (p->u.s[1])
+# define a02 (p->u.s[2])
+# define a03 (p->u.s[3])
+# define a04 (p->u.s[4])
+# define a10 (p->u.s[5])
+# define a11 (p->u.s[6])
+# define a12 (p->u.s[7])
+# define a13 (p->u.s[8])
+# define a14 (p->u.s[9])
+# define a20 (p->u.s[10])
+# define a21 (p->u.s[11])
+# define a22 (p->u.s[12])
+# define a23 (p->u.s[13])
+# define a24 (p->u.s[14])
+# define a30 (p->u.s[15])
+# define a31 (p->u.s[16])
+# define a32 (p->u.s[17])
+# define a33 (p->u.s[18])
+# define a34 (p->u.s[19])
+# define a40 (p->u.s[20])
+# define a41 (p->u.s[21])
+# define a42 (p->u.s[22])
+# define a43 (p->u.s[23])
+# define a44 (p->u.s[24])
+# define ROL64(a,x) ((a<<x)|(a>>(64-x)))
+
+ for(i=0; i<24; i+=4){
+ c0 = a00^a10^a20^a30^a40;
+ c1 = a01^a11^a21^a31^a41;
+ c2 = a02^a12^a22^a32^a42;
+ c3 = a03^a13^a23^a33^a43;
+ c4 = a04^a14^a24^a34^a44;
+ d0 = c4^ROL64(c1, 1);
+ d1 = c0^ROL64(c2, 1);
+ d2 = c1^ROL64(c3, 1);
+ d3 = c2^ROL64(c4, 1);
+ d4 = c3^ROL64(c0, 1);
+
+ b0 = (a00^d0);
+ b1 = ROL64((a11^d1), 44);
+ b2 = ROL64((a22^d2), 43);
+ b3 = ROL64((a33^d3), 21);
+ b4 = ROL64((a44^d4), 14);
+ a00 = b0 ^((~b1)& b2 );
+ a00 ^= RC[i];
+ a11 = b1 ^((~b2)& b3 );
+ a22 = b2 ^((~b3)& b4 );
+ a33 = b3 ^((~b4)& b0 );
+ a44 = b4 ^((~b0)& b1 );
+
+ b2 = ROL64((a20^d0), 3);
+ b3 = ROL64((a31^d1), 45);
+ b4 = ROL64((a42^d2), 61);
+ b0 = ROL64((a03^d3), 28);
+ b1 = ROL64((a14^d4), 20);
+ a20 = b0 ^((~b1)& b2 );
+ a31 = b1 ^((~b2)& b3 );
+ a42 = b2 ^((~b3)& b4 );
+ a03 = b3 ^((~b4)& b0 );
+ a14 = b4 ^((~b0)& b1 );
+
+ b4 = ROL64((a40^d0), 18);
+ b0 = ROL64((a01^d1), 1);
+ b1 = ROL64((a12^d2), 6);
+ b2 = ROL64((a23^d3), 25);
+ b3 = ROL64((a34^d4), 8);
+ a40 = b0 ^((~b1)& b2 );
+ a01 = b1 ^((~b2)& b3 );
+ a12 = b2 ^((~b3)& b4 );
+ a23 = b3 ^((~b4)& b0 );
+ a34 = b4 ^((~b0)& b1 );
+
+ b1 = ROL64((a10^d0), 36);
+ b2 = ROL64((a21^d1), 10);
+ b3 = ROL64((a32^d2), 15);
+ b4 = ROL64((a43^d3), 56);
+ b0 = ROL64((a04^d4), 27);
+ a10 = b0 ^((~b1)& b2 );
+ a21 = b1 ^((~b2)& b3 );
+ a32 = b2 ^((~b3)& b4 );
+ a43 = b3 ^((~b4)& b0 );
+ a04 = b4 ^((~b0)& b1 );
+
+ b3 = ROL64((a30^d0), 41);
+ b4 = ROL64((a41^d1), 2);
+ b0 = ROL64((a02^d2), 62);
+ b1 = ROL64((a13^d3), 55);
+ b2 = ROL64((a24^d4), 39);
+ a30 = b0 ^((~b1)& b2 );
+ a41 = b1 ^((~b2)& b3 );
+ a02 = b2 ^((~b3)& b4 );
+ a13 = b3 ^((~b4)& b0 );
+ a24 = b4 ^((~b0)& b1 );
+
+ c0 = a00^a20^a40^a10^a30;
+ c1 = a11^a31^a01^a21^a41;
+ c2 = a22^a42^a12^a32^a02;
+ c3 = a33^a03^a23^a43^a13;
+ c4 = a44^a14^a34^a04^a24;
+ d0 = c4^ROL64(c1, 1);
+ d1 = c0^ROL64(c2, 1);
+ d2 = c1^ROL64(c3, 1);
+ d3 = c2^ROL64(c4, 1);
+ d4 = c3^ROL64(c0, 1);
+
+ b0 = (a00^d0);
+ b1 = ROL64((a31^d1), 44);
+ b2 = ROL64((a12^d2), 43);
+ b3 = ROL64((a43^d3), 21);
+ b4 = ROL64((a24^d4), 14);
+ a00 = b0 ^((~b1)& b2 );
+ a00 ^= RC[i+1];
+ a31 = b1 ^((~b2)& b3 );
+ a12 = b2 ^((~b3)& b4 );
+ a43 = b3 ^((~b4)& b0 );
+ a24 = b4 ^((~b0)& b1 );
+
+ b2 = ROL64((a40^d0), 3);
+ b3 = ROL64((a21^d1), 45);
+ b4 = ROL64((a02^d2), 61);
+ b0 = ROL64((a33^d3), 28);
+ b1 = ROL64((a14^d4), 20);
+ a40 = b0 ^((~b1)& b2 );
+ a21 = b1 ^((~b2)& b3 );
+ a02 = b2 ^((~b3)& b4 );
+ a33 = b3 ^((~b4)& b0 );
+ a14 = b4 ^((~b0)& b1 );
+
+ b4 = ROL64((a30^d0), 18);
+ b0 = ROL64((a11^d1), 1);
+ b1 = ROL64((a42^d2), 6);
+ b2 = ROL64((a23^d3), 25);
+ b3 = ROL64((a04^d4), 8);
+ a30 = b0 ^((~b1)& b2 );
+ a11 = b1 ^((~b2)& b3 );
+ a42 = b2 ^((~b3)& b4 );
+ a23 = b3 ^((~b4)& b0 );
+ a04 = b4 ^((~b0)& b1 );
+
+ b1 = ROL64((a20^d0), 36);
+ b2 = ROL64((a01^d1), 10);
+ b3 = ROL64((a32^d2), 15);
+ b4 = ROL64((a13^d3), 56);
+ b0 = ROL64((a44^d4), 27);
+ a20 = b0 ^((~b1)& b2 );
+ a01 = b1 ^((~b2)& b3 );
+ a32 = b2 ^((~b3)& b4 );
+ a13 = b3 ^((~b4)& b0 );
+ a44 = b4 ^((~b0)& b1 );
+
+ b3 = ROL64((a10^d0), 41);
+ b4 = ROL64((a41^d1), 2);
+ b0 = ROL64((a22^d2), 62);
+ b1 = ROL64((a03^d3), 55);
+ b2 = ROL64((a34^d4), 39);
+ a10 = b0 ^((~b1)& b2 );
+ a41 = b1 ^((~b2)& b3 );
+ a22 = b2 ^((~b3)& b4 );
+ a03 = b3 ^((~b4)& b0 );
+ a34 = b4 ^((~b0)& b1 );
+
+ c0 = a00^a40^a30^a20^a10;
+ c1 = a31^a21^a11^a01^a41;
+ c2 = a12^a02^a42^a32^a22;
+ c3 = a43^a33^a23^a13^a03;
+ c4 = a24^a14^a04^a44^a34;
+ d0 = c4^ROL64(c1, 1);
+ d1 = c0^ROL64(c2, 1);
+ d2 = c1^ROL64(c3, 1);
+ d3 = c2^ROL64(c4, 1);
+ d4 = c3^ROL64(c0, 1);
+
+ b0 = (a00^d0);
+ b1 = ROL64((a21^d1), 44);
+ b2 = ROL64((a42^d2), 43);
+ b3 = ROL64((a13^d3), 21);
+ b4 = ROL64((a34^d4), 14);
+ a00 = b0 ^((~b1)& b2 );
+ a00 ^= RC[i+2];
+ a21 = b1 ^((~b2)& b3 );
+ a42 = b2 ^((~b3)& b4 );
+ a13 = b3 ^((~b4)& b0 );
+ a34 = b4 ^((~b0)& b1 );
+
+ b2 = ROL64((a30^d0), 3);
+ b3 = ROL64((a01^d1), 45);
+ b4 = ROL64((a22^d2), 61);
+ b0 = ROL64((a43^d3), 28);
+ b1 = ROL64((a14^d4), 20);
+ a30 = b0 ^((~b1)& b2 );
+ a01 = b1 ^((~b2)& b3 );
+ a22 = b2 ^((~b3)& b4 );
+ a43 = b3 ^((~b4)& b0 );
+ a14 = b4 ^((~b0)& b1 );
+
+ b4 = ROL64((a10^d0), 18);
+ b0 = ROL64((a31^d1), 1);
+ b1 = ROL64((a02^d2), 6);
+ b2 = ROL64((a23^d3), 25);
+ b3 = ROL64((a44^d4), 8);
+ a10 = b0 ^((~b1)& b2 );
+ a31 = b1 ^((~b2)& b3 );
+ a02 = b2 ^((~b3)& b4 );
+ a23 = b3 ^((~b4)& b0 );
+ a44 = b4 ^((~b0)& b1 );
+
+ b1 = ROL64((a40^d0), 36);
+ b2 = ROL64((a11^d1), 10);
+ b3 = ROL64((a32^d2), 15);
+ b4 = ROL64((a03^d3), 56);
+ b0 = ROL64((a24^d4), 27);
+ a40 = b0 ^((~b1)& b2 );
+ a11 = b1 ^((~b2)& b3 );
+ a32 = b2 ^((~b3)& b4 );
+ a03 = b3 ^((~b4)& b0 );
+ a24 = b4 ^((~b0)& b1 );
+
+ b3 = ROL64((a20^d0), 41);
+ b4 = ROL64((a41^d1), 2);
+ b0 = ROL64((a12^d2), 62);
+ b1 = ROL64((a33^d3), 55);
+ b2 = ROL64((a04^d4), 39);
+ a20 = b0 ^((~b1)& b2 );
+ a41 = b1 ^((~b2)& b3 );
+ a12 = b2 ^((~b3)& b4 );
+ a33 = b3 ^((~b4)& b0 );
+ a04 = b4 ^((~b0)& b1 );
+
+ c0 = a00^a30^a10^a40^a20;
+ c1 = a21^a01^a31^a11^a41;
+ c2 = a42^a22^a02^a32^a12;
+ c3 = a13^a43^a23^a03^a33;
+ c4 = a34^a14^a44^a24^a04;
+ d0 = c4^ROL64(c1, 1);
+ d1 = c0^ROL64(c2, 1);
+ d2 = c1^ROL64(c3, 1);
+ d3 = c2^ROL64(c4, 1);
+ d4 = c3^ROL64(c0, 1);
+
+ b0 = (a00^d0);
+ b1 = ROL64((a01^d1), 44);
+ b2 = ROL64((a02^d2), 43);
+ b3 = ROL64((a03^d3), 21);
+ b4 = ROL64((a04^d4), 14);
+ a00 = b0 ^((~b1)& b2 );
+ a00 ^= RC[i+3];
+ a01 = b1 ^((~b2)& b3 );
+ a02 = b2 ^((~b3)& b4 );
+ a03 = b3 ^((~b4)& b0 );
+ a04 = b4 ^((~b0)& b1 );
+
+ b2 = ROL64((a10^d0), 3);
+ b3 = ROL64((a11^d1), 45);
+ b4 = ROL64((a12^d2), 61);
+ b0 = ROL64((a13^d3), 28);
+ b1 = ROL64((a14^d4), 20);
+ a10 = b0 ^((~b1)& b2 );
+ a11 = b1 ^((~b2)& b3 );
+ a12 = b2 ^((~b3)& b4 );
+ a13 = b3 ^((~b4)& b0 );
+ a14 = b4 ^((~b0)& b1 );
+
+ b4 = ROL64((a20^d0), 18);
+ b0 = ROL64((a21^d1), 1);
+ b1 = ROL64((a22^d2), 6);
+ b2 = ROL64((a23^d3), 25);
+ b3 = ROL64((a24^d4), 8);
+ a20 = b0 ^((~b1)& b2 );
+ a21 = b1 ^((~b2)& b3 );
+ a22 = b2 ^((~b3)& b4 );
+ a23 = b3 ^((~b4)& b0 );
+ a24 = b4 ^((~b0)& b1 );
+
+ b1 = ROL64((a30^d0), 36);
+ b2 = ROL64((a31^d1), 10);
+ b3 = ROL64((a32^d2), 15);
+ b4 = ROL64((a33^d3), 56);
+ b0 = ROL64((a34^d4), 27);
+ a30 = b0 ^((~b1)& b2 );
+ a31 = b1 ^((~b2)& b3 );
+ a32 = b2 ^((~b3)& b4 );
+ a33 = b3 ^((~b4)& b0 );
+ a34 = b4 ^((~b0)& b1 );
+
+ b3 = ROL64((a40^d0), 41);
+ b4 = ROL64((a41^d1), 2);
+ b0 = ROL64((a42^d2), 62);
+ b1 = ROL64((a43^d3), 55);
+ b2 = ROL64((a44^d4), 39);
+ a40 = b0 ^((~b1)& b2 );
+ a41 = b1 ^((~b2)& b3 );
+ a42 = b2 ^((~b3)& b4 );
+ a43 = b3 ^((~b4)& b0 );
+ a44 = b4 ^((~b0)& b1 );
+ }
+}
+
+/*
+** Initialize a new hash. iSize determines the size of the hash
+** in bits and should be one of 224, 256, 384, or 512. Or iSize
+** can be zero to use the default hash size of 256 bits.
+*/
+static void SHA3Init(SHA3Context *p, int iSize){
+ memset(p, 0, sizeof(*p));
+ if( iSize>=128 && iSize<=512 ){
+ p->nRate = (1600 - ((iSize + 31)&~31)*2)/8;
+ }else{
+ p->nRate = (1600 - 2*256)/8;
+ }
+#if SHA3_BYTEORDER==1234
+ /* Known to be little-endian at compile-time. No-op */
+#elif SHA3_BYTEORDER==4321
+ p->ixMask = 7; /* Big-endian */
+#else
+ {
+ static unsigned int one = 1;
+ if( 1==*(unsigned char*)&one ){
+ /* Little endian. No byte swapping. */
+ p->ixMask = 0;
+ }else{
+ /* Big endian. Byte swap. */
+ p->ixMask = 7;
+ }
+ }
+#endif
+}
+
+/*
+** Make consecutive calls to the SHA3Update function to add new content
+** to the hash
+*/
+static void SHA3Update(
+ SHA3Context *p,
+ const unsigned char *aData,
+ unsigned int nData
+){
+ unsigned int i = 0;
+#if SHA3_BYTEORDER==1234
+ if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){
+ for(; i+7<nData; i+=8){
+ p->u.s[p->nLoaded/8] ^= *(u64*)&aData[i];
+ p->nLoaded += 8;
+ if( p->nLoaded>=p->nRate ){
+ KeccakF1600Step(p);
+ p->nLoaded = 0;
+ }
+ }
+ }
+#endif
+ for(; i<nData; i++){
+#if SHA3_BYTEORDER==1234
+ p->u.x[p->nLoaded] ^= aData[i];
+#elif SHA3_BYTEORDER==4321
+ p->u.x[p->nLoaded^0x07] ^= aData[i];
+#else
+ p->u.x[p->nLoaded^p->ixMask] ^= aData[i];
+#endif
+ p->nLoaded++;
+ if( p->nLoaded==p->nRate ){
+ KeccakF1600Step(p);
+ p->nLoaded = 0;
+ }
+ }
+}
+
+/*
+** After all content has been added, invoke SHA3Final() to compute
+** the final hash. The function returns a pointer to the binary
+** hash value.
+*/
+static unsigned char *SHA3Final(SHA3Context *p){
+ unsigned int i;
+ if( p->nLoaded==p->nRate-1 ){
+ const unsigned char c1 = 0x86;
+ SHA3Update(p, &c1, 1);
+ }else{
+ const unsigned char c2 = 0x06;
+ const unsigned char c3 = 0x80;
+ SHA3Update(p, &c2, 1);
+ p->nLoaded = p->nRate - 1;
+ SHA3Update(p, &c3, 1);
+ }
+ for(i=0; i<p->nRate; i++){
+ p->u.x[i+p->nRate] = p->u.x[i^p->ixMask];
+ }
+ return &p->u.x[p->nRate];
+}
+/* End of the hashing logic
+*****************************************************************************/
+
+/*
+** Implementation of the sha3(X,SIZE) function.
+**
+** Return a BLOB which is the SIZE-bit SHA3 hash of X. The default
+** size is 256. If X is a BLOB, it is hashed as is.
+** For all other non-NULL types of input, X is converted into a UTF-8 string
+** and the string is hashed without the trailing 0x00 terminator. The hash
+** of a NULL value is NULL.
+*/
+static void sha3Func(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ SHA3Context cx;
+ int eType = sqlite3_value_type(argv[0]);
+ int nByte = sqlite3_value_bytes(argv[0]);
+ int iSize;
+ if( argc==1 ){
+ iSize = 256;
+ }else{
+ iSize = sqlite3_value_int(argv[1]);
+ if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){
+ sqlite3_result_error(context, "SHA3 size should be one of: 224 256 "
+ "384 512", -1);
+ return;
+ }
+ }
+ if( eType==SQLITE_NULL ) return;
+ SHA3Init(&cx, iSize);
+ if( eType==SQLITE_BLOB ){
+ SHA3Update(&cx, sqlite3_value_blob(argv[0]), nByte);
+ }else{
+ SHA3Update(&cx, sqlite3_value_text(argv[0]), nByte);
+ }
+ sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
+}
+
+/* Compute a string using sqlite3_vsnprintf() with a maximum length
+** of 50 bytes and add it to the hash.
+*/
+static void hash_step_vformat(
+ SHA3Context *p, /* Add content to this context */
+ const char *zFormat,
+ ...
+){
+ va_list ap;
+ int n;
+ char zBuf[50];
+ va_start(ap, zFormat);
+ sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap);
+ va_end(ap);
+ n = (int)strlen(zBuf);
+ SHA3Update(p, (unsigned char*)zBuf, n);
+}
+
+/*
+** Implementation of the sha3_query(SQL,SIZE) function.
+**
+** This function compiles and runs the SQL statement(s) given in the
+** argument. The results are hashed using a SIZE-bit SHA3. The default
+** size is 256.
+**
+** The format of the byte stream that is hashed is summarized as follows:
+**
+** S<n>:<sql>
+** R
+** N
+** I<int>
+** F<ieee-float>
+** B<size>:<bytes>
+** T<size>:<text>
+**
+** <sql> is the original SQL text for each statement run and <n> is
+** the size of that text. The SQL text is UTF-8. A single R character
+** occurs before the start of each row. N means a NULL value.
+** I mean an 8-byte little-endian integer <int>. F is a floating point
+** number with an 8-byte little-endian IEEE floating point value <ieee-float>.
+** B means blobs of <size> bytes. T means text rendered as <size>
+** bytes of UTF-8. The <n> and <size> values are expressed as an ASCII
+** text integers.
+**
+** For each SQL statement in the X input, there is one S segment. Each
+** S segment is followed by zero or more R segments, one for each row in the
+** result set. After each R, there are one or more N, I, F, B, or T segments,
+** one for each column in the result set. Segments are concatentated directly
+** with no delimiters of any kind.
+*/
+static void sha3QueryFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ const char *zSql = (const char*)sqlite3_value_text(argv[0]);
+ sqlite3_stmt *pStmt = 0;
+ int nCol; /* Number of columns in the result set */
+ int i; /* Loop counter */
+ int rc;
+ int n;
+ const char *z;
+ SHA3Context cx;
+ int iSize;
+
+ if( argc==1 ){
+ iSize = 256;
+ }else{
+ iSize = sqlite3_value_int(argv[1]);
+ if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){
+ sqlite3_result_error(context, "SHA3 size should be one of: 224 256 "
+ "384 512", -1);
+ return;
+ }
+ }
+ if( zSql==0 ) return;
+ SHA3Init(&cx, iSize);
+ while( zSql[0] ){
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
+ if( rc ){
+ char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s",
+ zSql, sqlite3_errmsg(db));
+ sqlite3_finalize(pStmt);
+ sqlite3_result_error(context, zMsg, -1);
+ sqlite3_free(zMsg);
+ return;
+ }
+ if( !sqlite3_stmt_readonly(pStmt) ){
+ char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt));
+ sqlite3_finalize(pStmt);
+ sqlite3_result_error(context, zMsg, -1);
+ sqlite3_free(zMsg);
+ return;
+ }
+ nCol = sqlite3_column_count(pStmt);
+ z = sqlite3_sql(pStmt);
+ n = (int)strlen(z);
+ hash_step_vformat(&cx,"S%d:",n);
+ SHA3Update(&cx,(unsigned char*)z,n);
+
+ /* Compute a hash over the result of the query */
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ SHA3Update(&cx,(const unsigned char*)"R",1);
+ for(i=0; i<nCol; i++){
+ switch( sqlite3_column_type(pStmt,i) ){
+ case SQLITE_NULL: {
+ SHA3Update(&cx, (const unsigned char*)"N",1);
+ break;
+ }
+ case SQLITE_INTEGER: {
+ sqlite3_uint64 u;
+ int j;
+ unsigned char x[9];
+ sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
+ memcpy(&u, &v, 8);
+ for(j=8; j>=1; j--){
+ x[j] = u & 0xff;
+ u >>= 8;
+ }
+ x[0] = 'I';
+ SHA3Update(&cx, x, 9);
+ break;
+ }
+ case SQLITE_FLOAT: {
+ sqlite3_uint64 u;
+ int j;
+ unsigned char x[9];
+ double r = sqlite3_column_double(pStmt,i);
+ memcpy(&u, &r, 8);
+ for(j=8; j>=1; j--){
+ x[j] = u & 0xff;
+ u >>= 8;
+ }
+ x[0] = 'F';
+ SHA3Update(&cx,x,9);
+ break;
+ }
+ case SQLITE_TEXT: {
+ int n2 = sqlite3_column_bytes(pStmt, i);
+ const unsigned char *z2 = sqlite3_column_text(pStmt, i);
+ hash_step_vformat(&cx,"T%d:",n2);
+ SHA3Update(&cx, z2, n2);
+ break;
+ }
+ case SQLITE_BLOB: {
+ int n2 = sqlite3_column_bytes(pStmt, i);
+ const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
+ hash_step_vformat(&cx,"B%d:",n2);
+ SHA3Update(&cx, z2, n2);
+ break;
+ }
+ }
+ }
+ }
+ sqlite3_finalize(pStmt);
+ }
+ sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
+}
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_shathree_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "sha3", 1, SQLITE_UTF8, 0,
+ sha3Func, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "sha3", 2, SQLITE_UTF8, 0,
+ sha3Func, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "sha3_query", 1, SQLITE_UTF8, 0,
+ sha3QueryFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "sha3_query", 2, SQLITE_UTF8, 0,
+ sha3QueryFunc, 0, 0);
+ }
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ return sqlite3_shathree_init(db, pzErrMsg, pApi);
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/shell.c 2019-10-04 18:28:13.000000000 +0200
+++ src/sqlite-autoconf-3300000/shell.c 2019-10-08 13:42:19.064655700 +0200
@@ -200,6 +200,11 @@ extern char *sqlite3_win32_utf8_to_mbcs_
extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
#endif
+/* Prevent sqlite3_extension_init() to be multiply defined */
+#ifndef SQLITE_TEST
+# define SQLITE_TEST 1
+#endif
+
/* On Windows, we normally run with output mode of TEXT so that \n characters
** are automatically translated into \r\n. However, this behavior needs
** to be disabled in some cases (ex: when generating CSV output and when
@@ -298,45 +303,14 @@ static HANDLE hProcess;
static FILETIME ftKernelBegin;
static FILETIME ftUserBegin;
static sqlite3_int64 ftWallBegin;
-typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME,
- LPFILETIME, LPFILETIME);
-static GETPROCTIMES getProcessTimesAddr = NULL;
-
-/*
-** Check to see if we have timer support. Return 1 if necessary
-** support found (or found previously).
-*/
-static int hasTimer(void){
- if( getProcessTimesAddr ){
- return 1;
- } else {
- /* GetProcessTimes() isn't supported in WIN95 and some other Windows
- ** versions. See if the version we are running on has it, and if it
- ** does, save off a pointer to it and the current process handle.
- */
- hProcess = GetCurrentProcess();
- if( hProcess ){
- HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll"));
- if( NULL != hinstLib ){
- getProcessTimesAddr =
- (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");
- if( NULL != getProcessTimesAddr ){
- return 1;
- }
- FreeLibrary(hinstLib);
- }
- }
- }
- return 0;
-}
/*
** Begin timing an operation
*/
static void beginTimer(void){
- if( enableTimer && getProcessTimesAddr ){
+ if( enableTimer ){
FILETIME ftCreation, ftExit;
- getProcessTimesAddr(hProcess,&ftCreation,&ftExit,
+ GetProcessTimes(hProcess,&ftCreation,&ftExit,
&ftKernelBegin,&ftUserBegin);
ftWallBegin = timeOfDay();
}
@@ -353,10 +327,10 @@ static double timeDiff(FILETIME *pStart,
** Print the timing results.
*/
static void endTimer(void){
- if( enableTimer && getProcessTimesAddr){
+ if( enableTimer){
FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
sqlite3_int64 ftWallEnd = timeOfDay();
- getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
+ GetProcessTimes(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
printf("Run Time: real %.3f user %f sys %f\n",
(ftWallEnd - ftWallBegin)*0.001,
timeDiff(&ftUserBegin, &ftUserEnd),
@@ -366,7 +340,7 @@ static void endTimer(void){
#define BEGIN_TIMER beginTimer()
#define END_TIMER endTimer()
-#define HAS_TIMER hasTimer()
+#define HAS_TIMER 1
#else
#define BEGIN_TIMER
@@ -382,7 +356,7 @@ static void endTimer(void){
/*
** Number of elements in an array
*/
-#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
+#define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0])))
/*
** If the following flag is set, then command execution stops
@@ -677,7 +651,7 @@ static int hexDigitValue(char c){
*/
static sqlite3_int64 integerValue(const char *zArg){
sqlite3_int64 v = 0;
- static const struct { char *zSuffix; int iMult; } aMult[] = {
+ static const struct { const char zSuffix[4]; int iMult; } aMult[] = {
{ "KiB", 1024 },
{ "MiB", 1024*1024 },
{ "GiB", 1024*1024*1024 },
@@ -813,7 +787,7 @@ static char *shellFakeSchema(
char *zSql;
ShellText s;
char cQuote;
- char *zDiv = "(";
+ const char *zDiv = "(";
int nRow = 0;
zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;",
@@ -2023,6 +1997,15 @@ int sqlite3_shathree_init(
}
return rc;
}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ return sqlite3_shathree_init(db, pzErrMsg, pApi);
+}
+#endif
/************************* End ../ext/misc/shathree.c ********************/
/************************* Begin ../ext/misc/fileio.c ******************/
@@ -2110,9 +2093,9 @@ SQLITE_EXTENSION_INIT1
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <dirent.h>
#if !defined(_WIN32) && !defined(WIN32)
# include <unistd.h>
-# include <dirent.h>
# include <utime.h>
# include <sys/time.h>
#else
@@ -2120,7 +2103,6 @@ SQLITE_EXTENSION_INIT1
# include <io.h>
# include <direct.h>
/* # include "test_windirent.h" */
-# define dirent DIRENT
# ifndef chmod
# define chmod _chmod
# endif
@@ -2180,7 +2162,7 @@ static void readFileContents(sqlite3_con
fclose(in);
return;
}
- pBuf = sqlite3_malloc64( nIn ? nIn : 1 );
+ pBuf = sqlite3_malloc( nIn ? nIn : 1 );
if( pBuf==0 ){
sqlite3_result_error_nomem(ctx);
fclose(in);
@@ -2514,9 +2496,12 @@ static void writefileFunc(
}
if( argc>2 && res!=0 ){
+#if !defined(_WIN32) && !defined(WIN32)
if( S_ISLNK(mode) ){
ctxErrorMsg(context, "failed to create symlink: %s", zFile);
- }else if( S_ISDIR(mode) ){
+ }else
+#endif
+ if( S_ISDIR(mode) ){
ctxErrorMsg(context, "failed to create directory: %s", zFile);
}else{
ctxErrorMsg(context, "failed to write file: %s", zFile);
@@ -2539,9 +2524,12 @@ static void lsModeFunc(
int iMode = sqlite3_value_int(argv[0]);
char z[16];
(void)argc;
+#if !defined(_WIN32) && !defined(WIN32)
if( S_ISLNK(iMode) ){
z[0] = 'l';
- }else if( S_ISREG(iMode) ){
+ }else
+#endif
+ if( S_ISREG(iMode) ){
z[0] = '-';
}else if( S_ISDIR(iMode) ){
z[0] = 'd';
@@ -2699,8 +2687,8 @@ static int fsdirNext(sqlite3_vtab_cursor
FsdirLevel *pLvl;
if( iNew>=pCur->nLvl ){
int nNew = iNew+1;
- sqlite3_int64 nByte = nNew*sizeof(FsdirLevel);
- FsdirLevel *aNew = (FsdirLevel*)sqlite3_realloc64(pCur->aLvl, nByte);
+ size_t nByte = nNew*sizeof(FsdirLevel);
+ FsdirLevel *aNew = (FsdirLevel*)sqlite3_realloc(pCur->aLvl, nByte);
if( aNew==0 ) return SQLITE_NOMEM;
memset(&aNew[pCur->nLvl], 0, sizeof(FsdirLevel)*(nNew-pCur->nLvl));
pCur->aLvl = aNew;
@@ -2780,15 +2768,15 @@ static int fsdirColumn(
}else if( S_ISLNK(m) ){
char aStatic[64];
char *aBuf = aStatic;
- sqlite3_int64 nBuf = 64;
- int n;
+ size_t nBuf = 64;
+ size_t n;
while( 1 ){
n = readlink(pCur->zPath, aBuf, nBuf);
if( n<nBuf ) break;
if( aBuf!=aStatic ) sqlite3_free(aBuf);
nBuf = nBuf*2;
- aBuf = sqlite3_malloc64(nBuf);
+ aBuf = sqlite3_malloc(nBuf);
if( aBuf==0 ){
sqlite3_result_error_nomem(ctx);
return SQLITE_NOMEM;
@@ -2961,7 +2949,7 @@ static int fsdirBestIndex(
** Register the "fsdir" virtual table.
*/
static int fsdirRegister(sqlite3 *db){
- static sqlite3_module fsdirModule = {
+ static const sqlite3_module fsdirModule = {
0, /* iVersion */
0, /* xCreate */
fsdirConnect, /* xConnect */
@@ -3021,6 +3009,24 @@ int sqlite3_fileio_init(
}
return rc;
}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
+ readfileFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0,
+ writefileFunc, 0, 0);
+ }
+ return rc;
+}
+#endif
/************************* End ../ext/misc/fileio.c ********************/
/************************* Begin ../ext/misc/completion.c ******************/
@@ -3471,7 +3477,7 @@ static int completionBestIndex(
** This following structure defines all the methods for the
** completion virtual table.
*/
-static sqlite3_module completionModule = {
+static const sqlite3_module completionModule = {
0, /* iVersion */
0, /* xCreate */
completionConnect, /* xConnect */
@@ -3524,6 +3530,21 @@ int sqlite3_completion_init(
#endif
return rc;
}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)(pzErrMsg); /* Unused parameter */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3CompletionVtabInit(db);
+#endif
+ return rc;
+}
+#endif
/************************* End ../ext/misc/completion.c ********************/
/************************* Begin ../ext/misc/appendvfs.c ******************/
@@ -4248,8 +4269,13 @@ SQLITE_EXTENSION_INIT1
/* typedef sqlite3_int64 i64; */
/* typedef unsigned char u8; */
typedef unsigned short u16;
-typedef unsigned long u32;
-#define MIN(a,b) ((a)<(b) ? (a) : (b))
+typedef unsigned int u32;
+#ifndef MIN
+# define MIN(A,B) ((A)<(B)?(A):(B))
+#endif
+#ifndef MAX
+# define MAX(A,B) ((A)>(B)?(A):(B))
+#endif
#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
# define ALWAYS(X) (1)
@@ -4539,8 +4565,8 @@ static int zipfileConnect(
sqlite3_vtab **ppVtab,
char **pzErr
){
- int nByte = sizeof(ZipfileTab) + ZIPFILE_BUFFER_SIZE;
- int nFile = 0;
+ size_t nByte = sizeof(ZipfileTab) + ZIPFILE_BUFFER_SIZE;
+ size_t nFile = 0;
const char *zFile = 0;
ZipfileTab *pNew = 0;
int rc;
@@ -4562,12 +4588,12 @@ static int zipfileConnect(
if( argc>3 ){
zFile = argv[3];
- nFile = (int)strlen(zFile)+1;
+ nFile = strlen(zFile)+1;
}
rc = sqlite3_declare_vtab(db, ZIPFILE_SCHEMA);
if( rc==SQLITE_OK ){
- pNew = (ZipfileTab*)sqlite3_malloc64((sqlite3_int64)nByte+nFile);
+ pNew = (ZipfileTab*)sqlite3_malloc(nByte+nFile);
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, nByte+nFile);
pNew->db = db;
@@ -5015,7 +5041,7 @@ static int zipfileGetEntry(
}
if( rc==SQLITE_OK ){
- sqlite3_int64 nAlloc;
+ size_t nAlloc;
ZipfileEntry *pNew;
int nFile = zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF]);
@@ -5027,7 +5053,7 @@ static int zipfileGetEntry(
nAlloc += zipfileGetU32(&aRead[ZIPFILE_CDS_SZCOMPRESSED_OFF]);
}
- pNew = (ZipfileEntry*)sqlite3_malloc64(nAlloc);
+ pNew = (ZipfileEntry*)sqlite3_malloc(nAlloc);
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -5186,15 +5212,15 @@ static void zipfileInflate(
** case.
*/
static int zipfileDeflate(
- const u8 *aIn, int nIn, /* Input */
- u8 **ppOut, int *pnOut, /* Output */
+ const u8 *aIn, size_t nIn, /* Input */
+ u8 **ppOut, size_t *pnOut, /* Output */
char **pzErr /* OUT: Error message */
){
- sqlite3_int64 nAlloc = compressBound(nIn);
+ size_t nAlloc = compressBound(nIn);
u8 *aOut;
int rc = SQLITE_OK;
- aOut = (u8*)sqlite3_malloc64(nAlloc);
+ aOut = (u8*)sqlite3_malloc(nAlloc);
if( aOut==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -5211,7 +5237,7 @@ static int zipfileDeflate(
if( res==Z_STREAM_END ){
*ppOut = aOut;
- *pnOut = (int)str.total_out;
+ *pnOut = str.total_out;
}else{
sqlite3_free(aOut);
*pzErr = sqlite3_mprintf("zipfile: deflate() error");
@@ -5259,15 +5285,15 @@ static int zipfileColumn(
if( sqlite3_vtab_nochange(ctx) ) break;
case 5: { /* data */
if( i==4 || pCDS->iCompression==0 || pCDS->iCompression==8 ){
- int sz = pCDS->szCompressed;
- int szFinal = pCDS->szUncompressed;
+ size_t sz = pCDS->szCompressed;
+ size_t szFinal = pCDS->szUncompressed;
if( szFinal>0 ){
u8 *aBuf;
u8 *aFree = 0;
if( pCsr->pCurrent->aData ){
aBuf = pCsr->pCurrent->aData;
}else{
- aBuf = aFree = sqlite3_malloc64(sz);
+ aBuf = aFree = sqlite3_malloc(sz);
if( aBuf==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -5742,7 +5768,7 @@ static int zipfileUpdate(
const char *zPath = 0; /* Path for new entry */
int nPath = 0; /* strlen(zPath) */
const u8 *pData = 0; /* Pointer to buffer containing content */
- int nData = 0; /* Size of pData buffer in bytes */
+ size_t nData = 0; /* Size of pData buffer in bytes */
int iMethod = 0; /* Compression method for new entry */
u8 *pFree = 0; /* Free this */
char *zFree = 0; /* Also free this */
@@ -5794,7 +5820,7 @@ static int zipfileUpdate(
/* Value specified for "data", and possibly "method". This must be
** a regular file or a symlink. */
const u8 *aIn = sqlite3_value_blob(apVal[7]);
- int nIn = sqlite3_value_bytes(apVal[7]);
+ size_t nIn = sqlite3_value_bytes(apVal[7]);
int bAuto = sqlite3_value_type(apVal[8])==SQLITE_NULL;
iMethod = sqlite3_value_int(apVal[8]);
@@ -5806,7 +5832,7 @@ static int zipfileUpdate(
rc = SQLITE_CONSTRAINT;
}else{
if( bAuto || iMethod ){
- int nCmp;
+ size_t nCmp;
rc = zipfileDeflate(aIn, nIn, &pFree, &nCmp, &pTab->base.zErrMsg);
if( rc==SQLITE_OK ){
if( iMethod || nCmp<nIn ){
@@ -6092,8 +6118,8 @@ static int zipfileFindFunction(
typedef struct ZipfileBuffer ZipfileBuffer;
struct ZipfileBuffer {
u8 *a; /* Pointer to buffer */
- int n; /* Size of buffer in bytes */
- int nAlloc; /* Byte allocated at a[] */
+ size_t n; /* Size of buffer in bytes */
+ size_t nAlloc; /* Byte allocated at a[] */
};
typedef struct ZipfileCtx ZipfileCtx;
@@ -6103,14 +6129,14 @@ struct ZipfileCtx {
ZipfileBuffer cds;
};
-static int zipfileBufferGrow(ZipfileBuffer *pBuf, int nByte){
+static int zipfileBufferGrow(ZipfileBuffer *pBuf, size_t nByte){
if( pBuf->n+nByte>pBuf->nAlloc ){
u8 *aNew;
- sqlite3_int64 nNew = pBuf->n ? pBuf->n*2 : 512;
- int nReq = pBuf->n + nByte;
+ size_t nNew = pBuf->n ? pBuf->n*2 : 512;
+ size_t nReq = pBuf->n + nByte;
while( nNew<nReq ) nNew = nNew*2;
- aNew = sqlite3_realloc64(pBuf->a, nNew);
+ aNew = sqlite3_realloc(pBuf->a, nNew);
if( aNew==0 ) return SQLITE_NOMEM;
pBuf->a = aNew;
pBuf->nAlloc = (int)nNew;
@@ -6144,7 +6170,7 @@ void zipfileStep(sqlite3_context *pCtx,
int iMethod = -1; /* Compression method to use (0 or 8) */
const u8 *aData = 0; /* Possibly compressed data for new entry */
- int nData = 0; /* Size of aData[] in bytes */
+ size_t nData = 0; /* Size of aData[] in bytes */
int szUncompressed = 0; /* Size of data before compression */
u8 *aFree = 0; /* Free this before returning */
u32 iCrc32 = 0; /* crc32 of uncompressed data */
@@ -6152,7 +6178,7 @@ void zipfileStep(sqlite3_context *pCtx,
char *zName = 0; /* Path (name) of new entry */
int nName = 0; /* Size of zName in bytes */
char *zFree = 0; /* Free this before returning */
- int nByte;
+ size_t nByte;
memset(&e, 0, sizeof(e));
p = (ZipfileCtx*)sqlite3_aggregate_context(pCtx, sizeof(ZipfileCtx));
@@ -6207,7 +6233,7 @@ void zipfileStep(sqlite3_context *pCtx,
szUncompressed = nData = sqlite3_value_bytes(pData);
iCrc32 = crc32(0, aData, nData);
if( iMethod<0 || iMethod==8 ){
- int nOut = 0;
+ size_t nOut = 0;
rc = zipfileDeflate(aData, nData, &aFree, &nOut, &zErr);
if( rc!=SQLITE_OK ){
goto zipfile_step_out;
@@ -6304,7 +6330,7 @@ void zipfileStep(sqlite3_context *pCtx,
void zipfileFinal(sqlite3_context *pCtx){
ZipfileCtx *p;
ZipfileEOCD eocd;
- sqlite3_int64 nZip;
+ size_t nZip;
u8 *aZip;
p = (ZipfileCtx*)sqlite3_aggregate_context(pCtx, sizeof(ZipfileCtx));
@@ -6317,14 +6343,14 @@ void zipfileFinal(sqlite3_context *pCtx)
eocd.iOffset = p->body.n;
nZip = p->body.n + p->cds.n + ZIPFILE_EOCD_FIXED_SZ;
- aZip = (u8*)sqlite3_malloc64(nZip);
+ aZip = (u8*)sqlite3_malloc(nZip);
if( aZip==0 ){
sqlite3_result_error_nomem(pCtx);
}else{
memcpy(aZip, p->body.a, p->body.n);
memcpy(&aZip[p->body.n], p->cds.a, p->cds.n);
zipfileSerializeEOCD(&eocd, &aZip[p->body.n + p->cds.n]);
- sqlite3_result_blob(pCtx, aZip, (int)nZip, zipfileFree);
+ sqlite3_result_blob(pCtx, aZip, nZip, zipfileFree);
}
}
@@ -6337,7 +6363,7 @@ void zipfileFinal(sqlite3_context *pCtx)
** Register the "zipfile" virtual table.
*/
static int zipfileRegister(sqlite3 *db){
- static sqlite3_module zipfileModule = {
+ static const sqlite3_module zipfileModule = {
1, /* iVersion */
zipfileConnect, /* xCreate */
zipfileConnect, /* xConnect */
@@ -7306,7 +7332,7 @@ static int expertFilter(
}
static int idxRegisterVtab(sqlite3expert *p){
- static sqlite3_module expertModule = {
+ static const sqlite3_module expertModule = {
2, /* iVersion */
expertConnect, /* xCreate - create a table */
expertConnect, /* xConnect - connect to an existing table */
@@ -9448,7 +9474,7 @@ static int dbdataRowid(sqlite3_vtab_curs
** Invoke this routine to register the "sqlite_dbdata" virtual table module
*/
static int sqlite3DbdataRegister(sqlite3 *db){
- static sqlite3_module dbdata_module = {
+ static const sqlite3_module dbdata_module = {
0, /* iVersion */
0, /* xCreate */
dbdataConnect, /* xConnect */
@@ -9493,6 +9519,16 @@ int sqlite3_dbdata_init(
SQLITE_EXTENSION_INIT2(pApi);
return sqlite3DbdataRegister(db);
}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi);
+ return sqlite3DbdataRegister(db);
+}
+#endif
/************************* End ../ext/misc/dbdata.c ********************/
#endif
@@ -9676,7 +9712,7 @@ struct ShellState {
#define MODE_Pretty 11 /* Pretty-print schemas */
#define MODE_EQP 12 /* Converts EXPLAIN QUERY PLAN output into a graph */
-static const char *modeDescr[] = {
+static const char *const modeDescr[] = {
"line",
"column",
"list",
@@ -9762,8 +9798,8 @@ static void editFunc(
int rc;
int hasCRNL = 0;
FILE *f = 0;
- sqlite3_int64 sz;
- sqlite3_int64 x;
+ size_t sz;
+ size_t x;
unsigned char *p = 0;
if( argc==2 ){
@@ -9801,12 +9837,12 @@ static void editFunc(
}
sz = sqlite3_value_bytes(argv[0]);
if( bBin ){
- x = fwrite(sqlite3_value_blob(argv[0]), 1, (size_t)sz, f);
+ x = fwrite(sqlite3_value_blob(argv[0]), 1, sz, f);
}else{
const char *z = (const char*)sqlite3_value_text(argv[0]);
/* Remember whether or not the value originally contained \r\n */
if( z && strstr(z,"\r\n")!=0 ) hasCRNL = 1;
- x = fwrite(sqlite3_value_text(argv[0]), 1, (size_t)sz, f);
+ x = fwrite(sqlite3_value_text(argv[0]), 1, sz, f);
}
fclose(f);
f = 0;
@@ -9834,12 +9870,12 @@ static void editFunc(
fseek(f, 0, SEEK_END);
sz = ftell(f);
rewind(f);
- p = sqlite3_malloc64( sz+1 );
+ p = sqlite3_malloc( sz+1 );
if( p==0 ){
sqlite3_result_error_nomem(context);
goto edit_func_end;
}
- x = fread(p, 1, (size_t)sz, f);
+ x = fread(p, 1, sz, f);
fclose(f);
f = 0;
if( x!=sz ){
@@ -10186,7 +10222,7 @@ static int shellAuth(
const char *zA4
){
ShellState *p = (ShellState*)pClientData;
- static const char *azAction[] = { 0,
+ static const char *const azAction[] = { 0,
"CREATE_INDEX", "CREATE_TABLE", "CREATE_TEMP_INDEX",
"CREATE_TEMP_TABLE", "CREATE_TEMP_TRIGGER", "CREATE_TEMP_VIEW",
"CREATE_TRIGGER", "CREATE_VIEW", "DELETE",
@@ -10265,7 +10301,7 @@ static void eqp_append(ShellState *p, in
if( p->autoEQPtest ){
utf8_printf(p->out, "%d,%d,%s\n", iEqpId, p2, zText);
}
- pNew = sqlite3_malloc64( sizeof(*pNew) + nText );
+ pNew = sqlite3_malloc( sizeof(*pNew) + nText );
if( pNew==0 ) shell_out_of_memory();
pNew->iEqpId = iEqpId;
pNew->iParentId = p2;
@@ -10371,8 +10407,8 @@ static int progress_handler(void *pClien
static int shell_callback(
void *pArg,
int nArg, /* Number of result columns */
- char **azArg, /* Text of each result column */
- char **azCol, /* Column names */
+ const char **azArg,/* Text of each result column */
+ const char **azCol,/* Column names */
int *aiType /* Column types */
){
int i;
@@ -10399,7 +10435,7 @@ static int shell_callback(
static const int aExplainWidths[] = {4, 13, 4, 4, 4, 13, 2, 13};
const int *colWidth;
int showHdr;
- char *rowSep;
+ const char *rowSep;
if( p->cMode==MODE_Column ){
colWidth = p->colWidth;
showHdr = p->showHeader;
@@ -10547,7 +10583,7 @@ static int shell_callback(
}
if( azArg==0 ) break;
for(i=0; i<nArg; i++){
- char *z = azArg[i];
+ const char *z = azArg[i];
if( z==0 ) z = p->nullValue;
utf8_printf(p->out, "%s", z);
if( i<nArg-1 ){
@@ -10735,7 +10771,7 @@ static int shell_callback(
*/
static int callback(void *pArg, int nArg, char **azArg, char **azCol){
/* since we don't have type info, call the shell_callback with a NULL value */
- return shell_callback(pArg, nArg, azArg, azCol, NULL);
+ return shell_callback(pArg, nArg, (const char **)azArg, (const char **)azCol, NULL);
}
/*
@@ -10899,7 +10935,7 @@ static char *save_err_msg(
sqlite3 *db /* Database to query */
){
int nErrMsg = 1+strlen30(sqlite3_errmsg(db));
- char *zErrMsg = sqlite3_malloc64(nErrMsg);
+ char *zErrMsg = sqlite3_malloc(nErrMsg);
if( zErrMsg ){
memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg);
}
@@ -10947,8 +10983,8 @@ static void displayLinuxIoStats(FILE *ou
*/
static void displayStatLine(
ShellState *p, /* The shell context */
- char *zLabel, /* Label for this one line */
- char *zFormat, /* Format for the result */
+ const char *zLabel, /* Label for this one line */
+ const char *zFormat, /* Format for the result */
int iStatusCtrl, /* Which status to display */
int bReset /* True to reset the stats */
){
@@ -11153,7 +11189,7 @@ static void display_scanstats(
** is equal, according to strcmp(), to any of the strings in the array.
** Otherwise, return zero.
*/
-static int str_in_array(const char *zStr, const char **azArray){
+static int str_in_array(const char *zStr, const char *const *azArray){
int i;
for(i=0; azArray[i]; i++){
if( 0==strcmp(zStr, azArray[i]) ) return 1;
@@ -11186,10 +11222,10 @@ static void explain_data_prepare(ShellSt
int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */
int iOp; /* Index of operation in p->aiIndent[] */
- const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 };
- const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
+ const char *const azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 };
+ const char *const azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
"Rewind", 0 };
- const char *azGoto[] = { "Goto", 0 };
+ const char *const azGoto[] = { "Goto", 0 };
/* Try to figure out if this is really an EXPLAIN statement. If this
** cannot be verified, return early. */
@@ -11223,7 +11259,7 @@ static void explain_data_prepare(ShellSt
if( iOp==0 ){
/* Do further verfication that this is explain output. Abort if
** it is not */
- static const char *explainCols[] = {
+ static const char *const explainCols[] = {
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment" };
int jj;
for(jj=0; jj<ArraySize(explainCols); jj++){
@@ -11235,9 +11271,9 @@ static void explain_data_prepare(ShellSt
}
}
nAlloc += 100;
- p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int));
+ p->aiIndent = (int*)sqlite3_realloc(p->aiIndent, nAlloc*sizeof(int));
if( p->aiIndent==0 ) shell_out_of_memory();
- abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int));
+ abYield = (int*)sqlite3_realloc(abYield, nAlloc*sizeof(int));
if( abYield==0 ) shell_out_of_memory();
}
abYield[iOp] = str_in_array(zOp, azYield);
@@ -11376,18 +11412,18 @@ static void exec_prepared_stmt(
if( SQLITE_ROW == rc ){
/* allocate space for col name ptr, value ptr, and type */
int nCol = sqlite3_column_count(pStmt);
- void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1);
+ void *pData = sqlite3_malloc(3*nCol*sizeof(const char*) + 1);
if( !pData ){
rc = SQLITE_NOMEM;
}else{
- char **azCols = (char **)pData; /* Names of result columns */
- char **azVals = &azCols[nCol]; /* Results */
+ const char **azCols = (const char **)pData;/* Names of result columns */
+ const char **azVals = &azCols[nCol]; /* Results */
int *aiTypes = (int *)&azVals[nCol]; /* Result types */
int i, x;
assert(sizeof(int) <= sizeof(char *));
/* save off ptrs to column names */
for(i=0; i<nCol; i++){
- azCols[i] = (char *)sqlite3_column_name(pStmt, i);
+ azCols[i] = sqlite3_column_name(pStmt, i);
}
do{
/* extract the data and data types */
@@ -11396,7 +11432,7 @@ static void exec_prepared_stmt(
if( x==SQLITE_BLOB && pArg && pArg->cMode==MODE_Insert ){
azVals[i] = "";
}else{
- azVals[i] = (char*)sqlite3_column_text(pStmt, i);
+ azVals[i] = (const char *)sqlite3_column_text(pStmt, i);
}
if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
rc = SQLITE_NOMEM;
@@ -11805,7 +11841,7 @@ static char **tableColumnList(ShellState
if( preserveRowid ){
/* Only preserve the rowid if we can find a name to use for the
** rowid */
- static char *azRowid[] = { "rowid", "_rowid_", "oid" };
+ static const char *const azRowid[] = { "rowid", "_rowid_", "oid" };
int i, j;
for(j=0; j<3; j++){
for(i=1; i<=nCol; i++){
@@ -11817,7 +11853,7 @@ static char **tableColumnList(ShellState
** name for the rowid before adding it to azCol[0]. WITHOUT ROWID
** tables will fail this last check */
rc = sqlite3_table_column_metadata(p->db,0,zTab,azRowid[j],0,0,0,0,0);
- if( rc==SQLITE_OK ) azCol[0] = azRowid[j];
+ if( rc==SQLITE_OK ) azCol[0] = (char *)azRowid[j];
break;
}
}
@@ -12142,10 +12178,12 @@ static const char *(azHelp[]) = {
".schema ?PATTERN? Show the CREATE statements matching PATTERN",
" Options:",
" --indent Try to pretty-print the schema",
+#ifdef SQLITE_DEBUG
".selftest ?OPTIONS? Run tests defined in the SELFTEST table",
" Options:",
" --init Create a new SELFTEST table",
" -v Verbose output",
+#endif
".separator COL ?ROW? Change the column and row separators",
#if defined(SQLITE_ENABLE_SESSION)
".session ?NAME? CMD ... Create or control sessions",
@@ -12298,16 +12336,16 @@ static int process_input(ShellState *p);
** NULL is returned if any error is encountered. The final value of *pnByte
** is undefined in this case.
*/
-static char *readFile(const char *zName, int *pnByte){
+static char *readFile(const char *zName, size_t *pnByte){
FILE *in = fopen(zName, "rb");
- long nIn;
+ size_t nIn;
size_t nRead;
char *pBuf;
if( in==0 ) return 0;
fseek(in, 0, SEEK_END);
nIn = ftell(in);
rewind(in);
- pBuf = sqlite3_malloc64( nIn+1 );
+ pBuf = sqlite3_malloc( nIn+1 );
if( pBuf==0 ){ fclose(in); return 0; }
nRead = fread(pBuf, nIn, 1, in);
fclose(in);
@@ -12417,7 +12455,7 @@ int deduceDatabaseType(const char *zName
** program. Read content from the file in p->zDbFilename. If p->zDbFilename
** is 0, then read from standard input.
*/
-static unsigned char *readHexDb(ShellState *p, int *pnData){
+static unsigned char *readHexDb(ShellState *p, size_t *pnData){
unsigned char *a = 0;
int nLine;
int n = 0;
@@ -12592,9 +12630,9 @@ static void shellEscapeCrnl(
if( zNL || zCR ){
int iOut = 0;
- i64 nMax = (nNL > nCR) ? nNL : nCR;
- i64 nAlloc = nMax * nText + (nMax+64)*2;
- char *zOut = (char*)sqlite3_malloc64(nAlloc);
+ size_t nMax = (nNL > nCR) ? nNL : nCR;
+ size_t nAlloc = nMax * nText + (nMax+64)*2;
+ char *zOut = (char*)sqlite3_malloc(nAlloc);
if( zOut==0 ){
sqlite3_result_error_nomem(context);
return;
@@ -12743,7 +12781,7 @@ static void open_db(ShellState *p, int o
else
if( p->openMode==SHELL_OPEN_DESERIALIZE || p->openMode==SHELL_OPEN_HEXDB ){
int rc;
- int nData = 0;
+ size_t nData = 0;
unsigned char *aData;
if( p->openMode==SHELL_OPEN_DESERIALIZE ){
aData = (unsigned char*)readFile(p->zDbFilename, &nData);
@@ -13054,7 +13092,7 @@ struct ImportCtx {
static void import_append_char(ImportCtx *p, int c){
if( p->n+1>=p->nAlloc ){
p->nAlloc += p->nAlloc + 100;
- p->z = sqlite3_realloc64(p->z, p->nAlloc);
+ p->z = sqlite3_realloc(p->z, p->nAlloc);
if( p->z==0 ) shell_out_of_memory();
}
p->z[p->n++] = (char)c;
@@ -13073,7 +13111,7 @@ static void import_append_char(ImportCtx
** EOF on end-of-file.
** + Report syntax errors on stderr
*/
-static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
+static const char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
int c;
int cSep = p->cColSep;
int rSep = p->cRowSep;
@@ -13163,7 +13201,7 @@ static char *SQLITE_CDECL csv_read_one_f
** EOF on end-of-file.
** + Report syntax errors on stderr
*/
-static char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){
+static const char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){
int c;
int cSep = p->cColSep;
int rSep = p->cRowSep;
@@ -13215,7 +13253,7 @@ static void tryToCloneData(
goto end_data_xfer;
}
n = sqlite3_column_count(pQuery);
- zInsert = sqlite3_malloc64(200 + nTable + n*3);
+ zInsert = sqlite3_malloc(200 + nTable + n*3);
if( zInsert==0 ) shell_out_of_memory();
sqlite3_snprintf(200+nTable,zInsert,
"INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
@@ -13496,7 +13534,7 @@ static int shell_dbinfo_command(ShellSta
int i, rc;
unsigned iDataVersion;
char *zSchemaTab;
- char *zDb = nArg>=2 ? azArg[1] : "main";
+ const char *zDb = nArg>=2 ? azArg[1] : "main";
sqlite3_stmt *pStmt = 0;
unsigned char aHdr[100];
open_db(p, 0);
@@ -13981,7 +14019,7 @@ static int lintDotCommand(
return SQLITE_ERROR;
}
-#if !defined SQLITE_OMIT_VIRTUALTABLE
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
static void shellPrepare(
sqlite3 *db,
int *pRc,
@@ -14071,9 +14109,7 @@ void shellReset(
*pRc = rc;
}
}
-#endif /* !defined SQLITE_OMIT_VIRTUALTABLE */
-#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
/******************************************************************************
** The ".archive" or ".ar" command.
*/
@@ -14814,7 +14850,7 @@ static void shellExecPrintf(sqlite3 *db,
static void *shellMalloc(int *pRc, sqlite3_int64 nByte){
void *pRet = 0;
if( *pRc==SQLITE_OK ){
- pRet = sqlite3_malloc64(nByte);
+ pRet = sqlite3_malloc(nByte);
if( pRet==0 ){
*pRc = SQLITE_NOMEM;
}else{
@@ -16073,9 +16109,9 @@ static int do_meta_command(char *zLine,
sqlite3_exec(p->db, "SELECT 'ANALYZE sqlite_master'",
callback, &data, &zErrMsg);
data.cMode = data.mode = MODE_Insert;
- data.zDestTable = "sqlite_stat1";
+ data.zDestTable = (char *)"sqlite_stat1";
shell_exec(&data, "SELECT * FROM sqlite_stat1", &zErrMsg);
- data.zDestTable = "sqlite_stat4";
+ data.zDestTable = (char *)"sqlite_stat4";
shell_exec(&data, "SELECT * FROM sqlite_stat4", &zErrMsg);
raw_printf(p->out, "ANALYZE sqlite_master;\n");
}
@@ -16112,7 +16148,7 @@ static int do_meta_command(char *zLine,
int nSep; /* Number of bytes in p->colSeparator[] */
char *zSql; /* An SQL statement */
ImportCtx sCtx; /* Reader context */
- char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
+ const char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close file */
if( nArg!=3 ){
@@ -16225,7 +16261,7 @@ static int do_meta_command(char *zLine,
sqlite3_finalize(pStmt);
pStmt = 0;
if( nCol==0 ) return 0; /* no columns, no error */
- zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
+ zSql = sqlite3_malloc( nByte*2 + 20 + nCol*2 );
if( zSql==0 ){
xCloser(sCtx.in);
shell_out_of_memory();
@@ -16251,7 +16287,7 @@ static int do_meta_command(char *zLine,
do{
int startLine = sCtx.nLine;
for(i=0; i<nCol; i++){
- char *z = xRead(&sCtx);
+ const char *z = xRead(&sCtx);
/*
** Did we reach end-of-file before finding any columns?
** If so, stop instead of NULL filling the remaining columns.
@@ -16619,8 +16655,8 @@ static int do_meta_command(char *zLine,
if( azArg[0][0]=='e' ){
/* Transform the ".excel" command into ".once -x" */
nArg = 2;
- azArg[0] = "once";
- zFile = azArg[1] = "-x";
+ azArg[0] = (char *)"once";
+ zFile = azArg[1] = (char *)"-x";
n = 4;
}
if( nArg>2 ){
@@ -16981,7 +17017,7 @@ static int do_meta_command(char *zLine,
" sql text\n"
")", isMaster ? "sqlite_master" : "sqlite_temp_master");
new_argv[1] = 0;
- new_colv[0] = "sql";
+ new_colv[0] = (char *)"sql";
new_colv[1] = 0;
callback(&data, 1, new_argv, new_colv);
sqlite3_free(new_argv[0]);
@@ -17423,7 +17459,7 @@ static int do_meta_command(char *zLine,
int bDebug = 0; /* Only show the query that would have run */
sqlite3_stmt *pStmt; /* For querying tables names */
char *zSql; /* SQL to be run */
- char *zSep; /* Separator */
+ const char *zSep; /* Separator */
ShellText sSql; /* Complete SQL for the query to run the hash */
ShellText sQuery; /* Set of queries used to read all content */
open_db(p, 0);
@@ -17461,12 +17497,12 @@ static int do_meta_command(char *zLine,
}
}
if( bSchema ){
- zSql = "SELECT lower(name) FROM sqlite_master"
+ zSql = (char *)"SELECT lower(name) FROM sqlite_master"
" WHERE type='table' AND coalesce(rootpage,0)>1"
" UNION ALL SELECT 'sqlite_master'"
" ORDER BY 1 collate nocase";
}else{
- zSql = "SELECT lower(name) FROM sqlite_master"
+ zSql = (char *)"SELECT lower(name) FROM sqlite_master"
" WHERE type='table' AND coalesce(rootpage,0)>1"
" AND name NOT LIKE 'sqlite_%'"
" ORDER BY 1 collate nocase";
@@ -17551,7 +17587,7 @@ static int do_meta_command(char *zLine,
#endif /* !defined(SQLITE_NOHAVE_SYSTEM) */
if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
- static const char *azBool[] = { "off", "on", "trigger", "full"};
+ static const char *const azBool[] = { "off", "on", "trigger", "full"};
int i;
if( nArg!=1 ){
raw_printf(stderr, "Usage: .show\n");
@@ -17664,7 +17700,7 @@ static int do_meta_command(char *zLine,
if( nRow>=nAlloc ){
char **azNew;
int n2 = nAlloc*2 + 10;
- azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2);
+ azNew = sqlite3_realloc(azResult, sizeof(azResult[0])*n2);
if( azNew==0 ) shell_out_of_memory();
nAlloc = n2;
azResult = azNew;
@@ -17691,7 +17727,7 @@ static int do_meta_command(char *zLine,
nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
for(i=0; i<nPrintRow; i++){
for(j=i; j<nRow; j+=nPrintRow){
- char *zSp = j<nPrintRow ? "" : " ";
+ const char *zSp = j<nPrintRow ? "" : " ";
utf8_printf(p->out, "%s%-*s", zSp, maxlen,
azResult[j] ? azResult[j]:"");
}
@@ -18486,7 +18522,9 @@ static const char zOptions[] =
" -interactive force interactive I/O\n"
" -line set output mode to 'line'\n"
" -list set output mode to 'list'\n"
+#ifndef SQLITE_OMIT_LOOKASIDE
" -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n"
+#endif
#if defined(SQLITE_ENABLE_DESERIALIZE)
" -maxsize N maximum size for a --deserialize database\n"
#endif
@@ -18500,6 +18538,7 @@ static const char zOptions[] =
" -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n"
" -quote set output mode to 'quote'\n"
" -readonly open the database read-only\n"
+ " -scanstats print scan stats before each finalize\n"
" -separator SEP set output column separator. Default: '|'\n"
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
" -sorterref SIZE sorter references threshold size\n"
@@ -18507,6 +18546,9 @@ static const char zOptions[] =
" -stats print memory stats before each finalize\n"
" -version show SQLite version\n"
" -vfs NAME use NAME as the default VFS\n"
+#ifdef SQLITE_USE_FCNTL_TRACE
+ " -vfslog enable the vfslog extension\n"
+#endif
#ifdef SQLITE_ENABLE_VFSTRACE
" -vfstrace enable tracing of all VFS calls\n"
#endif
@@ -18550,6 +18592,8 @@ static void main_init(ShellState *data)
data->showHeader = 0;
data->shellFlgs = SHFLG_Lookaside;
verify_uninitialized();
+ sqlite3_config(64); /* SQLITE_CONFIG_EXPLAIN_COMMENTS */
+ sqlite3_config(65); /* SQLITE_CONFIG_ENABLE_UNKOWN_SQL_FUNCTION */
sqlite3_config(SQLITE_CONFIG_URI, 1);
sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
@@ -18590,8 +18634,12 @@ static char *cmdline_option_value(int ar
return argv[i];
}
+#if defined(_WIN32) && defined(__MSVCRT__) && !defined(main)
+int _CRT_glob = 0x0001; /* See MinGW bug #2062 */
+#endif
+
#ifndef SQLITE_SHELL_IS_UTF8
-# if (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)
+# if (defined(_WIN32) || defined(WIN32)) && (defined(_MSC_VER) || defined(__MSVCRT__))
# define SQLITE_SHELL_IS_UTF8 (0)
# else
# define SQLITE_SHELL_IS_UTF8 (1)
@@ -18749,6 +18797,11 @@ int SQLITE_CDECL wmain(int argc, wchar_t
#else
(void)cmdline_option_value(argc, argv, ++i);
#endif
+#ifdef SQLITE_USE_FCNTL_TRACE
+ }else if( strcmp(z,"-vfslog")==0 ){
+ extern int sqlite3_register_vfslog(const char *);
+ sqlite3_register_vfslog(NULL);
+#endif
}else if( strcmp(z,"-pagecache")==0 ){
int n, sz;
sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
@@ -18970,6 +19023,10 @@ int SQLITE_CDECL wmain(int argc, wchar_t
#endif
}else if( strcmp(z,"-vfs")==0 ){
i++;
+#ifdef SQLITE_USE_FCNTL_TRACE
+ }else if( strcmp(z,"-vfslog")==0 ){
+ i++;
+#endif
#ifdef SQLITE_ENABLE_VFSTRACE
}else if( strcmp(z,"-vfstrace")==0 ){
i++;
--- origsrc/sqlite-autoconf-3300000/showauth.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/showauth.c 2019-10-08 13:42:19.215975200 +0200
@@ -0,0 +1,112 @@
+/*
+** 2014-09-21
+**
+** 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 SQLite extension adds a debug "authorizer" callback to the database
+** connection. The callback merely writes the authorization request to
+** standard output and returns SQLITE_OK.
+**
+** This extension can be used (for example) in the command-line shell to
+** trace the operation of the authorizer.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <stdio.h>
+
+/*
+** Display the authorization request
+*/
+static int authCallback(
+ void *pClientData,
+ int op,
+ const char *z1,
+ const char *z2,
+ const char *z3,
+ const char *z4
+){
+ const char *zOp;
+ char zOpSpace[50];
+ switch( op ){
+ case SQLITE_CREATE_INDEX: zOp = "CREATE_INDEX"; break;
+ case SQLITE_CREATE_TABLE: zOp = "CREATE_TABLE"; break;
+ case SQLITE_CREATE_TEMP_INDEX: zOp = "CREATE_TEMP_INDEX"; break;
+ case SQLITE_CREATE_TEMP_TABLE: zOp = "CREATE_TEMP_TABLE"; break;
+ case SQLITE_CREATE_TEMP_TRIGGER: zOp = "CREATE_TEMP_TRIGGER"; break;
+ case SQLITE_CREATE_TEMP_VIEW: zOp = "CREATE_TEMP_VIEW"; break;
+ case SQLITE_CREATE_TRIGGER: zOp = "CREATE_TRIGGER"; break;
+ case SQLITE_CREATE_VIEW: zOp = "CREATE_VIEW"; break;
+ case SQLITE_DELETE: zOp = "DELETE"; break;
+ case SQLITE_DROP_INDEX: zOp = "DROP_INDEX"; break;
+ case SQLITE_DROP_TABLE: zOp = "DROP_TABLE"; break;
+ case SQLITE_DROP_TEMP_INDEX: zOp = "DROP_TEMP_INDEX"; break;
+ case SQLITE_DROP_TEMP_TABLE: zOp = "DROP_TEMP_TABLE"; break;
+ case SQLITE_DROP_TEMP_TRIGGER: zOp = "DROP_TEMP_TRIGGER"; break;
+ case SQLITE_DROP_TEMP_VIEW: zOp = "DROP_TEMP_VIEW"; break;
+ case SQLITE_DROP_TRIGGER: zOp = "DROP_TRIGGER"; break;
+ case SQLITE_DROP_VIEW: zOp = "DROP_VIEW"; break;
+ case SQLITE_INSERT: zOp = "INSERT"; break;
+ case SQLITE_PRAGMA: zOp = "PRAGMA"; break;
+ case SQLITE_READ: zOp = "READ"; break;
+ case SQLITE_SELECT: zOp = "SELECT"; break;
+ case SQLITE_TRANSACTION: zOp = "TRANSACTION"; break;
+ case SQLITE_UPDATE: zOp = "UPDATE"; break;
+ case SQLITE_ATTACH: zOp = "ATTACH"; break;
+ case SQLITE_DETACH: zOp = "DETACH"; break;
+ case SQLITE_ALTER_TABLE: zOp = "ALTER_TABLE"; break;
+ case SQLITE_REINDEX: zOp = "REINDEX"; break;
+ case SQLITE_ANALYZE: zOp = "ANALYZE"; break;
+ case SQLITE_CREATE_VTABLE: zOp = "CREATE_VTABLE"; break;
+ case SQLITE_DROP_VTABLE: zOp = "DROP_VTABLE"; break;
+ case SQLITE_FUNCTION: zOp = "FUNCTION"; break;
+ case SQLITE_SAVEPOINT: zOp = "SAVEPOINT"; break;
+ case SQLITE_COPY: zOp = "COPY"; break;
+ case SQLITE_RECURSIVE: zOp = "RECURSIVE"; break;
+
+
+ default: {
+ sqlite3_snprintf(sizeof(zOpSpace), zOpSpace, "%d", op);
+ zOp = zOpSpace;
+ break;
+ }
+ }
+ if( z1==0 ) z1 = "NULL";
+ if( z2==0 ) z2 = "NULL";
+ if( z3==0 ) z3 = "NULL";
+ if( z4==0 ) z4 = "NULL";
+ printf("AUTH: %s,%s,%s,%s,%s\n", zOp, z1, z2, z3, z4);
+ return SQLITE_OK;
+}
+
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_showauth_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_set_authorizer(db, authCallback, 0);
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ return sqlite3_showauth_init(db, pzErrMsg, pApi);
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/spaceanal.tcl 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/spaceanal.tcl 2019-03-05 13:14:40.824000000 +0100
@@ -0,0 +1,896 @@
+#! /bin/sh
+# restart with tclsh \
+exec tclsh "$0" ${1+"$@"}
+package require sqlite3
+
+# Run this TCL script using an SQLite-enabled TCL interpreter to get a report
+# on how much disk space is used by a particular data to actually store data
+# versus how much space is unused.
+#
+# The dbstat virtual table is required.
+#
+
+if {[catch {
+
+# Argument $tname is the name of a table within the database opened by
+# database handle [db]. Return true if it is a WITHOUT ROWID table, or
+# false otherwise.
+#
+proc is_without_rowid {tname} {
+ set t [string map {' ''} $tname]
+ db eval "PRAGMA index_list = '$t'" o {
+ if {$o(origin) == "pk"} {
+ set n $o(name)
+ if {0==[db one { SELECT count(*) FROM sqlite_master WHERE name=$n }]} {
+ return 1
+ }
+ }
+ }
+ return 0
+}
+
+# Read and run TCL commands from standard input. Used to implement
+# the --tclsh option.
+#
+proc tclsh {} {
+ set line {}
+ while {![eof stdin]} {
+ if {$line!=""} {
+ puts -nonewline "> "
+ } else {
+ puts -nonewline "% "
+ }
+ flush stdout
+ append line [gets stdin]
+ if {[info complete $line]} {
+ if {[catch {uplevel #0 $line} result]} {
+ puts stderr "Error: $result"
+ } elseif {$result!=""} {
+ puts $result
+ }
+ set line {}
+ } else {
+ append line \n
+ }
+ }
+}
+
+
+# Get the name of the database to analyze
+#
+proc usage {} {
+ set argv0 [file rootname [file tail [info script]]]
+ puts stderr "Usage: $argv0 ?--pageinfo? ?--stats? database-filename"
+ puts stderr {
+Analyze the SQLite3 database file specified by the "database-filename"
+argument and output a report detailing size and storage efficiency
+information for the database and its constituent tables and indexes.
+
+Options:
+
+ --pageinfo Show how each page of the database-file is used
+
+ --stats Output SQL text that creates a new database containing
+ statistics about the database that was analyzed
+
+ --tclsh Run the built-in TCL interpreter interactively (for debugging)
+
+ --version Show the version number of SQLite
+}
+ exit 1
+}
+set file_to_analyze {}
+set flags(-pageinfo) 0
+set flags(-stats) 0
+set flags(-debug) 0
+append argv {}
+foreach arg $argv {
+ if {[regexp {^-+pageinfo$} $arg]} {
+ set flags(-pageinfo) 1
+ } elseif {[regexp {^-+stats$} $arg]} {
+ set flags(-stats) 1
+ } elseif {[regexp {^-+debug$} $arg]} {
+ set flags(-debug) 1
+ } elseif {[regexp {^-+tclsh$} $arg]} {
+ tclsh
+ exit 0
+ } elseif {[regexp {^-+version$} $arg]} {
+ sqlite3 mem :memory:
+ puts [mem one {SELECT sqlite_version()||' '||sqlite_source_id()}]
+ mem close
+ exit 0
+ } elseif {[regexp {^-} $arg]} {
+ puts stderr "Unknown option: $arg"
+ usage
+ } elseif {$file_to_analyze!=""} {
+ usage
+ } else {
+ set file_to_analyze $arg
+ }
+}
+if {$file_to_analyze==""} usage
+set root_filename $file_to_analyze
+regexp {^file:(//)?([^?]*)} $file_to_analyze all x1 root_filename
+if {![file exists $root_filename]} {
+ puts stderr "No such file: $root_filename"
+ exit 1
+}
+if {![file readable $root_filename]} {
+ puts stderr "File is not readable: $root_filename"
+ exit 1
+}
+set true_file_size [file size $root_filename]
+if {$true_file_size<512} {
+ puts stderr "Empty or malformed database: $root_filename"
+ exit 1
+}
+
+# Compute the total file size assuming test_multiplexor is being used.
+# Assume that SQLITE_ENABLE_8_3_NAMES might be enabled
+#
+set extension [file extension $root_filename]
+set pattern $root_filename
+append pattern {[0-3][0-9][0-9]}
+foreach f [glob -nocomplain $pattern] {
+ incr true_file_size [file size $f]
+ set extension {}
+}
+if {[string length $extension]>=2 && [string length $extension]<=4} {
+ set pattern [file rootname $root_filename]
+ append pattern {.[0-3][0-9][0-9]}
+ foreach f [glob -nocomplain $pattern] {
+ incr true_file_size [file size $f]
+ }
+}
+
+# Open the database
+#
+if {[catch {sqlite3 db $file_to_analyze -uri 1} msg]} {
+ puts stderr "error trying to open $file_to_analyze: $msg"
+ exit 1
+}
+if {$flags(-debug)} {
+ proc dbtrace {txt} {puts $txt; flush stdout;}
+ db trace ::dbtrace
+}
+
+# Make sure all required compile-time options are available
+#
+if {![db exists {SELECT 1 FROM pragma_compile_options
+ WHERE compile_options='ENABLE_DBSTAT_VTAB'}]} {
+ puts "The SQLite database engine linked with this application\
+ lacks required capabilities. Recompile using the\
+ -DSQLITE_ENABLE_DBSTAT_VTAB compile-time option to fix\
+ this problem."
+ exit 1
+}
+
+db eval {SELECT count(*) FROM sqlite_master}
+set pageSize [expr {wide([db one {PRAGMA page_size}])}]
+
+if {$flags(-pageinfo)} {
+ db eval {CREATE VIRTUAL TABLE temp.stat USING dbstat}
+ db eval {SELECT name, path, pageno FROM temp.stat ORDER BY pageno} {
+ puts "$pageno $name $path"
+ }
+ exit 0
+}
+if {$flags(-stats)} {
+ db eval {CREATE VIRTUAL TABLE temp.stat USING dbstat}
+ puts "BEGIN;"
+ puts "CREATE TABLE stats("
+ puts " name STRING, /* Name of table or index */"
+ puts " path INTEGER, /* Path to page from root */"
+ puts " pageno INTEGER, /* Page number */"
+ puts " pagetype STRING, /* 'internal', 'leaf' or 'overflow' */"
+ puts " ncell INTEGER, /* Cells on page (0 for overflow) */"
+ puts " payload INTEGER, /* Bytes of payload on this page */"
+ puts " unused INTEGER, /* Bytes of unused space on this page */"
+ puts " mx_payload INTEGER, /* Largest payload size of all cells */"
+ puts " pgoffset INTEGER, /* Offset of page in file */"
+ puts " pgsize INTEGER /* Size of the page */"
+ puts ");"
+ db eval {SELECT quote(name) || ',' ||
+ quote(path) || ',' ||
+ quote(pageno) || ',' ||
+ quote(pagetype) || ',' ||
+ quote(ncell) || ',' ||
+ quote(payload) || ',' ||
+ quote(unused) || ',' ||
+ quote(mx_payload) || ',' ||
+ quote(pgoffset) || ',' ||
+ quote(pgsize) AS x FROM stat} {
+ puts "INSERT INTO stats VALUES($x);"
+ }
+ puts "COMMIT;"
+ exit 0
+}
+
+
+# In-memory database for collecting statistics. This script loops through
+# the tables and indices in the database being analyzed, adding a row for each
+# to an in-memory database (for which the schema is shown below). It then
+# queries the in-memory db to produce the space-analysis report.
+#
+sqlite3 mem :memory:
+if {$flags(-debug)} {
+ proc dbtrace {txt} {puts $txt; flush stdout;}
+ mem trace ::dbtrace
+}
+set tabledef {CREATE TABLE space_used(
+ name clob, -- Name of a table or index in the database file
+ tblname clob, -- Name of associated table
+ is_index boolean, -- TRUE if it is an index, false for a table
+ is_without_rowid boolean, -- TRUE if WITHOUT ROWID table
+ nentry int, -- Number of entries in the BTree
+ leaf_entries int, -- Number of leaf entries
+ depth int, -- Depth of the b-tree
+ payload int, -- Total amount of data stored in this table or index
+ ovfl_payload int, -- Total amount of data stored on overflow pages
+ ovfl_cnt int, -- Number of entries that use overflow
+ mx_payload int, -- Maximum payload size
+ int_pages int, -- Number of interior pages used
+ leaf_pages int, -- Number of leaf pages used
+ ovfl_pages int, -- Number of overflow pages used
+ int_unused int, -- Number of unused bytes on interior pages
+ leaf_unused int, -- Number of unused bytes on primary pages
+ ovfl_unused int, -- Number of unused bytes on overflow pages
+ gap_cnt int, -- Number of gaps in the page layout
+ compressed_size int -- Total bytes stored on disk
+);}
+mem eval $tabledef
+
+# Create a temporary "dbstat" virtual table.
+#
+db eval {CREATE VIRTUAL TABLE temp.stat USING dbstat}
+db eval {CREATE TEMP TABLE dbstat AS SELECT * FROM temp.stat
+ ORDER BY name, path}
+db eval {DROP TABLE temp.stat}
+
+set isCompressed 0
+set compressOverhead 0
+set depth 0
+set sql { SELECT name, tbl_name FROM sqlite_master WHERE rootpage>0 }
+foreach {name tblname} [concat sqlite_master sqlite_master [db eval $sql]] {
+
+ set is_index [expr {$name!=$tblname}]
+ set is_without_rowid [is_without_rowid $name]
+ db eval {
+ SELECT
+ sum(ncell) AS nentry,
+ sum((pagetype=='leaf')*ncell) AS leaf_entries,
+ sum(payload) AS payload,
+ sum((pagetype=='overflow') * payload) AS ovfl_payload,
+ sum(path LIKE '%+000000') AS ovfl_cnt,
+ max(mx_payload) AS mx_payload,
+ sum(pagetype=='internal') AS int_pages,
+ sum(pagetype=='leaf') AS leaf_pages,
+ sum(pagetype=='overflow') AS ovfl_pages,
+ sum((pagetype=='internal') * unused) AS int_unused,
+ sum((pagetype=='leaf') * unused) AS leaf_unused,
+ sum((pagetype=='overflow') * unused) AS ovfl_unused,
+ sum(pgsize) AS compressed_size,
+ max((length(CASE WHEN path LIKE '%+%' THEN '' ELSE path END)+3)/4)
+ AS depth
+ FROM temp.dbstat WHERE name = $name
+ } break
+
+ set total_pages [expr {$leaf_pages+$int_pages+$ovfl_pages}]
+ set storage [expr {$total_pages*$pageSize}]
+ if {!$isCompressed && $storage>$compressed_size} {
+ set isCompressed 1
+ set compressOverhead 14
+ }
+
+ # Column 'gap_cnt' is set to the number of non-contiguous entries in the
+ # list of pages visited if the b-tree structure is traversed in a top-down
+ # fashion (each node visited before its child-tree is passed). Any overflow
+ # chains present are traversed from start to finish before any child-tree
+ # is.
+ #
+ set gap_cnt 0
+ set prev 0
+ db eval {
+ SELECT pageno, pagetype FROM temp.dbstat
+ WHERE name=$name
+ ORDER BY pageno
+ } {
+ if {$prev>0 && $pagetype=="leaf" && $pageno!=$prev+1} {
+ incr gap_cnt
+ }
+ set prev $pageno
+ }
+ mem eval {
+ INSERT INTO space_used VALUES(
+ $name,
+ $tblname,
+ $is_index,
+ $is_without_rowid,
+ $nentry,
+ $leaf_entries,
+ $depth,
+ $payload,
+ $ovfl_payload,
+ $ovfl_cnt,
+ $mx_payload,
+ $int_pages,
+ $leaf_pages,
+ $ovfl_pages,
+ $int_unused,
+ $leaf_unused,
+ $ovfl_unused,
+ $gap_cnt,
+ $compressed_size
+ );
+ }
+}
+
+proc integerify {real} {
+ if {[string is double -strict $real]} {
+ return [expr {wide($real)}]
+ } else {
+ return 0
+ }
+}
+mem function int integerify
+
+# Quote a string for use in an SQL query. Examples:
+#
+# [quote {hello world}] == {'hello world'}
+# [quote {hello world's}] == {'hello world''s'}
+#
+proc quote {txt} {
+ return [string map {' ''} $txt]
+}
+
+# Output a title line
+#
+proc titleline {title} {
+ if {$title==""} {
+ puts [string repeat * 79]
+ } else {
+ set len [string length $title]
+ set stars [string repeat * [expr 79-$len-5]]
+ puts "*** $title $stars"
+ }
+}
+
+# Generate a single line of output in the statistics section of the
+# report.
+#
+proc statline {title value {extra {}}} {
+ set len [string length $title]
+ set dots [string repeat . [expr 50-$len]]
+ set len [string length $value]
+ set sp2 [string range { } $len end]
+ if {$extra ne ""} {
+ set extra " $extra"
+ }
+ puts "$title$dots $value$sp2$extra"
+}
+
+# Generate a formatted percentage value for $num/$denom
+#
+proc percent {num denom {of {}}} {
+ if {$denom==0.0} {return ""}
+ set v [expr {$num*100.0/$denom}]
+ set of {}
+ if {$v==100.0 || $v<0.001 || ($v>1.0 && $v<99.0)} {
+ return [format {%5.1f%% %s} $v $of]
+ } elseif {$v<0.1 || $v>99.9} {
+ return [format {%7.3f%% %s} $v $of]
+ } else {
+ return [format {%6.2f%% %s} $v $of]
+ }
+}
+
+proc divide {num denom} {
+ if {$denom==0} {return 0.0}
+ return [format %.2f [expr double($num)/double($denom)]]
+}
+
+# Generate a subreport that covers some subset of the database.
+# the $where clause determines which subset to analyze.
+#
+proc subreport {title where showFrag} {
+ global pageSize file_pgcnt compressOverhead
+
+ # Query the in-memory database for the sum of various statistics
+ # for the subset of tables/indices identified by the WHERE clause in
+ # $where. Note that even if the WHERE clause matches no rows, the
+ # following query returns exactly one row (because it is an aggregate).
+ #
+ # The results of the query are stored directly by SQLite into local
+ # variables (i.e. $nentry, $payload etc.).
+ #
+ mem eval "
+ SELECT
+ int(sum(
+ CASE WHEN (is_without_rowid OR is_index) THEN nentry
+ ELSE leaf_entries
+ END
+ )) AS nentry,
+ int(sum(payload)) AS payload,
+ int(sum(ovfl_payload)) AS ovfl_payload,
+ max(mx_payload) AS mx_payload,
+ int(sum(ovfl_cnt)) as ovfl_cnt,
+ int(sum(leaf_pages)) AS leaf_pages,
+ int(sum(int_pages)) AS int_pages,
+ int(sum(ovfl_pages)) AS ovfl_pages,
+ int(sum(leaf_unused)) AS leaf_unused,
+ int(sum(int_unused)) AS int_unused,
+ int(sum(ovfl_unused)) AS ovfl_unused,
+ int(sum(gap_cnt)) AS gap_cnt,
+ int(sum(compressed_size)) AS compressed_size,
+ int(max(depth)) AS depth,
+ count(*) AS cnt
+ FROM space_used WHERE $where" {} {}
+
+ # Output the sub-report title, nicely decorated with * characters.
+ #
+ puts ""
+ titleline $title
+ puts ""
+
+ # Calculate statistics and store the results in TCL variables, as follows:
+ #
+ # total_pages: Database pages consumed.
+ # total_pages_percent: Pages consumed as a percentage of the file.
+ # storage: Bytes consumed.
+ # payload_percent: Payload bytes used as a percentage of $storage.
+ # total_unused: Unused bytes on pages.
+ # avg_payload: Average payload per btree entry.
+ # avg_fanout: Average fanout for internal pages.
+ # avg_unused: Average unused bytes per btree entry.
+ # avg_meta: Average metadata overhead per entry.
+ # ovfl_cnt_percent: Percentage of btree entries that use overflow pages.
+ #
+ set total_pages [expr {$leaf_pages+$int_pages+$ovfl_pages}]
+ set total_pages_percent [percent $total_pages $file_pgcnt]
+ set storage [expr {$total_pages*$pageSize}]
+ set payload_percent [percent $payload $storage {of storage consumed}]
+ set total_unused [expr {$ovfl_unused+$int_unused+$leaf_unused}]
+ set avg_payload [divide $payload $nentry]
+ set avg_unused [divide $total_unused $nentry]
+ set total_meta [expr {$storage - $payload - $total_unused}]
+ set total_meta [expr {$total_meta + 4*($ovfl_pages - $ovfl_cnt)}]
+ set meta_percent [percent $total_meta $storage {of metadata}]
+ set avg_meta [divide $total_meta $nentry]
+ if {$int_pages>0} {
+ # TODO: Is this formula correct?
+ set nTab [mem eval "
+ SELECT count(*) FROM (
+ SELECT DISTINCT tblname FROM space_used WHERE $where AND is_index=0
+ )
+ "]
+ set avg_fanout [mem eval "
+ SELECT (sum(leaf_pages+int_pages)-$nTab)/sum(int_pages) FROM space_used
+ WHERE $where
+ "]
+ set avg_fanout [format %.2f $avg_fanout]
+ }
+ set ovfl_cnt_percent [percent $ovfl_cnt $nentry {of all entries}]
+
+ # Print out the sub-report statistics.
+ #
+ statline {Percentage of total database} $total_pages_percent
+ statline {Number of entries} $nentry
+ statline {Bytes of storage consumed} $storage
+ if {$compressed_size!=$storage} {
+ set compressed_size [expr {$compressed_size+$compressOverhead*$total_pages}]
+ set pct [expr {$compressed_size*100.0/$storage}]
+ set pct [format {%5.1f%%} $pct]
+ statline {Bytes used after compression} $compressed_size $pct
+ }
+ statline {Bytes of payload} $payload $payload_percent
+ statline {Bytes of metadata} $total_meta $meta_percent
+ if {$cnt==1} {statline {B-tree depth} $depth}
+ statline {Average payload per entry} $avg_payload
+ statline {Average unused bytes per entry} $avg_unused
+ statline {Average metadata per entry} $avg_meta
+ if {[info exists avg_fanout]} {
+ statline {Average fanout} $avg_fanout
+ }
+ if {$showFrag && $total_pages>1} {
+ set fragmentation [percent $gap_cnt [expr {$total_pages-1}]]
+ statline {Non-sequential pages} $gap_cnt $fragmentation
+ }
+ statline {Maximum payload per entry} $mx_payload
+ statline {Entries that use overflow} $ovfl_cnt $ovfl_cnt_percent
+ if {$int_pages>0} {
+ statline {Index pages used} $int_pages
+ }
+ statline {Primary pages used} $leaf_pages
+ statline {Overflow pages used} $ovfl_pages
+ statline {Total pages used} $total_pages
+ if {$int_unused>0} {
+ set int_unused_percent [
+ percent $int_unused [expr {$int_pages*$pageSize}] {of index space}]
+ statline "Unused bytes on index pages" $int_unused $int_unused_percent
+ }
+ statline "Unused bytes on primary pages" $leaf_unused [
+ percent $leaf_unused [expr {$leaf_pages*$pageSize}] {of primary space}]
+ statline "Unused bytes on overflow pages" $ovfl_unused [
+ percent $ovfl_unused [expr {$ovfl_pages*$pageSize}] {of overflow space}]
+ statline "Unused bytes on all pages" $total_unused [
+ percent $total_unused $storage {of all space}]
+ return 1
+}
+
+# Calculate the overhead in pages caused by auto-vacuum.
+#
+# This procedure calculates and returns the number of pages used by the
+# auto-vacuum 'pointer-map'. If the database does not support auto-vacuum,
+# then 0 is returned. The two arguments are the size of the database file in
+# pages and the page size used by the database (in bytes).
+proc autovacuum_overhead {filePages pageSize} {
+
+ # Set $autovacuum to non-zero for databases that support auto-vacuum.
+ set autovacuum [db one {PRAGMA auto_vacuum}]
+
+ # If the database is not an auto-vacuum database or the file consists
+ # of one page only then there is no overhead for auto-vacuum. Return zero.
+ if {0==$autovacuum || $filePages==1} {
+ return 0
+ }
+
+ # The number of entries on each pointer map page. The layout of the
+ # database file is one pointer-map page, followed by $ptrsPerPage other
+ # pages, followed by a pointer-map page etc. The first pointer-map page
+ # is the second page of the file overall.
+ set ptrsPerPage [expr double($pageSize/5)]
+
+ # Return the number of pointer map pages in the database.
+ return [expr wide(ceil( ($filePages-1.0)/($ptrsPerPage+1.0) ))]
+}
+
+
+# Calculate the summary statistics for the database and store the results
+# in TCL variables. They are output below. Variables are as follows:
+#
+# pageSize: Size of each page in bytes.
+# file_bytes: File size in bytes.
+# file_pgcnt: Number of pages in the file.
+# file_pgcnt2: Number of pages in the file (calculated).
+# av_pgcnt: Pages consumed by the auto-vacuum pointer-map.
+# av_percent: Percentage of the file consumed by auto-vacuum pointer-map.
+# inuse_pgcnt: Data pages in the file.
+# inuse_percent: Percentage of pages used to store data.
+# free_pgcnt: Free pages calculated as (<total pages> - <in-use pages>)
+# free_pgcnt2: Free pages in the file according to the file header.
+# free_percent: Percentage of file consumed by free pages (calculated).
+# free_percent2: Percentage of file consumed by free pages (header).
+# ntable: Number of tables in the db.
+# nindex: Number of indices in the db.
+# nautoindex: Number of indices created automatically.
+# nmanindex: Number of indices created manually.
+# user_payload: Number of bytes of payload in table btrees
+# (not including sqlite_master)
+# user_percent: $user_payload as a percentage of total file size.
+
+### The following, setting $file_bytes based on the actual size of the file
+### on disk, causes this tool to choke on zipvfs databases. So set it based
+### on the return of [PRAGMA page_count] instead.
+if 0 {
+ set file_bytes [file size $file_to_analyze]
+ set file_pgcnt [expr {$file_bytes/$pageSize}]
+}
+set file_pgcnt [db one {PRAGMA page_count}]
+set file_bytes [expr {$file_pgcnt * $pageSize}]
+
+set av_pgcnt [autovacuum_overhead $file_pgcnt $pageSize]
+set av_percent [percent $av_pgcnt $file_pgcnt]
+
+set sql {SELECT sum(leaf_pages+int_pages+ovfl_pages) FROM space_used}
+set inuse_pgcnt [expr wide([mem eval $sql])]
+set inuse_percent [percent $inuse_pgcnt $file_pgcnt]
+
+set free_pgcnt [expr {$file_pgcnt-$inuse_pgcnt-$av_pgcnt}]
+set free_percent [percent $free_pgcnt $file_pgcnt]
+set free_pgcnt2 [db one {PRAGMA freelist_count}]
+set free_percent2 [percent $free_pgcnt2 $file_pgcnt]
+
+set file_pgcnt2 [expr {$inuse_pgcnt+$free_pgcnt2+$av_pgcnt}]
+
+set ntable [db eval {SELECT count(*)+1 FROM sqlite_master WHERE type='table'}]
+set nindex [db eval {SELECT count(*) FROM sqlite_master WHERE type='index'}]
+set sql {SELECT count(*) FROM sqlite_master WHERE name LIKE 'sqlite_autoindex%'}
+set nautoindex [db eval $sql]
+set nmanindex [expr {$nindex-$nautoindex}]
+
+# set total_payload [mem eval "SELECT sum(payload) FROM space_used"]
+set user_payload [mem one {SELECT int(sum(payload)) FROM space_used
+ WHERE NOT is_index AND name NOT LIKE 'sqlite_master'}]
+set user_percent [percent $user_payload $file_bytes]
+
+# Output the summary statistics calculated above.
+#
+puts "/** Disk-Space Utilization Report For $root_filename"
+puts ""
+statline {Page size in bytes} $pageSize
+statline {Pages in the whole file (measured)} $file_pgcnt
+statline {Pages in the whole file (calculated)} $file_pgcnt2
+statline {Pages that store data} $inuse_pgcnt $inuse_percent
+statline {Pages on the freelist (per header)} $free_pgcnt2 $free_percent2
+statline {Pages on the freelist (calculated)} $free_pgcnt $free_percent
+statline {Pages of auto-vacuum overhead} $av_pgcnt $av_percent
+statline {Number of tables in the database} $ntable
+statline {Number of indices} $nindex
+statline {Number of defined indices} $nmanindex
+statline {Number of implied indices} $nautoindex
+if {$isCompressed} {
+ statline {Size of uncompressed content in bytes} $file_bytes
+ set efficiency [percent $true_file_size $file_bytes]
+ statline {Size of compressed file on disk} $true_file_size $efficiency
+} else {
+ statline {Size of the file in bytes} $file_bytes
+}
+statline {Bytes of user payload stored} $user_payload $user_percent
+
+# Output table rankings
+#
+puts ""
+titleline "Page counts for all tables with their indices"
+puts ""
+mem eval {SELECT tblname, count(*) AS cnt,
+ int(sum(int_pages+leaf_pages+ovfl_pages)) AS size
+ FROM space_used GROUP BY tblname ORDER BY size+0 DESC, tblname} {} {
+ statline [string toupper $tblname] $size [percent $size $file_pgcnt]
+}
+puts ""
+titleline "Page counts for all tables and indices separately"
+puts ""
+mem eval {
+ SELECT
+ upper(name) AS nm,
+ int(int_pages+leaf_pages+ovfl_pages) AS size
+ FROM space_used
+ ORDER BY size+0 DESC, name} {} {
+ statline $nm $size [percent $size $file_pgcnt]
+}
+if {$isCompressed} {
+ puts ""
+ titleline "Bytes of disk space used after compression"
+ puts ""
+ set csum 0
+ mem eval {SELECT tblname,
+ int(sum(compressed_size)) +
+ $compressOverhead*sum(int_pages+leaf_pages+ovfl_pages)
+ AS csize
+ FROM space_used GROUP BY tblname ORDER BY csize+0 DESC, tblname} {} {
+ incr csum $csize
+ statline [string toupper $tblname] $csize [percent $csize $true_file_size]
+ }
+ set overhead [expr {$true_file_size - $csum}]
+ if {$overhead>0} {
+ statline {Header and free space} $overhead [percent $overhead $true_file_size]
+ }
+}
+
+# Output subreports
+#
+if {$nindex>0} {
+ subreport {All tables and indices} 1 0
+}
+subreport {All tables} {NOT is_index} 0
+if {$nindex>0} {
+ subreport {All indices} {is_index} 0
+}
+foreach tbl [mem eval {SELECT DISTINCT tblname name FROM space_used
+ ORDER BY name}] {
+ set qn [quote $tbl]
+ set name [string toupper $tbl]
+ set n [mem eval {SELECT count(*) FROM space_used WHERE tblname=$tbl}]
+ if {$n>1} {
+ set idxlist [mem eval "SELECT name FROM space_used
+ WHERE tblname='$qn' AND is_index
+ ORDER BY 1"]
+ subreport "Table $name and all its indices" "tblname='$qn'" 0
+ subreport "Table $name w/o any indices" "name='$qn'" 1
+ if {[llength $idxlist]>1} {
+ subreport "Indices of table $name" "tblname='$qn' AND is_index" 0
+ }
+ foreach idx $idxlist {
+ set qidx [quote $idx]
+ subreport "Index [string toupper $idx] of table $name" "name='$qidx'" 1
+ }
+ } else {
+ subreport "Table $name" "name='$qn'" 1
+ }
+}
+
+# Output instructions on what the numbers above mean.
+#
+puts ""
+titleline Definitions
+puts {
+Page size in bytes
+
+ The number of bytes in a single page of the database file.
+ Usually 1024.
+
+Number of pages in the whole file
+}
+puts " The number of $pageSize-byte pages that go into forming the complete
+ database"
+puts {
+Pages that store data
+
+ The number of pages that store data, either as primary B*Tree pages or
+ as overflow pages. The number at the right is the data pages divided by
+ the total number of pages in the file.
+
+Pages on the freelist
+
+ The number of pages that are not currently in use but are reserved for
+ future use. The percentage at the right is the number of freelist pages
+ divided by the total number of pages in the file.
+
+Pages of auto-vacuum overhead
+
+ The number of pages that store data used by the database to facilitate
+ auto-vacuum. This is zero for databases that do not support auto-vacuum.
+
+Number of tables in the database
+
+ The number of tables in the database, including the SQLITE_MASTER table
+ used to store schema information.
+
+Number of indices
+
+ The total number of indices in the database.
+
+Number of defined indices
+
+ The number of indices created using an explicit CREATE INDEX statement.
+
+Number of implied indices
+
+ The number of indices used to implement PRIMARY KEY or UNIQUE constraints
+ on tables.
+
+Size of the file in bytes
+
+ The total amount of disk space used by the entire database files.
+
+Bytes of user payload stored
+
+ The total number of bytes of user payload stored in the database. The
+ schema information in the SQLITE_MASTER table is not counted when
+ computing this number. The percentage at the right shows the payload
+ divided by the total file size.
+
+Percentage of total database
+
+ The amount of the complete database file that is devoted to storing
+ information described by this category.
+
+Number of entries
+
+ The total number of B-Tree key/value pairs stored under this category.
+
+Bytes of storage consumed
+
+ The total amount of disk space required to store all B-Tree entries
+ under this category. The is the total number of pages used times
+ the pages size.
+
+Bytes of payload
+
+ The amount of payload stored under this category. Payload is the data
+ part of table entries and the key part of index entries. The percentage
+ at the right is the bytes of payload divided by the bytes of storage
+ consumed.
+
+Bytes of metadata
+
+ The amount of formatting and structural information stored in the
+ table or index. Metadata includes the btree page header, the cell pointer
+ array, the size field for each cell, the left child pointer or non-leaf
+ cells, the overflow pointers for overflow cells, and the rowid value for
+ rowid table cells. In other words, metadata is everything that is neither
+ unused space nor content. The record header in the payload is counted as
+ content, not metadata.
+
+Average payload per entry
+
+ The average amount of payload on each entry. This is just the bytes of
+ payload divided by the number of entries.
+
+Average unused bytes per entry
+
+ The average amount of free space remaining on all pages under this
+ category on a per-entry basis. This is the number of unused bytes on
+ all pages divided by the number of entries.
+
+Non-sequential pages
+
+ The number of pages in the table or index that are out of sequence.
+ Many filesystems are optimized for sequential file access so a small
+ number of non-sequential pages might result in faster queries,
+ especially for larger database files that do not fit in the disk cache.
+ Note that after running VACUUM, the root page of each table or index is
+ at the beginning of the database file and all other pages are in a
+ separate part of the database file, resulting in a single non-
+ sequential page.
+
+Maximum payload per entry
+
+ The largest payload size of any entry.
+
+Entries that use overflow
+
+ The number of entries that user one or more overflow pages.
+
+Total pages used
+
+ This is the number of pages used to hold all information in the current
+ category. This is the sum of index, primary, and overflow pages.
+
+Index pages used
+
+ This is the number of pages in a table B-tree that hold only key (rowid)
+ information and no data.
+
+Primary pages used
+
+ This is the number of B-tree pages that hold both key and data.
+
+Overflow pages used
+
+ The total number of overflow pages used for this category.
+
+Unused bytes on index pages
+
+ The total number of bytes of unused space on all index pages. The
+ percentage at the right is the number of unused bytes divided by the
+ total number of bytes on index pages.
+
+Unused bytes on primary pages
+
+ The total number of bytes of unused space on all primary pages. The
+ percentage at the right is the number of unused bytes divided by the
+ total number of bytes on primary pages.
+
+Unused bytes on overflow pages
+
+ The total number of bytes of unused space on all overflow pages. The
+ percentage at the right is the number of unused bytes divided by the
+ total number of bytes on overflow pages.
+
+Unused bytes on all pages
+
+ The total number of bytes of unused space on all primary and overflow
+ pages. The percentage at the right is the number of unused bytes
+ divided by the total number of bytes.
+}
+
+# Output a dump of the in-memory database. This can be used for more
+# complex offline analysis.
+#
+titleline {}
+puts "The entire text of this report can be sourced into any SQL database"
+puts "engine for further analysis. All of the text above is an SQL comment."
+puts "The data used to generate this report follows:"
+puts "*/"
+puts "BEGIN;"
+puts $tabledef
+unset -nocomplain x
+mem eval {SELECT * FROM space_used} x {
+ puts -nonewline "INSERT INTO space_used VALUES"
+ set sep (
+ foreach col $x(*) {
+ set v $x($col)
+ if {$v=="" || ![string is double $v]} {set v '[quote $v]'}
+ puts -nonewline $sep$v
+ set sep ,
+ }
+ puts ");"
+}
+puts "COMMIT;"
+
+} err]} {
+ puts "ERROR: $err"
+ puts $errorInfo
+ exit 1
+}
--- origsrc/sqlite-autoconf-3300000/spellfix.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/spellfix.c 2019-10-08 13:42:19.216952100 +0200
@@ -0,0 +1,3079 @@
+/*
+** 2012 April 10
+**
+** 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 module implements the spellfix1 VIRTUAL TABLE that can be used
+** to search a large vocabulary for close matches. See separate
+** documentation (http://www.sqlite.org/spellfix1.html) for details.
+*/
+#include <string.h>
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+
+#ifndef SQLITE_AMALGAMATION
+# if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
+# define NDEBUG 1
+# endif
+# if defined(NDEBUG) && defined(SQLITE_DEBUG)
+# undef NDEBUG
+# endif
+# include <stdio.h>
+# include <stdlib.h>
+# include <assert.h>
+# define ALWAYS(X) 1
+# define NEVER(X) 0
+ typedef unsigned char u8;
+ typedef unsigned short u16;
+#endif
+#include <ctype.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/*
+** Character classes for ASCII characters:
+**
+** 0 '' Silent letters: H W
+** 1 'A' Any vowel: A E I O U (Y)
+** 2 'B' A bilabeal stop or fricative: B F P V W
+** 3 'C' Other fricatives or back stops: C G J K Q S X Z
+** 4 'D' Alveolar stops: D T
+** 5 'H' Letter H at the beginning of a word
+** 6 'L' Glide: L
+** 7 'R' Semivowel: R
+** 8 'M' Nasals: M N
+** 9 'Y' Letter Y at the beginning of a word.
+** 10 '9' Digits: 0 1 2 3 4 5 6 7 8 9
+** 11 ' ' White space
+** 12 '?' Other.
+*/
+#define CCLASS_SILENT 0
+#define CCLASS_VOWEL 1
+#define CCLASS_B 2
+#define CCLASS_C 3
+#define CCLASS_D 4
+#define CCLASS_H 5
+#define CCLASS_L 6
+#define CCLASS_R 7
+#define CCLASS_M 8
+#define CCLASS_Y 9
+#define CCLASS_DIGIT 10
+#define CCLASS_SPACE 11
+#define CCLASS_OTHER 12
+
+/*
+** The following table gives the character class for non-initial ASCII
+** characters.
+*/
+static const unsigned char midClass[] = {
+ /* */ CCLASS_OTHER, /* */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+ /* */ CCLASS_OTHER, /* */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+ /* */ CCLASS_OTHER, /* */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+ /* */ CCLASS_SPACE, /* */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+ /* */ CCLASS_SPACE, /* */ CCLASS_SPACE, /* */ CCLASS_OTHER,
+ /* */ CCLASS_OTHER, /* */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+ /* */ CCLASS_OTHER, /* */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+ /* */ CCLASS_OTHER, /* */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+ /* */ CCLASS_OTHER, /* */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+ /* */ CCLASS_OTHER, /* */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+ /* */ CCLASS_OTHER, /* */ CCLASS_OTHER, /* */ CCLASS_SPACE,
+ /* ! */ CCLASS_OTHER, /* " */ CCLASS_OTHER, /* # */ CCLASS_OTHER,
+ /* $ */ CCLASS_OTHER, /* % */ CCLASS_OTHER, /* & */ CCLASS_OTHER,
+ /* ' */ CCLASS_SILENT, /* ( */ CCLASS_OTHER, /* ) */ CCLASS_OTHER,
+ /* * */ CCLASS_OTHER, /* + */ CCLASS_OTHER, /* , */ CCLASS_OTHER,
+ /* - */ CCLASS_OTHER, /* . */ CCLASS_OTHER, /* / */ CCLASS_OTHER,
+ /* 0 */ CCLASS_DIGIT, /* 1 */ CCLASS_DIGIT, /* 2 */ CCLASS_DIGIT,
+ /* 3 */ CCLASS_DIGIT, /* 4 */ CCLASS_DIGIT, /* 5 */ CCLASS_DIGIT,
+ /* 6 */ CCLASS_DIGIT, /* 7 */ CCLASS_DIGIT, /* 8 */ CCLASS_DIGIT,
+ /* 9 */ CCLASS_DIGIT, /* : */ CCLASS_OTHER, /* ; */ CCLASS_OTHER,
+ /* < */ CCLASS_OTHER, /* = */ CCLASS_OTHER, /* > */ CCLASS_OTHER,
+ /* ? */ CCLASS_OTHER, /* @ */ CCLASS_OTHER, /* A */ CCLASS_VOWEL,
+ /* B */ CCLASS_B, /* C */ CCLASS_C, /* D */ CCLASS_D,
+ /* E */ CCLASS_VOWEL, /* F */ CCLASS_B, /* G */ CCLASS_C,
+ /* H */ CCLASS_SILENT, /* I */ CCLASS_VOWEL, /* J */ CCLASS_C,
+ /* K */ CCLASS_C, /* L */ CCLASS_L, /* M */ CCLASS_M,
+ /* N */ CCLASS_M, /* O */ CCLASS_VOWEL, /* P */ CCLASS_B,
+ /* Q */ CCLASS_C, /* R */ CCLASS_R, /* S */ CCLASS_C,
+ /* T */ CCLASS_D, /* U */ CCLASS_VOWEL, /* V */ CCLASS_B,
+ /* W */ CCLASS_B, /* X */ CCLASS_C, /* Y */ CCLASS_VOWEL,
+ /* Z */ CCLASS_C, /* [ */ CCLASS_OTHER, /* \ */ CCLASS_OTHER,
+ /* ] */ CCLASS_OTHER, /* ^ */ CCLASS_OTHER, /* _ */ CCLASS_OTHER,
+ /* ` */ CCLASS_OTHER, /* a */ CCLASS_VOWEL, /* b */ CCLASS_B,
+ /* c */ CCLASS_C, /* d */ CCLASS_D, /* e */ CCLASS_VOWEL,
+ /* f */ CCLASS_B, /* g */ CCLASS_C, /* h */ CCLASS_SILENT,
+ /* i */ CCLASS_VOWEL, /* j */ CCLASS_C, /* k */ CCLASS_C,
+ /* l */ CCLASS_L, /* m */ CCLASS_M, /* n */ CCLASS_M,
+ /* o */ CCLASS_VOWEL, /* p */ CCLASS_B, /* q */ CCLASS_C,
+ /* r */ CCLASS_R, /* s */ CCLASS_C, /* t */ CCLASS_D,
+ /* u */ CCLASS_VOWEL, /* v */ CCLASS_B, /* w */ CCLASS_B,
+ /* x */ CCLASS_C, /* y */ CCLASS_VOWEL, /* z */ CCLASS_C,
+ /* { */ CCLASS_OTHER, /* | */ CCLASS_OTHER, /* } */ CCLASS_OTHER,
+ /* ~ */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+};
+/*
+** This tables gives the character class for ASCII characters that form the
+** initial character of a word. The only difference from midClass is with
+** the letters H, W, and Y.
+*/
+static const unsigned char initClass[] = {
+ /* */ CCLASS_OTHER, /* */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+ /* */ CCLASS_OTHER, /* */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+ /* */ CCLASS_OTHER, /* */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+ /* */ CCLASS_SPACE, /* */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+ /* */ CCLASS_SPACE, /* */ CCLASS_SPACE, /* */ CCLASS_OTHER,
+ /* */ CCLASS_OTHER, /* */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+ /* */ CCLASS_OTHER, /* */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+ /* */ CCLASS_OTHER, /* */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+ /* */ CCLASS_OTHER, /* */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+ /* */ CCLASS_OTHER, /* */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+ /* */ CCLASS_OTHER, /* */ CCLASS_OTHER, /* */ CCLASS_SPACE,
+ /* ! */ CCLASS_OTHER, /* " */ CCLASS_OTHER, /* # */ CCLASS_OTHER,
+ /* $ */ CCLASS_OTHER, /* % */ CCLASS_OTHER, /* & */ CCLASS_OTHER,
+ /* ' */ CCLASS_OTHER, /* ( */ CCLASS_OTHER, /* ) */ CCLASS_OTHER,
+ /* * */ CCLASS_OTHER, /* + */ CCLASS_OTHER, /* , */ CCLASS_OTHER,
+ /* - */ CCLASS_OTHER, /* . */ CCLASS_OTHER, /* / */ CCLASS_OTHER,
+ /* 0 */ CCLASS_DIGIT, /* 1 */ CCLASS_DIGIT, /* 2 */ CCLASS_DIGIT,
+ /* 3 */ CCLASS_DIGIT, /* 4 */ CCLASS_DIGIT, /* 5 */ CCLASS_DIGIT,
+ /* 6 */ CCLASS_DIGIT, /* 7 */ CCLASS_DIGIT, /* 8 */ CCLASS_DIGIT,
+ /* 9 */ CCLASS_DIGIT, /* : */ CCLASS_OTHER, /* ; */ CCLASS_OTHER,
+ /* < */ CCLASS_OTHER, /* = */ CCLASS_OTHER, /* > */ CCLASS_OTHER,
+ /* ? */ CCLASS_OTHER, /* @ */ CCLASS_OTHER, /* A */ CCLASS_VOWEL,
+ /* B */ CCLASS_B, /* C */ CCLASS_C, /* D */ CCLASS_D,
+ /* E */ CCLASS_VOWEL, /* F */ CCLASS_B, /* G */ CCLASS_C,
+ /* H */ CCLASS_SILENT, /* I */ CCLASS_VOWEL, /* J */ CCLASS_C,
+ /* K */ CCLASS_C, /* L */ CCLASS_L, /* M */ CCLASS_M,
+ /* N */ CCLASS_M, /* O */ CCLASS_VOWEL, /* P */ CCLASS_B,
+ /* Q */ CCLASS_C, /* R */ CCLASS_R, /* S */ CCLASS_C,
+ /* T */ CCLASS_D, /* U */ CCLASS_VOWEL, /* V */ CCLASS_B,
+ /* W */ CCLASS_B, /* X */ CCLASS_C, /* Y */ CCLASS_Y,
+ /* Z */ CCLASS_C, /* [ */ CCLASS_OTHER, /* \ */ CCLASS_OTHER,
+ /* ] */ CCLASS_OTHER, /* ^ */ CCLASS_OTHER, /* _ */ CCLASS_OTHER,
+ /* ` */ CCLASS_OTHER, /* a */ CCLASS_VOWEL, /* b */ CCLASS_B,
+ /* c */ CCLASS_C, /* d */ CCLASS_D, /* e */ CCLASS_VOWEL,
+ /* f */ CCLASS_B, /* g */ CCLASS_C, /* h */ CCLASS_SILENT,
+ /* i */ CCLASS_VOWEL, /* j */ CCLASS_C, /* k */ CCLASS_C,
+ /* l */ CCLASS_L, /* m */ CCLASS_M, /* n */ CCLASS_M,
+ /* o */ CCLASS_VOWEL, /* p */ CCLASS_B, /* q */ CCLASS_C,
+ /* r */ CCLASS_R, /* s */ CCLASS_C, /* t */ CCLASS_D,
+ /* u */ CCLASS_VOWEL, /* v */ CCLASS_B, /* w */ CCLASS_B,
+ /* x */ CCLASS_C, /* y */ CCLASS_Y, /* z */ CCLASS_C,
+ /* { */ CCLASS_OTHER, /* | */ CCLASS_OTHER, /* } */ CCLASS_OTHER,
+ /* ~ */ CCLASS_OTHER, /* */ CCLASS_OTHER,
+};
+
+/*
+** Mapping from the character class number (0-13) to a symbol for each
+** character class. Note that initClass[] can be used to map the class
+** symbol back into the class number.
+*/
+static const unsigned char className[] = ".ABCDHLRMY9 ?";
+
+/*
+** Generate a "phonetic hash" from a string of ASCII characters
+** in zIn[0..nIn-1].
+**
+** * Map characters by character class as defined above.
+** * Omit double-letters
+** * Omit vowels beside R and L
+** * Omit T when followed by CH
+** * Omit W when followed by R
+** * Omit D when followed by J or G
+** * Omit K in KN or G in GN at the beginning of a word
+**
+** Space to hold the result is obtained from sqlite3_malloc()
+**
+** Return NULL if memory allocation fails.
+*/
+static unsigned char *phoneticHash(const unsigned char *zIn, int nIn){
+ unsigned char *zOut = sqlite3_malloc( nIn + 1 );
+ int i;
+ int nOut = 0;
+ char cPrev = 0x77;
+ char cPrevX = 0x77;
+ const unsigned char *aClass = initClass;
+
+ if( zOut==0 ) return 0;
+ if( nIn>2 ){
+ switch( zIn[0] ){
+ case 'g':
+ case 'k': {
+ if( zIn[1]=='n' ){ zIn++; nIn--; }
+ break;
+ }
+ }
+ }
+ for(i=0; i<nIn; i++){
+ unsigned char c = zIn[i];
+ if( i+1<nIn ){
+ if( c=='w' && zIn[i+1]=='r' ) continue;
+ if( c=='d' && (zIn[i+1]=='j' || zIn[i+1]=='g') ) continue;
+ if( i+2<nIn ){
+ if( c=='t' && zIn[i+1]=='c' && zIn[i+2]=='h' ) continue;
+ }
+ }
+ c = aClass[c&0x7f];
+ if( c==CCLASS_SPACE ) continue;
+ if( c==CCLASS_OTHER && cPrev!=CCLASS_DIGIT ) continue;
+ aClass = midClass;
+ if( c==CCLASS_VOWEL && (cPrevX==CCLASS_R || cPrevX==CCLASS_L) ){
+ continue; /* No vowels beside L or R */
+ }
+ if( (c==CCLASS_R || c==CCLASS_L) && cPrevX==CCLASS_VOWEL ){
+ nOut--; /* No vowels beside L or R */
+ }
+ cPrev = c;
+ if( c==CCLASS_SILENT ) continue;
+ cPrevX = c;
+ c = className[c];
+ assert( nOut>=0 );
+ if( nOut==0 || c!=zOut[nOut-1] ) zOut[nOut++] = c;
+ }
+ zOut[nOut] = 0;
+ return zOut;
+}
+
+/*
+** This is an SQL function wrapper around phoneticHash(). See
+** the description of phoneticHash() for additional information.
+*/
+static void phoneticHashSqlFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const unsigned char *zIn;
+ unsigned char *zOut;
+
+ zIn = sqlite3_value_text(argv[0]);
+ if( zIn==0 ) return;
+ zOut = phoneticHash(zIn, sqlite3_value_bytes(argv[0]));
+ if( zOut==0 ){
+ sqlite3_result_error_nomem(context);
+ }else{
+ sqlite3_result_text(context, (char*)zOut, -1, sqlite3_free);
+ }
+}
+
+/*
+** Return the character class number for a character given its
+** context.
+*/
+static char characterClass(char cPrev, char c){
+ return cPrev==0 ? initClass[c&0x7f] : midClass[c&0x7f];
+}
+
+/*
+** Return the cost of inserting or deleting character c immediately
+** following character cPrev. If cPrev==0, that means c is the first
+** character of the word.
+*/
+static int insertOrDeleteCost(char cPrev, char c, char cNext){
+ char classC = characterClass(cPrev, c);
+ char classCprev;
+
+ if( classC==CCLASS_SILENT ){
+ /* Insert or delete "silent" characters such as H or W */
+ return 1;
+ }
+ if( cPrev==c ){
+ /* Repeated characters, or miss a repeat */
+ return 10;
+ }
+ if( classC==CCLASS_VOWEL && (cPrev=='r' || cNext=='r') ){
+ return 20; /* Insert a vowel before or after 'r' */
+ }
+ classCprev = characterClass(cPrev, cPrev);
+ if( classC==classCprev ){
+ if( classC==CCLASS_VOWEL ){
+ /* Remove or add a new vowel to a vowel cluster */
+ return 15;
+ }else{
+ /* Remove or add a consonant not in the same class */
+ return 50;
+ }
+ }
+
+ /* any other character insertion or deletion */
+ return 100;
+}
+
+/*
+** Divide the insertion cost by this factor when appending to the
+** end of the word.
+*/
+#define FINAL_INS_COST_DIV 4
+
+/*
+** Return the cost of substituting cTo in place of cFrom assuming
+** the previous character is cPrev. If cPrev==0 then cTo is the first
+** character of the word.
+*/
+static int substituteCost(char cPrev, char cFrom, char cTo){
+ char classFrom, classTo;
+ if( cFrom==cTo ){
+ /* Exact match */
+ return 0;
+ }
+ if( cFrom==(cTo^0x20) && ((cTo>='A' && cTo<='Z') || (cTo>='a' && cTo<='z')) ){
+ /* differ only in case */
+ return 0;
+ }
+ classFrom = characterClass(cPrev, cFrom);
+ classTo = characterClass(cPrev, cTo);
+ if( classFrom==classTo ){
+ /* Same character class */
+ return 40;
+ }
+ if( classFrom>=CCLASS_B && classFrom<=CCLASS_Y
+ && classTo>=CCLASS_B && classTo<=CCLASS_Y ){
+ /* Convert from one consonant to another, but in a different class */
+ return 75;
+ }
+ /* Any other subsitution */
+ return 100;
+}
+
+/*
+** Given two strings zA and zB which are pure ASCII, return the cost
+** of transforming zA into zB. If zA ends with '*' assume that it is
+** a prefix of zB and give only minimal penalty for extra characters
+** on the end of zB.
+**
+** Smaller numbers mean a closer match.
+**
+** Negative values indicate an error:
+** -1 One of the inputs is NULL
+** -2 Non-ASCII characters on input
+** -3 Unable to allocate memory
+**
+** If pnMatch is not NULL, then *pnMatch is set to the number of bytes
+** of zB that matched the pattern in zA. If zA does not end with a '*',
+** then this value is always the number of bytes in zB (i.e. strlen(zB)).
+** If zA does end in a '*', then it is the number of bytes in the prefix
+** of zB that was deemed to match zA.
+*/
+static int editdist1(const char *zA, const char *zB, int *pnMatch){
+ int nA, nB; /* Number of characters in zA[] and zB[] */
+ int xA, xB; /* Loop counters for zA[] and zB[] */
+ char cA = 0, cB; /* Current character of zA and zB */
+ char cAprev, cBprev; /* Previous character of zA and zB */
+ char cAnext, cBnext; /* Next character in zA and zB */
+ int d; /* North-west cost value */
+ int dc = 0; /* North-west character value */
+ int res; /* Final result */
+ int *m; /* The cost matrix */
+ char *cx; /* Corresponding character values */
+ int *toFree = 0; /* Malloced space */
+ int nMatch = 0;
+ int mStack[60+15]; /* Stack space to use if not too much is needed */
+
+ /* Early out if either input is NULL */
+ if( zA==0 || zB==0 ) return -1;
+
+ /* Skip any common prefix */
+ while( zA[0] && zA[0]==zB[0] ){ dc = zA[0]; zA++; zB++; nMatch++; }
+ if( pnMatch ) *pnMatch = nMatch;
+ if( zA[0]==0 && zB[0]==0 ) return 0;
+
+#if 0
+ printf("A=\"%s\" B=\"%s\" dc=%c\n", zA, zB, dc?dc:' ');
+#endif
+
+ /* Verify input strings and measure their lengths */
+ for(nA=0; zA[nA]; nA++){
+ if( zA[nA]&0x80 ) return -2;
+ }
+ for(nB=0; zB[nB]; nB++){
+ if( zB[nB]&0x80 ) return -2;
+ }
+
+ /* Special processing if either string is empty */
+ if( nA==0 ){
+ cBprev = (char)dc;
+ for(xB=res=0; (cB = zB[xB])!=0; xB++){
+ res += insertOrDeleteCost(cBprev, cB, zB[xB+1])/FINAL_INS_COST_DIV;
+ cBprev = cB;
+ }
+ return res;
+ }
+ if( nB==0 ){
+ cAprev = (char)dc;
+ for(xA=res=0; (cA = zA[xA])!=0; xA++){
+ res += insertOrDeleteCost(cAprev, cA, zA[xA+1]);
+ cAprev = cA;
+ }
+ return res;
+ }
+
+ /* A is a prefix of B */
+ if( zA[0]=='*' && zA[1]==0 ) return 0;
+
+ /* Allocate and initialize the Wagner matrix */
+ if( nB<(sizeof(mStack)*4)/(sizeof(mStack[0])*5) ){
+ m = mStack;
+ }else{
+ m = toFree = sqlite3_malloc( (nB+1)*5*sizeof(m[0])/4 );
+ if( m==0 ) return -3;
+ }
+ cx = (char*)&m[nB+1];
+
+ /* Compute the Wagner edit distance */
+ m[0] = 0;
+ cx[0] = (char)dc;
+ cBprev = (char)dc;
+ for(xB=1; xB<=nB; xB++){
+ cBnext = zB[xB];
+ cB = zB[xB-1];
+ cx[xB] = cB;
+ m[xB] = m[xB-1] + insertOrDeleteCost(cBprev, cB, cBnext);
+ cBprev = cB;
+ }
+ cAprev = (char)dc;
+ for(xA=1; xA<=nA; xA++){
+ int lastA = (xA==nA);
+ cA = zA[xA-1];
+ cAnext = zA[xA];
+ if( cA=='*' && lastA ) break;
+ d = m[0];
+ dc = cx[0];
+ m[0] = d + insertOrDeleteCost(cAprev, cA, cAnext);
+ cBprev = 0;
+ for(xB=1; xB<=nB; xB++){
+ int totalCost, insCost, delCost, subCost, ncx;
+ cB = zB[xB-1];
+ cBnext = zB[xB];
+
+ /* Cost to insert cB */
+ insCost = insertOrDeleteCost(cx[xB-1], cB, cBnext);
+ if( lastA ) insCost /= FINAL_INS_COST_DIV;
+
+ /* Cost to delete cA */
+ delCost = insertOrDeleteCost(cx[xB], cA, cBnext);
+
+ /* Cost to substitute cA->cB */
+ subCost = substituteCost(cx[xB-1], cA, cB);
+
+ /* Best cost */
+ totalCost = insCost + m[xB-1];
+ ncx = cB;
+ if( (delCost + m[xB])<totalCost ){
+ totalCost = delCost + m[xB];
+ ncx = cA;
+ }
+ if( (subCost + d)<totalCost ){
+ totalCost = subCost + d;
+ }
+
+#if 0
+ printf("%d,%d d=%4d u=%4d r=%4d dc=%c cA=%c cB=%c"
+ " ins=%4d del=%4d sub=%4d t=%4d ncx=%c\n",
+ xA, xB, d, m[xB], m[xB-1], dc?dc:' ', cA, cB,
+ insCost, delCost, subCost, totalCost, ncx?ncx:' ');
+#endif
+
+ /* Update the matrix */
+ d = m[xB];
+ dc = cx[xB];
+ m[xB] = totalCost;
+ cx[xB] = (char)ncx;
+ cBprev = cB;
+ }
+ cAprev = cA;
+ }
+
+ /* Free the wagner matrix and return the result */
+ if( cA=='*' ){
+ res = m[1];
+ for(xB=1; xB<=nB; xB++){
+ if( m[xB]<res ){
+ res = m[xB];
+ if( pnMatch ) *pnMatch = xB+nMatch;
+ }
+ }
+ }else{
+ res = m[nB];
+ /* In the current implementation, pnMatch is always NULL if zA does
+ ** not end in "*" */
+ assert( pnMatch==0 );
+ }
+ sqlite3_free(toFree);
+ return res;
+}
+
+/*
+** Function: editdist(A,B)
+**
+** Return the cost of transforming string A into string B. Both strings
+** must be pure ASCII text. If A ends with '*' then it is assumed to be
+** a prefix of B and extra characters on the end of B have minimal additional
+** cost.
+*/
+static void editdistSqlFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ int res = editdist1(
+ (const char*)sqlite3_value_text(argv[0]),
+ (const char*)sqlite3_value_text(argv[1]),
+ 0);
+ if( res<0 ){
+ if( res==(-3) ){
+ sqlite3_result_error_nomem(context);
+ }else if( res==(-2) ){
+ sqlite3_result_error(context, "non-ASCII input to editdist()", -1);
+ }else{
+ sqlite3_result_error(context, "NULL input to editdist()", -1);
+ }
+ }else{
+ sqlite3_result_int(context, res);
+ }
+}
+
+/* End of the fixed-cost edit distance implementation
+******************************************************************************
+*****************************************************************************
+** Begin: Configurable cost unicode edit distance routines
+*/
+/* Forward declaration of structures */
+typedef struct EditDist3Cost EditDist3Cost;
+typedef struct EditDist3Config EditDist3Config;
+typedef struct EditDist3Point EditDist3Point;
+typedef struct EditDist3From EditDist3From;
+typedef struct EditDist3FromString EditDist3FromString;
+typedef struct EditDist3To EditDist3To;
+typedef struct EditDist3ToString EditDist3ToString;
+typedef struct EditDist3Lang EditDist3Lang;
+
+
+/*
+** An entry in the edit cost table
+*/
+struct EditDist3Cost {
+ EditDist3Cost *pNext; /* Next cost element */
+ u8 nFrom; /* Number of bytes in aFrom */
+ u8 nTo; /* Number of bytes in aTo */
+ u16 iCost; /* Cost of this transformation */
+ char a[4] ; /* FROM string followed by TO string */
+ /* Additional TO and FROM string bytes appended as necessary */
+};
+
+/*
+** Edit costs for a particular language ID
+*/
+struct EditDist3Lang {
+ int iLang; /* Language ID */
+ int iInsCost; /* Default insertion cost */
+ int iDelCost; /* Default deletion cost */
+ int iSubCost; /* Default substitution cost */
+ EditDist3Cost *pCost; /* Costs */
+};
+
+
+/*
+** The default EditDist3Lang object, with default costs.
+*/
+static const EditDist3Lang editDist3Lang = { 0, 100, 100, 150, 0 };
+
+/*
+** Complete configuration
+*/
+struct EditDist3Config {
+ int nLang; /* Number of language IDs. Size of a[] */
+ EditDist3Lang *a; /* One for each distinct language ID */
+};
+
+/*
+** Extra information about each character in the FROM string.
+*/
+struct EditDist3From {
+ int nSubst; /* Number of substitution cost entries */
+ int nDel; /* Number of deletion cost entries */
+ int nByte; /* Number of bytes in this character */
+ EditDist3Cost **apSubst; /* Array of substitution costs for this element */
+ EditDist3Cost **apDel; /* Array of deletion cost entries */
+};
+
+/*
+** A precompiled FROM string.
+*
+** In the common case we expect the FROM string to be reused multiple times.
+** In other words, the common case will be to measure the edit distance
+** from a single origin string to multiple target strings.
+*/
+struct EditDist3FromString {
+ char *z; /* The complete text of the FROM string */
+ int n; /* Number of characters in the FROM string */
+ int isPrefix; /* True if ends with '*' character */
+ EditDist3From *a; /* Extra info about each char of the FROM string */
+};
+
+/*
+** Extra information about each character in the TO string.
+*/
+struct EditDist3To {
+ int nIns; /* Number of insertion cost entries */
+ int nByte; /* Number of bytes in this character */
+ EditDist3Cost **apIns; /* Array of deletion cost entries */
+};
+
+/*
+** A precompiled FROM string
+*/
+struct EditDist3ToString {
+ char *z; /* The complete text of the TO string */
+ int n; /* Number of characters in the TO string */
+ EditDist3To *a; /* Extra info about each char of the TO string */
+};
+
+/*
+** Clear or delete an instance of the object that records all edit-distance
+** weights.
+*/
+static void editDist3ConfigClear(EditDist3Config *p){
+ int i;
+ if( p==0 ) return;
+ for(i=0; i<p->nLang; i++){
+ EditDist3Cost *pCost, *pNext;
+ pCost = p->a[i].pCost;
+ while( pCost ){
+ pNext = pCost->pNext;
+ sqlite3_free(pCost);
+ pCost = pNext;
+ }
+ }
+ sqlite3_free(p->a);
+ memset(p, 0, sizeof(*p));
+}
+static void editDist3ConfigDelete(void *pIn){
+ EditDist3Config *p = (EditDist3Config*)pIn;
+ editDist3ConfigClear(p);
+ sqlite3_free(p);
+}
+
+/* Compare the FROM values of two EditDist3Cost objects, for sorting.
+** Return negative, zero, or positive if the A is less than, equal to,
+** or greater than B.
+*/
+static int editDist3CostCompare(EditDist3Cost *pA, EditDist3Cost *pB){
+ int n = pA->nFrom;
+ int rc;
+ if( n>pB->nFrom ) n = pB->nFrom;
+ rc = strncmp(pA->a, pB->a, n);
+ if( rc==0 ) rc = pA->nFrom - pB->nFrom;
+ return rc;
+}
+
+/*
+** Merge together two sorted lists of EditDist3Cost objects, in order
+** of increasing FROM.
+*/
+static EditDist3Cost *editDist3CostMerge(
+ EditDist3Cost *pA,
+ EditDist3Cost *pB
+){
+ EditDist3Cost *pHead = 0;
+ EditDist3Cost **ppTail = &pHead;
+ EditDist3Cost *p;
+ while( pA && pB ){
+ if( editDist3CostCompare(pA,pB)<=0 ){
+ p = pA;
+ pA = pA->pNext;
+ }else{
+ p = pB;
+ pB = pB->pNext;
+ }
+ *ppTail = p;
+ ppTail = &p->pNext;
+ }
+ if( pA ){
+ *ppTail = pA;
+ }else{
+ *ppTail = pB;
+ }
+ return pHead;
+}
+
+/*
+** Sort a list of EditDist3Cost objects into order of increasing FROM
+*/
+static EditDist3Cost *editDist3CostSort(EditDist3Cost *pList){
+ EditDist3Cost *ap[60], *p;
+ int i;
+ int mx = 0;
+ ap[0] = 0;
+ ap[1] = 0;
+ while( pList ){
+ p = pList;
+ pList = p->pNext;
+ p->pNext = 0;
+ for(i=0; ap[i]; i++){
+ p = editDist3CostMerge(ap[i],p);
+ ap[i] = 0;
+ }
+ ap[i] = p;
+ if( i>mx ){
+ mx = i;
+ ap[i+1] = 0;
+ }
+ }
+ p = 0;
+ for(i=0; i<=mx; i++){
+ if( ap[i] ) p = editDist3CostMerge(p,ap[i]);
+ }
+ return p;
+}
+
+/*
+** Load all edit-distance weights from a table.
+*/
+static int editDist3ConfigLoad(
+ EditDist3Config *p, /* The edit distance configuration to load */
+ sqlite3 *db, /* Load from this database */
+ const char *zTable /* Name of the table from which to load */
+){
+ sqlite3_stmt *pStmt;
+ int rc, rc2;
+ char *zSql;
+ int iLangPrev = -9999;
+ EditDist3Lang *pLang = 0;
+
+ zSql = sqlite3_mprintf("SELECT iLang, cFrom, cTo, iCost"
+ " FROM \"%w\" WHERE iLang>=0 ORDER BY iLang", zTable);
+ if( zSql==0 ) return SQLITE_NOMEM;
+ rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ if( rc ) return rc;
+ editDist3ConfigClear(p);
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ int iLang = sqlite3_column_int(pStmt, 0);
+ const char *zFrom = (const char*)sqlite3_column_text(pStmt, 1);
+ int nFrom = zFrom ? sqlite3_column_bytes(pStmt, 1) : 0;
+ const char *zTo = (const char*)sqlite3_column_text(pStmt, 2);
+ int nTo = zTo ? sqlite3_column_bytes(pStmt, 2) : 0;
+ int iCost = sqlite3_column_int(pStmt, 3);
+
+ assert( zFrom!=0 || nFrom==0 );
+ assert( zTo!=0 || nTo==0 );
+ if( nFrom>100 || nTo>100 ) continue;
+ if( iCost<0 ) continue;
+ if( iCost>=10000 ) continue; /* Costs above 10K are considered infinite */
+ if( pLang==0 || iLang!=iLangPrev ){
+ EditDist3Lang *pNew;
+ pNew = sqlite3_realloc(p->a, (p->nLang+1)*sizeof(p->a[0]));
+ if( pNew==0 ){ rc = SQLITE_NOMEM; break; }
+ p->a = pNew;
+ pLang = &p->a[p->nLang];
+ p->nLang++;
+ pLang->iLang = iLang;
+ pLang->iInsCost = 100;
+ pLang->iDelCost = 100;
+ pLang->iSubCost = 150;
+ pLang->pCost = 0;
+ iLangPrev = iLang;
+ }
+ if( nFrom==1 && zFrom[0]=='?' && nTo==0 ){
+ pLang->iDelCost = iCost;
+ }else if( nFrom==0 && nTo==1 && zTo[0]=='?' ){
+ pLang->iInsCost = iCost;
+ }else if( nFrom==1 && nTo==1 && zFrom[0]=='?' && zTo[0]=='?' ){
+ pLang->iSubCost = iCost;
+ }else{
+ EditDist3Cost *pCost;
+ int nExtra = nFrom + nTo - 4;
+ if( nExtra<0 ) nExtra = 0;
+ pCost = sqlite3_malloc( sizeof(*pCost) + nExtra );
+ if( pCost==0 ){ rc = SQLITE_NOMEM; break; }
+ pCost->nFrom = (u8)nFrom;
+ pCost->nTo = (u8)nTo;
+ pCost->iCost = (u16)iCost;
+ memcpy(pCost->a, zFrom, nFrom);
+ memcpy(pCost->a + nFrom, zTo, nTo);
+ pCost->pNext = pLang->pCost;
+ pLang->pCost = pCost;
+ }
+ }
+ rc2 = sqlite3_finalize(pStmt);
+ if( rc==SQLITE_OK ) rc = rc2;
+ if( rc==SQLITE_OK ){
+ int iLang;
+ for(iLang=0; iLang<p->nLang; iLang++){
+ p->a[iLang].pCost = editDist3CostSort(p->a[iLang].pCost);
+ }
+ }
+ return rc;
+}
+
+/*
+** Return the length (in bytes) of a utf-8 character. Or return a maximum
+** of N.
+*/
+static int utf8Len(unsigned char c, int N){
+ int len = 1;
+ if( c>0x7f ){
+ if( (c&0xe0)==0xc0 ){
+ len = 2;
+ }else if( (c&0xf0)==0xe0 ){
+ len = 3;
+ }else{
+ len = 4;
+ }
+ }
+ if( len>N ) len = N;
+ return len;
+}
+
+/*
+** Return TRUE (non-zero) if the To side of the given cost matches
+** the given string.
+*/
+static int matchTo(EditDist3Cost *p, const char *z, int n){
+ assert( n>0 );
+ if( p->a[p->nFrom]!=z[0] ) return 0;
+ if( p->nTo>n ) return 0;
+ if( strncmp(p->a+p->nFrom, z, p->nTo)!=0 ) return 0;
+ return 1;
+}
+
+/*
+** Return TRUE (non-zero) if the From side of the given cost matches
+** the given string.
+*/
+static int matchFrom(EditDist3Cost *p, const char *z, int n){
+ assert( p->nFrom<=n );
+ if( p->nFrom ){
+ if( p->a[0]!=z[0] ) return 0;
+ if( strncmp(p->a, z, p->nFrom)!=0 ) return 0;
+ }
+ return 1;
+}
+
+/*
+** Return TRUE (non-zero) of the next FROM character and the next TO
+** character are the same.
+*/
+static int matchFromTo(
+ EditDist3FromString *pStr, /* Left hand string */
+ int n1, /* Index of comparison character on the left */
+ const char *z2, /* Right-handl comparison character */
+ int n2 /* Bytes remaining in z2[] */
+){
+ int b1 = pStr->a[n1].nByte;
+ if( b1>n2 ) return 0;
+ assert( b1>0 );
+ if( pStr->z[n1]!=z2[0] ) return 0;
+ if( strncmp(pStr->z+n1, z2, b1)!=0 ) return 0;
+ return 1;
+}
+
+/*
+** Delete an EditDist3FromString objecct
+*/
+static void editDist3FromStringDelete(EditDist3FromString *p){
+ int i;
+ if( p ){
+ for(i=0; i<p->n; i++){
+ sqlite3_free(p->a[i].apDel);
+ sqlite3_free(p->a[i].apSubst);
+ }
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Create a EditDist3FromString object.
+*/
+static EditDist3FromString *editDist3FromStringNew(
+ const EditDist3Lang *pLang,
+ const char *z,
+ int n
+){
+ EditDist3FromString *pStr;
+ EditDist3Cost *p;
+ int i;
+
+ if( z==0 ) return 0;
+ if( n<0 ) n = (int)strlen(z);
+ pStr = sqlite3_malloc( sizeof(*pStr) + sizeof(pStr->a[0])*n + n + 1 );
+ if( pStr==0 ) return 0;
+ pStr->a = (EditDist3From*)&pStr[1];
+ memset(pStr->a, 0, sizeof(pStr->a[0])*n);
+ pStr->n = n;
+ pStr->z = (char*)&pStr->a[n];
+ memcpy(pStr->z, z, n+1);
+ if( n && z[n-1]=='*' ){
+ pStr->isPrefix = 1;
+ n--;
+ pStr->n--;
+ pStr->z[n] = 0;
+ }else{
+ pStr->isPrefix = 0;
+ }
+
+ for(i=0; i<n; i++){
+ EditDist3From *pFrom = &pStr->a[i];
+ memset(pFrom, 0, sizeof(*pFrom));
+ pFrom->nByte = utf8Len((unsigned char)z[i], n-i);
+ for(p=pLang->pCost; p; p=p->pNext){
+ EditDist3Cost **apNew;
+ if( i+p->nFrom>n ) continue;
+ if( matchFrom(p, z+i, n-i)==0 ) continue;
+ if( p->nTo==0 ){
+ apNew = sqlite3_realloc(pFrom->apDel,
+ sizeof(*apNew)*(pFrom->nDel+1));
+ if( apNew==0 ) break;
+ pFrom->apDel = apNew;
+ apNew[pFrom->nDel++] = p;
+ }else{
+ apNew = sqlite3_realloc(pFrom->apSubst,
+ sizeof(*apNew)*(pFrom->nSubst+1));
+ if( apNew==0 ) break;
+ pFrom->apSubst = apNew;
+ apNew[pFrom->nSubst++] = p;
+ }
+ }
+ if( p ){
+ editDist3FromStringDelete(pStr);
+ pStr = 0;
+ break;
+ }
+ }
+ return pStr;
+}
+
+/*
+** Update entry m[i] such that it is the minimum of its current value
+** and m[j]+iCost.
+*/
+static void updateCost(
+ unsigned int *m,
+ int i,
+ int j,
+ int iCost
+){
+ unsigned int b;
+ assert( iCost>=0 );
+ assert( iCost<10000 );
+ b = m[j] + iCost;
+ if( b<m[i] ) m[i] = b;
+}
+
+/*
+** How much stack space (int bytes) to use for Wagner matrix in
+** editDist3Core(). If more space than this is required, the entire
+** matrix is taken from the heap. To reduce the load on the memory
+** allocator, make this value as large as practical for the
+** architecture in use.
+*/
+#ifndef SQLITE_SPELLFIX_STACKALLOC_SZ
+# define SQLITE_SPELLFIX_STACKALLOC_SZ (1024)
+#endif
+
+/* Compute the edit distance between two strings.
+**
+** If an error occurs, return a negative number which is the error code.
+**
+** If pnMatch is not NULL, then *pnMatch is set to the number of characters
+** (not bytes) in z2 that matched the search pattern in *pFrom. If pFrom does
+** not contain the pattern for a prefix-search, then this is always the number
+** of characters in z2. If pFrom does contain a prefix search pattern, then
+** it is the number of characters in the prefix of z2 that was deemed to
+** match pFrom.
+*/
+static int editDist3Core(
+ EditDist3FromString *pFrom, /* The FROM string */
+ const char *z2, /* The TO string */
+ int n2, /* Length of the TO string */
+ const EditDist3Lang *pLang, /* Edit weights for a particular language ID */
+ int *pnMatch /* OUT: Characters in matched prefix */
+){
+ int k, n;
+ int i1, b1;
+ int i2, b2;
+ EditDist3FromString f = *pFrom;
+ EditDist3To *a2;
+ unsigned int *m;
+ unsigned int *pToFree;
+ int szRow;
+ EditDist3Cost *p;
+ int res;
+ sqlite3_uint64 nByte;
+ unsigned int stackSpace[SQLITE_SPELLFIX_STACKALLOC_SZ/sizeof(unsigned int)];
+
+ /* allocate the Wagner matrix and the aTo[] array for the TO string */
+ n = (f.n+1)*(n2+1);
+ n = (n+1)&~1;
+ nByte = n*sizeof(m[0]) + sizeof(a2[0])*n2;
+ if( nByte<=sizeof(stackSpace) ){
+ m = stackSpace;
+ pToFree = 0;
+ }else{
+ m = pToFree = sqlite3_malloc( nByte );
+ if( m==0 ) return -1; /* Out of memory */
+ }
+ a2 = (EditDist3To*)&m[n];
+ memset(a2, 0, sizeof(a2[0])*n2);
+
+ /* Fill in the a1[] matrix for all characters of the TO string */
+ for(i2=0; i2<n2; i2++){
+ a2[i2].nByte = utf8Len((unsigned char)z2[i2], n2-i2);
+ for(p=pLang->pCost; p; p=p->pNext){
+ EditDist3Cost **apNew;
+ if( p->nFrom>0 ) break;
+ if( i2+p->nTo>n2 ) continue;
+ if( p->a[0]>z2[i2] ) break;
+ if( matchTo(p, z2+i2, n2-i2)==0 ) continue;
+ a2[i2].nIns++;
+ apNew = sqlite3_realloc(a2[i2].apIns, sizeof(*apNew)*a2[i2].nIns);
+ if( apNew==0 ){
+ res = -1; /* Out of memory */
+ goto editDist3Abort;
+ }
+ a2[i2].apIns = apNew;
+ a2[i2].apIns[a2[i2].nIns-1] = p;
+ }
+ }
+
+ /* Prepare to compute the minimum edit distance */
+ szRow = f.n+1;
+ memset(m, 0x01, (n2+1)*szRow*sizeof(m[0]));
+ m[0] = 0;
+
+ /* First fill in the top-row of the matrix with FROM deletion costs */
+ for(i1=0; i1<f.n; i1 += b1){
+ b1 = f.a[i1].nByte;
+ updateCost(m, i1+b1, i1, pLang->iDelCost);
+ for(k=0; k<f.a[i1].nDel; k++){
+ p = f.a[i1].apDel[k];
+ updateCost(m, i1+p->nFrom, i1, p->iCost);
+ }
+ }
+
+ /* Fill in all subsequent rows, top-to-bottom, left-to-right */
+ for(i2=0; i2<n2; i2 += b2){
+ int rx; /* Starting index for current row */
+ int rxp; /* Starting index for previous row */
+ b2 = a2[i2].nByte;
+ rx = szRow*(i2+b2);
+ rxp = szRow*i2;
+ updateCost(m, rx, rxp, pLang->iInsCost);
+ for(k=0; k<a2[i2].nIns; k++){
+ p = a2[i2].apIns[k];
+ updateCost(m, szRow*(i2+p->nTo), rxp, p->iCost);
+ }
+ for(i1=0; i1<f.n; i1+=b1){
+ int cx; /* Index of current cell */
+ int cxp; /* Index of cell immediately to the left */
+ int cxd; /* Index of cell to the left and one row above */
+ int cxu; /* Index of cell immediately above */
+ b1 = f.a[i1].nByte;
+ cxp = rx + i1;
+ cx = cxp + b1;
+ cxd = rxp + i1;
+ cxu = cxd + b1;
+ updateCost(m, cx, cxp, pLang->iDelCost);
+ for(k=0; k<f.a[i1].nDel; k++){
+ p = f.a[i1].apDel[k];
+ updateCost(m, cxp+p->nFrom, cxp, p->iCost);
+ }
+ updateCost(m, cx, cxu, pLang->iInsCost);
+ if( matchFromTo(&f, i1, z2+i2, n2-i2) ){
+ updateCost(m, cx, cxd, 0);
+ }
+ updateCost(m, cx, cxd, pLang->iSubCost);
+ for(k=0; k<f.a[i1].nSubst; k++){
+ p = f.a[i1].apSubst[k];
+ if( matchTo(p, z2+i2, n2-i2) ){
+ updateCost(m, cxd+p->nFrom+szRow*p->nTo, cxd, p->iCost);
+ }
+ }
+ }
+ }
+
+#if 0 /* Enable for debugging */
+ printf(" ^");
+ for(i1=0; i1<f.n; i1++) printf(" %c-%2x", f.z[i1], f.z[i1]&0xff);
+ printf("\n ^:");
+ for(i1=0; i1<szRow; i1++){
+ int v = m[i1];
+ if( v>9999 ) printf(" ****");
+ else printf(" %4d", v);
+ }
+ printf("\n");
+ for(i2=0; i2<n2; i2++){
+ printf("%c-%02x:", z2[i2], z2[i2]&0xff);
+ for(i1=0; i1<szRow; i1++){
+ int v = m[(i2+1)*szRow+i1];
+ if( v>9999 ) printf(" ****");
+ else printf(" %4d", v);
+ }
+ printf("\n");
+ }
+#endif
+
+ /* Free memory allocations and return the result */
+ res = (int)m[szRow*(n2+1)-1];
+ n = n2;
+ if( f.isPrefix ){
+ for(i2=1; i2<=n2; i2++){
+ int b = m[szRow*i2-1];
+ if( b<=res ){
+ res = b;
+ n = i2 - 1;
+ }
+ }
+ }
+ if( pnMatch ){
+ int nExtra = 0;
+ for(k=0; k<n; k++){
+ if( (z2[k] & 0xc0)==0x80 ) nExtra++;
+ }
+ *pnMatch = n - nExtra;
+ }
+
+editDist3Abort:
+ for(i2=0; i2<n2; i2++) sqlite3_free(a2[i2].apIns);
+ sqlite3_free(pToFree);
+ return res;
+}
+
+/*
+** Get an appropriate EditDist3Lang object.
+*/
+static const EditDist3Lang *editDist3FindLang(
+ EditDist3Config *pConfig,
+ int iLang
+){
+ int i;
+ for(i=0; i<pConfig->nLang; i++){
+ if( pConfig->a[i].iLang==iLang ) return &pConfig->a[i];
+ }
+ return &editDist3Lang;
+}
+
+/*
+** Function: editdist3(A,B,iLang)
+** editdist3(tablename)
+**
+** Return the cost of transforming string A into string B using edit
+** weights for iLang.
+**
+** The second form loads edit weights into memory from a table.
+*/
+static void editDist3SqlFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ EditDist3Config *pConfig = (EditDist3Config*)sqlite3_user_data(context);
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ int rc;
+ if( argc==1 ){
+ const char *zTable = (const char*)sqlite3_value_text(argv[0]);
+ rc = editDist3ConfigLoad(pConfig, db, zTable);
+ if( rc ) sqlite3_result_error_code(context, rc);
+ }else{
+ const char *zA = (const char*)sqlite3_value_text(argv[0]);
+ const char *zB = (const char*)sqlite3_value_text(argv[1]);
+ int nA = sqlite3_value_bytes(argv[0]);
+ int nB = sqlite3_value_bytes(argv[1]);
+ int iLang = argc==3 ? sqlite3_value_int(argv[2]) : 0;
+ const EditDist3Lang *pLang = editDist3FindLang(pConfig, iLang);
+ EditDist3FromString *pFrom;
+ int dist;
+
+ pFrom = editDist3FromStringNew(pLang, zA, nA);
+ if( pFrom==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+ dist = editDist3Core(pFrom, zB, nB, pLang, 0);
+ editDist3FromStringDelete(pFrom);
+ if( dist==(-1) ){
+ sqlite3_result_error_nomem(context);
+ }else{
+ sqlite3_result_int(context, dist);
+ }
+ }
+}
+
+/*
+** Register the editDist3 function with SQLite
+*/
+static int editDist3Install(sqlite3 *db){
+ int rc;
+ EditDist3Config *pConfig = sqlite3_malloc( sizeof(*pConfig) );
+ if( pConfig==0 ) return SQLITE_NOMEM;
+ memset(pConfig, 0, sizeof(*pConfig));
+ rc = sqlite3_create_function_v2(db, "editdist3",
+ 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, pConfig,
+ editDist3SqlFunc, 0, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function_v2(db, "editdist3",
+ 3, SQLITE_UTF8|SQLITE_DETERMINISTIC, pConfig,
+ editDist3SqlFunc, 0, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function_v2(db, "editdist3",
+ 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, pConfig,
+ editDist3SqlFunc, 0, 0, editDist3ConfigDelete);
+ }else{
+ sqlite3_free(pConfig);
+ }
+ return rc;
+}
+/* End configurable cost unicode edit distance routines
+******************************************************************************
+******************************************************************************
+** Begin transliterate unicode-to-ascii implementation
+*/
+
+#if !SQLITE_AMALGAMATION
+/*
+** This lookup table is used to help decode the first byte of
+** a multi-byte UTF8 character.
+*/
+static const unsigned char sqlite3Utf8Trans1[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
+};
+#endif
+
+/*
+** Return the value of the first UTF-8 character in the string.
+*/
+static int utf8Read(const unsigned char *z, int n, int *pSize){
+ int c, i;
+
+ /* All callers to this routine (in the current implementation)
+ ** always have n>0. */
+ if( NEVER(n==0) ){
+ c = i = 0;
+ }else{
+ c = z[0];
+ i = 1;
+ if( c>=0xc0 ){
+ c = sqlite3Utf8Trans1[c-0xc0];
+ while( i<n && (z[i] & 0xc0)==0x80 ){
+ c = (c<<6) + (0x3f & z[i++]);
+ }
+ }
+ }
+ *pSize = i;
+ return c;
+}
+
+/*
+** Return the number of characters in the utf-8 string in the nIn byte
+** buffer pointed to by zIn.
+*/
+static int utf8Charlen(const char *zIn, int nIn){
+ int i;
+ int nChar = 0;
+ for(i=0; i<nIn; nChar++){
+ int sz;
+ utf8Read((const unsigned char *)&zIn[i], nIn-i, &sz);
+ i += sz;
+ }
+ return nChar;
+}
+
+typedef struct Transliteration Transliteration;
+struct Transliteration {
+ unsigned short int cFrom;
+ unsigned char cTo0, cTo1, cTo2, cTo3;
+#ifdef SQLITE_SPELLFIX_5BYTE_MAPPINGS
+ unsigned char cTo4;
+#endif
+};
+
+/*
+** Table of translations from unicode characters into ASCII.
+*/
+static const Transliteration translit[] = {
+ { 0x00A0, 0x20, 0x00, 0x00, 0x00 }, /*   to */
+ { 0x00B5, 0x75, 0x00, 0x00, 0x00 }, /* µ to u */
+ { 0x00C0, 0x41, 0x00, 0x00, 0x00 }, /* À to A */
+ { 0x00C1, 0x41, 0x00, 0x00, 0x00 }, /* � to A */
+ { 0x00C2, 0x41, 0x00, 0x00, 0x00 }, /* Â to A */
+ { 0x00C3, 0x41, 0x00, 0x00, 0x00 }, /* Ã to A */
+ { 0x00C4, 0x41, 0x65, 0x00, 0x00 }, /* Ä to Ae */
+ { 0x00C5, 0x41, 0x61, 0x00, 0x00 }, /* Ã… to Aa */
+ { 0x00C6, 0x41, 0x45, 0x00, 0x00 }, /* Æ to AE */
+ { 0x00C7, 0x43, 0x00, 0x00, 0x00 }, /* Ç to C */
+ { 0x00C8, 0x45, 0x00, 0x00, 0x00 }, /* È to E */
+ { 0x00C9, 0x45, 0x00, 0x00, 0x00 }, /* É to E */
+ { 0x00CA, 0x45, 0x00, 0x00, 0x00 }, /* Ê to E */
+ { 0x00CB, 0x45, 0x00, 0x00, 0x00 }, /* Ë to E */
+ { 0x00CC, 0x49, 0x00, 0x00, 0x00 }, /* Ì to I */
+ { 0x00CD, 0x49, 0x00, 0x00, 0x00 }, /* � to I */
+ { 0x00CE, 0x49, 0x00, 0x00, 0x00 }, /* ÃŽ to I */
+ { 0x00CF, 0x49, 0x00, 0x00, 0x00 }, /* � to I */
+ { 0x00D0, 0x44, 0x00, 0x00, 0x00 }, /* � to D */
+ { 0x00D1, 0x4E, 0x00, 0x00, 0x00 }, /* Ñ to N */
+ { 0x00D2, 0x4F, 0x00, 0x00, 0x00 }, /* Ã’ to O */
+ { 0x00D3, 0x4F, 0x00, 0x00, 0x00 }, /* Ó to O */
+ { 0x00D4, 0x4F, 0x00, 0x00, 0x00 }, /* Ô to O */
+ { 0x00D5, 0x4F, 0x00, 0x00, 0x00 }, /* Õ to O */
+ { 0x00D6, 0x4F, 0x65, 0x00, 0x00 }, /* Ö to Oe */
+ { 0x00D7, 0x78, 0x00, 0x00, 0x00 }, /* × to x */
+ { 0x00D8, 0x4F, 0x00, 0x00, 0x00 }, /* Ø to O */
+ { 0x00D9, 0x55, 0x00, 0x00, 0x00 }, /* Ù to U */
+ { 0x00DA, 0x55, 0x00, 0x00, 0x00 }, /* Ú to U */
+ { 0x00DB, 0x55, 0x00, 0x00, 0x00 }, /* Û to U */
+ { 0x00DC, 0x55, 0x65, 0x00, 0x00 }, /* Ü to Ue */
+ { 0x00DD, 0x59, 0x00, 0x00, 0x00 }, /* � to Y */
+ { 0x00DE, 0x54, 0x68, 0x00, 0x00 }, /* Þ to Th */
+ { 0x00DF, 0x73, 0x73, 0x00, 0x00 }, /* ß to ss */
+ { 0x00E0, 0x61, 0x00, 0x00, 0x00 }, /* à to a */
+ { 0x00E1, 0x61, 0x00, 0x00, 0x00 }, /* á to a */
+ { 0x00E2, 0x61, 0x00, 0x00, 0x00 }, /* â to a */
+ { 0x00E3, 0x61, 0x00, 0x00, 0x00 }, /* ã to a */
+ { 0x00E4, 0x61, 0x65, 0x00, 0x00 }, /* ä to ae */
+ { 0x00E5, 0x61, 0x61, 0x00, 0x00 }, /* å to aa */
+ { 0x00E6, 0x61, 0x65, 0x00, 0x00 }, /* æ to ae */
+ { 0x00E7, 0x63, 0x00, 0x00, 0x00 }, /* ç to c */
+ { 0x00E8, 0x65, 0x00, 0x00, 0x00 }, /* è to e */
+ { 0x00E9, 0x65, 0x00, 0x00, 0x00 }, /* é to e */
+ { 0x00EA, 0x65, 0x00, 0x00, 0x00 }, /* ê to e */
+ { 0x00EB, 0x65, 0x00, 0x00, 0x00 }, /* ë to e */
+ { 0x00EC, 0x69, 0x00, 0x00, 0x00 }, /* ì to i */
+ { 0x00ED, 0x69, 0x00, 0x00, 0x00 }, /* í to i */
+ { 0x00EE, 0x69, 0x00, 0x00, 0x00 }, /* î to i */
+ { 0x00EF, 0x69, 0x00, 0x00, 0x00 }, /* ï to i */
+ { 0x00F0, 0x64, 0x00, 0x00, 0x00 }, /* ð to d */
+ { 0x00F1, 0x6E, 0x00, 0x00, 0x00 }, /* ñ to n */
+ { 0x00F2, 0x6F, 0x00, 0x00, 0x00 }, /* ò to o */
+ { 0x00F3, 0x6F, 0x00, 0x00, 0x00 }, /* ó to o */
+ { 0x00F4, 0x6F, 0x00, 0x00, 0x00 }, /* ô to o */
+ { 0x00F5, 0x6F, 0x00, 0x00, 0x00 }, /* õ to o */
+ { 0x00F6, 0x6F, 0x65, 0x00, 0x00 }, /* ö to oe */
+ { 0x00F7, 0x3A, 0x00, 0x00, 0x00 }, /* ÷ to : */
+ { 0x00F8, 0x6F, 0x00, 0x00, 0x00 }, /* ø to o */
+ { 0x00F9, 0x75, 0x00, 0x00, 0x00 }, /* ù to u */
+ { 0x00FA, 0x75, 0x00, 0x00, 0x00 }, /* ú to u */
+ { 0x00FB, 0x75, 0x00, 0x00, 0x00 }, /* û to u */
+ { 0x00FC, 0x75, 0x65, 0x00, 0x00 }, /* ü to ue */
+ { 0x00FD, 0x79, 0x00, 0x00, 0x00 }, /* ý to y */
+ { 0x00FE, 0x74, 0x68, 0x00, 0x00 }, /* þ to th */
+ { 0x00FF, 0x79, 0x00, 0x00, 0x00 }, /* ÿ to y */
+ { 0x0100, 0x41, 0x00, 0x00, 0x00 }, /* Ā to A */
+ { 0x0101, 0x61, 0x00, 0x00, 0x00 }, /* � to a */
+ { 0x0102, 0x41, 0x00, 0x00, 0x00 }, /* Ä‚ to A */
+ { 0x0103, 0x61, 0x00, 0x00, 0x00 }, /* ă to a */
+ { 0x0104, 0x41, 0x00, 0x00, 0x00 }, /* Ä„ to A */
+ { 0x0105, 0x61, 0x00, 0x00, 0x00 }, /* Ä… to a */
+ { 0x0106, 0x43, 0x00, 0x00, 0x00 }, /* Ć to C */
+ { 0x0107, 0x63, 0x00, 0x00, 0x00 }, /* ć to c */
+ { 0x0108, 0x43, 0x68, 0x00, 0x00 }, /* Ĉ to Ch */
+ { 0x0109, 0x63, 0x68, 0x00, 0x00 }, /* ĉ to ch */
+ { 0x010A, 0x43, 0x00, 0x00, 0x00 }, /* ÄŠ to C */
+ { 0x010B, 0x63, 0x00, 0x00, 0x00 }, /* Ä‹ to c */
+ { 0x010C, 0x43, 0x00, 0x00, 0x00 }, /* Č to C */
+ { 0x010D, 0x63, 0x00, 0x00, 0x00 }, /* � to c */
+ { 0x010E, 0x44, 0x00, 0x00, 0x00 }, /* ÄŽ to D */
+ { 0x010F, 0x64, 0x00, 0x00, 0x00 }, /* � to d */
+ { 0x0110, 0x44, 0x00, 0x00, 0x00 }, /* � to D */
+ { 0x0111, 0x64, 0x00, 0x00, 0x00 }, /* Ä‘ to d */
+ { 0x0112, 0x45, 0x00, 0x00, 0x00 }, /* Ä’ to E */
+ { 0x0113, 0x65, 0x00, 0x00, 0x00 }, /* Ä“ to e */
+ { 0x0114, 0x45, 0x00, 0x00, 0x00 }, /* Ä” to E */
+ { 0x0115, 0x65, 0x00, 0x00, 0x00 }, /* Ä• to e */
+ { 0x0116, 0x45, 0x00, 0x00, 0x00 }, /* Ä– to E */
+ { 0x0117, 0x65, 0x00, 0x00, 0x00 }, /* Ä— to e */
+ { 0x0118, 0x45, 0x00, 0x00, 0x00 }, /* Ę to E */
+ { 0x0119, 0x65, 0x00, 0x00, 0x00 }, /* Ä™ to e */
+ { 0x011A, 0x45, 0x00, 0x00, 0x00 }, /* Äš to E */
+ { 0x011B, 0x65, 0x00, 0x00, 0x00 }, /* Ä› to e */
+ { 0x011C, 0x47, 0x68, 0x00, 0x00 }, /* Ĝ to Gh */
+ { 0x011D, 0x67, 0x68, 0x00, 0x00 }, /* � to gh */
+ { 0x011E, 0x47, 0x00, 0x00, 0x00 }, /* Äž to G */
+ { 0x011F, 0x67, 0x00, 0x00, 0x00 }, /* ÄŸ to g */
+ { 0x0120, 0x47, 0x00, 0x00, 0x00 }, /* Ä  to G */
+ { 0x0121, 0x67, 0x00, 0x00, 0x00 }, /* Ä¡ to g */
+ { 0x0122, 0x47, 0x00, 0x00, 0x00 }, /* Ģ to G */
+ { 0x0123, 0x67, 0x00, 0x00, 0x00 }, /* ģ to g */
+ { 0x0124, 0x48, 0x68, 0x00, 0x00 }, /* Ĥ to Hh */
+ { 0x0125, 0x68, 0x68, 0x00, 0x00 }, /* ĥ to hh */
+ { 0x0126, 0x48, 0x00, 0x00, 0x00 }, /* Ħ to H */
+ { 0x0127, 0x68, 0x00, 0x00, 0x00 }, /* ħ to h */
+ { 0x0128, 0x49, 0x00, 0x00, 0x00 }, /* Ĩ to I */
+ { 0x0129, 0x69, 0x00, 0x00, 0x00 }, /* Ä© to i */
+ { 0x012A, 0x49, 0x00, 0x00, 0x00 }, /* Ī to I */
+ { 0x012B, 0x69, 0x00, 0x00, 0x00 }, /* Ä« to i */
+ { 0x012C, 0x49, 0x00, 0x00, 0x00 }, /* Ĭ to I */
+ { 0x012D, 0x69, 0x00, 0x00, 0x00 }, /* Ä­ to i */
+ { 0x012E, 0x49, 0x00, 0x00, 0x00 }, /* Ä® to I */
+ { 0x012F, 0x69, 0x00, 0x00, 0x00 }, /* į to i */
+ { 0x0130, 0x49, 0x00, 0x00, 0x00 }, /* İ to I */
+ { 0x0131, 0x69, 0x00, 0x00, 0x00 }, /* ı to i */
+ { 0x0132, 0x49, 0x4A, 0x00, 0x00 }, /* IJ to IJ */
+ { 0x0133, 0x69, 0x6A, 0x00, 0x00 }, /* ij to ij */
+ { 0x0134, 0x4A, 0x68, 0x00, 0x00 }, /* Ä´ to Jh */
+ { 0x0135, 0x6A, 0x68, 0x00, 0x00 }, /* ĵ to jh */
+ { 0x0136, 0x4B, 0x00, 0x00, 0x00 }, /* Ķ to K */
+ { 0x0137, 0x6B, 0x00, 0x00, 0x00 }, /* Ä· to k */
+ { 0x0138, 0x6B, 0x00, 0x00, 0x00 }, /* ĸ to k */
+ { 0x0139, 0x4C, 0x00, 0x00, 0x00 }, /* Ĺ to L */
+ { 0x013A, 0x6C, 0x00, 0x00, 0x00 }, /* ĺ to l */
+ { 0x013B, 0x4C, 0x00, 0x00, 0x00 }, /* Ä» to L */
+ { 0x013C, 0x6C, 0x00, 0x00, 0x00 }, /* ļ to l */
+ { 0x013D, 0x4C, 0x00, 0x00, 0x00 }, /* Ľ to L */
+ { 0x013E, 0x6C, 0x00, 0x00, 0x00 }, /* ľ to l */
+ { 0x013F, 0x4C, 0x2E, 0x00, 0x00 }, /* Ä¿ to L. */
+ { 0x0140, 0x6C, 0x2E, 0x00, 0x00 }, /* ŀ to l. */
+ { 0x0141, 0x4C, 0x00, 0x00, 0x00 }, /* � to L */
+ { 0x0142, 0x6C, 0x00, 0x00, 0x00 }, /* Å‚ to l */
+ { 0x0143, 0x4E, 0x00, 0x00, 0x00 }, /* Ń to N */
+ { 0x0144, 0x6E, 0x00, 0x00, 0x00 }, /* Å„ to n */
+ { 0x0145, 0x4E, 0x00, 0x00, 0x00 }, /* Å… to N */
+ { 0x0146, 0x6E, 0x00, 0x00, 0x00 }, /* ņ to n */
+ { 0x0147, 0x4E, 0x00, 0x00, 0x00 }, /* Ň to N */
+ { 0x0148, 0x6E, 0x00, 0x00, 0x00 }, /* ň to n */
+ { 0x0149, 0x27, 0x6E, 0x00, 0x00 }, /* ʼn to 'n */
+ { 0x014A, 0x4E, 0x47, 0x00, 0x00 }, /* ÅŠ to NG */
+ { 0x014B, 0x6E, 0x67, 0x00, 0x00 }, /* Å‹ to ng */
+ { 0x014C, 0x4F, 0x00, 0x00, 0x00 }, /* Ō to O */
+ { 0x014D, 0x6F, 0x00, 0x00, 0x00 }, /* � to o */
+ { 0x014E, 0x4F, 0x00, 0x00, 0x00 }, /* ÅŽ to O */
+ { 0x014F, 0x6F, 0x00, 0x00, 0x00 }, /* � to o */
+ { 0x0150, 0x4F, 0x00, 0x00, 0x00 }, /* � to O */
+ { 0x0151, 0x6F, 0x00, 0x00, 0x00 }, /* Å‘ to o */
+ { 0x0152, 0x4F, 0x45, 0x00, 0x00 }, /* Å’ to OE */
+ { 0x0153, 0x6F, 0x65, 0x00, 0x00 }, /* Å“ to oe */
+ { 0x0154, 0x52, 0x00, 0x00, 0x00 }, /* Å” to R */
+ { 0x0155, 0x72, 0x00, 0x00, 0x00 }, /* Å• to r */
+ { 0x0156, 0x52, 0x00, 0x00, 0x00 }, /* Å– to R */
+ { 0x0157, 0x72, 0x00, 0x00, 0x00 }, /* Å— to r */
+ { 0x0158, 0x52, 0x00, 0x00, 0x00 }, /* Ř to R */
+ { 0x0159, 0x72, 0x00, 0x00, 0x00 }, /* Å™ to r */
+ { 0x015A, 0x53, 0x00, 0x00, 0x00 }, /* Åš to S */
+ { 0x015B, 0x73, 0x00, 0x00, 0x00 }, /* Å› to s */
+ { 0x015C, 0x53, 0x68, 0x00, 0x00 }, /* Ŝ to Sh */
+ { 0x015D, 0x73, 0x68, 0x00, 0x00 }, /* � to sh */
+ { 0x015E, 0x53, 0x00, 0x00, 0x00 }, /* Åž to S */
+ { 0x015F, 0x73, 0x00, 0x00, 0x00 }, /* ÅŸ to s */
+ { 0x0160, 0x53, 0x00, 0x00, 0x00 }, /* Å  to S */
+ { 0x0161, 0x73, 0x00, 0x00, 0x00 }, /* Å¡ to s */
+ { 0x0162, 0x54, 0x00, 0x00, 0x00 }, /* Ţ to T */
+ { 0x0163, 0x74, 0x00, 0x00, 0x00 }, /* ţ to t */
+ { 0x0164, 0x54, 0x00, 0x00, 0x00 }, /* Ť to T */
+ { 0x0165, 0x74, 0x00, 0x00, 0x00 }, /* ť to t */
+ { 0x0166, 0x54, 0x00, 0x00, 0x00 }, /* Ŧ to T */
+ { 0x0167, 0x74, 0x00, 0x00, 0x00 }, /* ŧ to t */
+ { 0x0168, 0x55, 0x00, 0x00, 0x00 }, /* Ũ to U */
+ { 0x0169, 0x75, 0x00, 0x00, 0x00 }, /* Å© to u */
+ { 0x016A, 0x55, 0x00, 0x00, 0x00 }, /* Ū to U */
+ { 0x016B, 0x75, 0x00, 0x00, 0x00 }, /* Å« to u */
+ { 0x016C, 0x55, 0x00, 0x00, 0x00 }, /* Ŭ to U */
+ { 0x016D, 0x75, 0x00, 0x00, 0x00 }, /* Å­ to u */
+ { 0x016E, 0x55, 0x00, 0x00, 0x00 }, /* Å® to U */
+ { 0x016F, 0x75, 0x00, 0x00, 0x00 }, /* ů to u */
+ { 0x0170, 0x55, 0x00, 0x00, 0x00 }, /* Ű to U */
+ { 0x0171, 0x75, 0x00, 0x00, 0x00 }, /* ű to u */
+ { 0x0172, 0x55, 0x00, 0x00, 0x00 }, /* Ų to U */
+ { 0x0173, 0x75, 0x00, 0x00, 0x00 }, /* ų to u */
+ { 0x0174, 0x57, 0x00, 0x00, 0x00 }, /* Å´ to W */
+ { 0x0175, 0x77, 0x00, 0x00, 0x00 }, /* ŵ to w */
+ { 0x0176, 0x59, 0x00, 0x00, 0x00 }, /* Ŷ to Y */
+ { 0x0177, 0x79, 0x00, 0x00, 0x00 }, /* Å· to y */
+ { 0x0178, 0x59, 0x00, 0x00, 0x00 }, /* Ÿ to Y */
+ { 0x0179, 0x5A, 0x00, 0x00, 0x00 }, /* Ź to Z */
+ { 0x017A, 0x7A, 0x00, 0x00, 0x00 }, /* ź to z */
+ { 0x017B, 0x5A, 0x00, 0x00, 0x00 }, /* Å» to Z */
+ { 0x017C, 0x7A, 0x00, 0x00, 0x00 }, /* ż to z */
+ { 0x017D, 0x5A, 0x00, 0x00, 0x00 }, /* Ž to Z */
+ { 0x017E, 0x7A, 0x00, 0x00, 0x00 }, /* ž to z */
+ { 0x017F, 0x73, 0x00, 0x00, 0x00 }, /* Å¿ to s */
+ { 0x0192, 0x66, 0x00, 0x00, 0x00 }, /* Æ’ to f */
+ { 0x0218, 0x53, 0x00, 0x00, 0x00 }, /* Ș to S */
+ { 0x0219, 0x73, 0x00, 0x00, 0x00 }, /* È™ to s */
+ { 0x021A, 0x54, 0x00, 0x00, 0x00 }, /* Èš to T */
+ { 0x021B, 0x74, 0x00, 0x00, 0x00 }, /* È› to t */
+ { 0x0386, 0x41, 0x00, 0x00, 0x00 }, /* Ά to A */
+ { 0x0388, 0x45, 0x00, 0x00, 0x00 }, /* Έ to E */
+ { 0x0389, 0x49, 0x00, 0x00, 0x00 }, /* Ή to I */
+ { 0x038A, 0x49, 0x00, 0x00, 0x00 }, /* Ί to I */
+ { 0x038C, 0x4f, 0x00, 0x00, 0x00 }, /* Ό to O */
+ { 0x038E, 0x59, 0x00, 0x00, 0x00 }, /* ÎŽ to Y */
+ { 0x038F, 0x4f, 0x00, 0x00, 0x00 }, /* � to O */
+ { 0x0390, 0x69, 0x00, 0x00, 0x00 }, /* � to i */
+ { 0x0391, 0x41, 0x00, 0x00, 0x00 }, /* Α to A */
+ { 0x0392, 0x42, 0x00, 0x00, 0x00 }, /* Î’ to B */
+ { 0x0393, 0x47, 0x00, 0x00, 0x00 }, /* Γ to G */
+ { 0x0394, 0x44, 0x00, 0x00, 0x00 }, /* Δ to D */
+ { 0x0395, 0x45, 0x00, 0x00, 0x00 }, /* Ε to E */
+ { 0x0396, 0x5a, 0x00, 0x00, 0x00 }, /* Ζ to Z */
+ { 0x0397, 0x49, 0x00, 0x00, 0x00 }, /* Η to I */
+ { 0x0398, 0x54, 0x68, 0x00, 0x00 }, /* Θ to Th */
+ { 0x0399, 0x49, 0x00, 0x00, 0x00 }, /* Ι to I */
+ { 0x039A, 0x4b, 0x00, 0x00, 0x00 }, /* Κ to K */
+ { 0x039B, 0x4c, 0x00, 0x00, 0x00 }, /* Λ to L */
+ { 0x039C, 0x4d, 0x00, 0x00, 0x00 }, /* Μ to M */
+ { 0x039D, 0x4e, 0x00, 0x00, 0x00 }, /* � to N */
+ { 0x039E, 0x58, 0x00, 0x00, 0x00 }, /* Ξ to X */
+ { 0x039F, 0x4f, 0x00, 0x00, 0x00 }, /* Ο to O */
+ { 0x03A0, 0x50, 0x00, 0x00, 0x00 }, /* Π to P */
+ { 0x03A1, 0x52, 0x00, 0x00, 0x00 }, /* Ρ to R */
+ { 0x03A3, 0x53, 0x00, 0x00, 0x00 }, /* Σ to S */
+ { 0x03A4, 0x54, 0x00, 0x00, 0x00 }, /* Τ to T */
+ { 0x03A5, 0x59, 0x00, 0x00, 0x00 }, /* Υ to Y */
+ { 0x03A6, 0x46, 0x00, 0x00, 0x00 }, /* Φ to F */
+ { 0x03A7, 0x43, 0x68, 0x00, 0x00 }, /* Χ to Ch */
+ { 0x03A8, 0x50, 0x73, 0x00, 0x00 }, /* Ψ to Ps */
+ { 0x03A9, 0x4f, 0x00, 0x00, 0x00 }, /* Ω to O */
+ { 0x03AA, 0x49, 0x00, 0x00, 0x00 }, /* Ϊ to I */
+ { 0x03AB, 0x59, 0x00, 0x00, 0x00 }, /* Ϋ to Y */
+ { 0x03AC, 0x61, 0x00, 0x00, 0x00 }, /* ά to a */
+ { 0x03AD, 0x65, 0x00, 0x00, 0x00 }, /* έ to e */
+ { 0x03AE, 0x69, 0x00, 0x00, 0x00 }, /* ή to i */
+ { 0x03AF, 0x69, 0x00, 0x00, 0x00 }, /* ί to i */
+ { 0x03B1, 0x61, 0x00, 0x00, 0x00 }, /* α to a */
+ { 0x03B2, 0x62, 0x00, 0x00, 0x00 }, /* β to b */
+ { 0x03B3, 0x67, 0x00, 0x00, 0x00 }, /* γ to g */
+ { 0x03B4, 0x64, 0x00, 0x00, 0x00 }, /* δ to d */
+ { 0x03B5, 0x65, 0x00, 0x00, 0x00 }, /* ε to e */
+ { 0x03B6, 0x7a, 0x00, 0x00, 0x00 }, /* ζ to z */
+ { 0x03B7, 0x69, 0x00, 0x00, 0x00 }, /* η to i */
+ { 0x03B8, 0x74, 0x68, 0x00, 0x00 }, /* θ to th */
+ { 0x03B9, 0x69, 0x00, 0x00, 0x00 }, /* ι to i */
+ { 0x03BA, 0x6b, 0x00, 0x00, 0x00 }, /* κ to k */
+ { 0x03BB, 0x6c, 0x00, 0x00, 0x00 }, /* λ to l */
+ { 0x03BC, 0x6d, 0x00, 0x00, 0x00 }, /* μ to m */
+ { 0x03BD, 0x6e, 0x00, 0x00, 0x00 }, /* ν to n */
+ { 0x03BE, 0x78, 0x00, 0x00, 0x00 }, /* ξ to x */
+ { 0x03BF, 0x6f, 0x00, 0x00, 0x00 }, /* ο to o */
+ { 0x03C0, 0x70, 0x00, 0x00, 0x00 }, /* π to p */
+ { 0x03C1, 0x72, 0x00, 0x00, 0x00 }, /* � to r */
+ { 0x03C3, 0x73, 0x00, 0x00, 0x00 }, /* σ to s */
+ { 0x03C4, 0x74, 0x00, 0x00, 0x00 }, /* Ï„ to t */
+ { 0x03C5, 0x79, 0x00, 0x00, 0x00 }, /* Ï… to y */
+ { 0x03C6, 0x66, 0x00, 0x00, 0x00 }, /* φ to f */
+ { 0x03C7, 0x63, 0x68, 0x00, 0x00 }, /* χ to ch */
+ { 0x03C8, 0x70, 0x73, 0x00, 0x00 }, /* ψ to ps */
+ { 0x03C9, 0x6f, 0x00, 0x00, 0x00 }, /* ω to o */
+ { 0x03CA, 0x69, 0x00, 0x00, 0x00 }, /* ÏŠ to i */
+ { 0x03CB, 0x79, 0x00, 0x00, 0x00 }, /* Ï‹ to y */
+ { 0x03CC, 0x6f, 0x00, 0x00, 0x00 }, /* ό to o */
+ { 0x03CD, 0x79, 0x00, 0x00, 0x00 }, /* � to y */
+ { 0x03CE, 0x69, 0x00, 0x00, 0x00 }, /* ÏŽ to i */
+ { 0x0400, 0x45, 0x00, 0x00, 0x00 }, /* Ѐ to E */
+ { 0x0401, 0x45, 0x00, 0x00, 0x00 }, /* � to E */
+ { 0x0402, 0x44, 0x00, 0x00, 0x00 }, /* Ђ to D */
+ { 0x0403, 0x47, 0x00, 0x00, 0x00 }, /* Ѓ to G */
+ { 0x0404, 0x45, 0x00, 0x00, 0x00 }, /* Є to E */
+ { 0x0405, 0x5a, 0x00, 0x00, 0x00 }, /* Ð… to Z */
+ { 0x0406, 0x49, 0x00, 0x00, 0x00 }, /* І to I */
+ { 0x0407, 0x49, 0x00, 0x00, 0x00 }, /* Ї to I */
+ { 0x0408, 0x4a, 0x00, 0x00, 0x00 }, /* Ј to J */
+ { 0x0409, 0x49, 0x00, 0x00, 0x00 }, /* Љ to I */
+ { 0x040A, 0x4e, 0x00, 0x00, 0x00 }, /* Њ to N */
+ { 0x040B, 0x44, 0x00, 0x00, 0x00 }, /* Ћ to D */
+ { 0x040C, 0x4b, 0x00, 0x00, 0x00 }, /* Ќ to K */
+ { 0x040D, 0x49, 0x00, 0x00, 0x00 }, /* � to I */
+ { 0x040E, 0x55, 0x00, 0x00, 0x00 }, /* ÐŽ to U */
+ { 0x040F, 0x44, 0x00, 0x00, 0x00 }, /* � to D */
+ { 0x0410, 0x41, 0x00, 0x00, 0x00 }, /* � to A */
+ { 0x0411, 0x42, 0x00, 0x00, 0x00 }, /* Б to B */
+ { 0x0412, 0x56, 0x00, 0x00, 0x00 }, /* Ð’ to V */
+ { 0x0413, 0x47, 0x00, 0x00, 0x00 }, /* Г to G */
+ { 0x0414, 0x44, 0x00, 0x00, 0x00 }, /* Д to D */
+ { 0x0415, 0x45, 0x00, 0x00, 0x00 }, /* Е to E */
+ { 0x0416, 0x5a, 0x68, 0x00, 0x00 }, /* Ж to Zh */
+ { 0x0417, 0x5a, 0x00, 0x00, 0x00 }, /* З to Z */
+ { 0x0418, 0x49, 0x00, 0x00, 0x00 }, /* И to I */
+ { 0x0419, 0x49, 0x00, 0x00, 0x00 }, /* Й to I */
+ { 0x041A, 0x4b, 0x00, 0x00, 0x00 }, /* К to K */
+ { 0x041B, 0x4c, 0x00, 0x00, 0x00 }, /* Л to L */
+ { 0x041C, 0x4d, 0x00, 0x00, 0x00 }, /* М to M */
+ { 0x041D, 0x4e, 0x00, 0x00, 0x00 }, /* � to N */
+ { 0x041E, 0x4f, 0x00, 0x00, 0x00 }, /* О to O */
+ { 0x041F, 0x50, 0x00, 0x00, 0x00 }, /* П to P */
+ { 0x0420, 0x52, 0x00, 0x00, 0x00 }, /* Р to R */
+ { 0x0421, 0x53, 0x00, 0x00, 0x00 }, /* С to S */
+ { 0x0422, 0x54, 0x00, 0x00, 0x00 }, /* Т to T */
+ { 0x0423, 0x55, 0x00, 0x00, 0x00 }, /* У to U */
+ { 0x0424, 0x46, 0x00, 0x00, 0x00 }, /* Ф to F */
+ { 0x0425, 0x4b, 0x68, 0x00, 0x00 }, /* Х to Kh */
+ { 0x0426, 0x54, 0x63, 0x00, 0x00 }, /* Ц to Tc */
+ { 0x0427, 0x43, 0x68, 0x00, 0x00 }, /* Ч to Ch */
+ { 0x0428, 0x53, 0x68, 0x00, 0x00 }, /* Ш to Sh */
+ { 0x0429, 0x53, 0x68, 0x63, 0x68 }, /* Щ to Shch */
+ { 0x042A, 0x61, 0x00, 0x00, 0x00 }, /* to A */
+ { 0x042B, 0x59, 0x00, 0x00, 0x00 }, /* Ы to Y */
+ { 0x042C, 0x59, 0x00, 0x00, 0x00 }, /* to Y */
+ { 0x042D, 0x45, 0x00, 0x00, 0x00 }, /* Э to E */
+ { 0x042E, 0x49, 0x75, 0x00, 0x00 }, /* Ю to Iu */
+ { 0x042F, 0x49, 0x61, 0x00, 0x00 }, /* Я to Ia */
+ { 0x0430, 0x61, 0x00, 0x00, 0x00 }, /* а to a */
+ { 0x0431, 0x62, 0x00, 0x00, 0x00 }, /* б to b */
+ { 0x0432, 0x76, 0x00, 0x00, 0x00 }, /* в to v */
+ { 0x0433, 0x67, 0x00, 0x00, 0x00 }, /* г to g */
+ { 0x0434, 0x64, 0x00, 0x00, 0x00 }, /* д to d */
+ { 0x0435, 0x65, 0x00, 0x00, 0x00 }, /* е to e */
+ { 0x0436, 0x7a, 0x68, 0x00, 0x00 }, /* ж to zh */
+ { 0x0437, 0x7a, 0x00, 0x00, 0x00 }, /* з to z */
+ { 0x0438, 0x69, 0x00, 0x00, 0x00 }, /* и to i */
+ { 0x0439, 0x69, 0x00, 0x00, 0x00 }, /* й to i */
+ { 0x043A, 0x6b, 0x00, 0x00, 0x00 }, /* к to k */
+ { 0x043B, 0x6c, 0x00, 0x00, 0x00 }, /* л to l */
+ { 0x043C, 0x6d, 0x00, 0x00, 0x00 }, /* м to m */
+ { 0x043D, 0x6e, 0x00, 0x00, 0x00 }, /* н to n */
+ { 0x043E, 0x6f, 0x00, 0x00, 0x00 }, /* о to o */
+ { 0x043F, 0x70, 0x00, 0x00, 0x00 }, /* п to p */
+ { 0x0440, 0x72, 0x00, 0x00, 0x00 }, /* р to r */
+ { 0x0441, 0x73, 0x00, 0x00, 0x00 }, /* � to s */
+ { 0x0442, 0x74, 0x00, 0x00, 0x00 }, /* Ñ‚ to t */
+ { 0x0443, 0x75, 0x00, 0x00, 0x00 }, /* у to u */
+ { 0x0444, 0x66, 0x00, 0x00, 0x00 }, /* Ñ„ to f */
+ { 0x0445, 0x6b, 0x68, 0x00, 0x00 }, /* Ñ… to kh */
+ { 0x0446, 0x74, 0x63, 0x00, 0x00 }, /* ц to tc */
+ { 0x0447, 0x63, 0x68, 0x00, 0x00 }, /* ч to ch */
+ { 0x0448, 0x73, 0x68, 0x00, 0x00 }, /* ш to sh */
+ { 0x0449, 0x73, 0x68, 0x63, 0x68 }, /* щ to shch */
+ { 0x044A, 0x61, 0x00, 0x00, 0x00 }, /* to a */
+ { 0x044B, 0x79, 0x00, 0x00, 0x00 }, /* Ñ‹ to y */
+ { 0x044C, 0x79, 0x00, 0x00, 0x00 }, /* to y */
+ { 0x044D, 0x65, 0x00, 0x00, 0x00 }, /* � to e */
+ { 0x044E, 0x69, 0x75, 0x00, 0x00 }, /* ÑŽ to iu */
+ { 0x044F, 0x69, 0x61, 0x00, 0x00 }, /* � to ia */
+ { 0x0450, 0x65, 0x00, 0x00, 0x00 }, /* � to e */
+ { 0x0451, 0x65, 0x00, 0x00, 0x00 }, /* Ñ‘ to e */
+ { 0x0452, 0x64, 0x00, 0x00, 0x00 }, /* Ñ’ to d */
+ { 0x0453, 0x67, 0x00, 0x00, 0x00 }, /* Ñ“ to g */
+ { 0x0454, 0x65, 0x00, 0x00, 0x00 }, /* Ñ” to e */
+ { 0x0455, 0x7a, 0x00, 0x00, 0x00 }, /* Ñ• to z */
+ { 0x0456, 0x69, 0x00, 0x00, 0x00 }, /* Ñ– to i */
+ { 0x0457, 0x69, 0x00, 0x00, 0x00 }, /* Ñ— to i */
+ { 0x0458, 0x6a, 0x00, 0x00, 0x00 }, /* ј to j */
+ { 0x0459, 0x69, 0x00, 0x00, 0x00 }, /* Ñ™ to i */
+ { 0x045A, 0x6e, 0x00, 0x00, 0x00 }, /* Ñš to n */
+ { 0x045B, 0x64, 0x00, 0x00, 0x00 }, /* Ñ› to d */
+ { 0x045C, 0x6b, 0x00, 0x00, 0x00 }, /* ќ to k */
+ { 0x045D, 0x69, 0x00, 0x00, 0x00 }, /* � to i */
+ { 0x045E, 0x75, 0x00, 0x00, 0x00 }, /* Ñž to u */
+ { 0x045F, 0x64, 0x00, 0x00, 0x00 }, /* ÑŸ to d */
+ { 0x1E02, 0x42, 0x00, 0x00, 0x00 }, /* Ḃ to B */
+ { 0x1E03, 0x62, 0x00, 0x00, 0x00 }, /* ḃ to b */
+ { 0x1E0A, 0x44, 0x00, 0x00, 0x00 }, /* Ḋ to D */
+ { 0x1E0B, 0x64, 0x00, 0x00, 0x00 }, /* ḋ to d */
+ { 0x1E1E, 0x46, 0x00, 0x00, 0x00 }, /* Ḟ to F */
+ { 0x1E1F, 0x66, 0x00, 0x00, 0x00 }, /* ḟ to f */
+ { 0x1E40, 0x4D, 0x00, 0x00, 0x00 }, /* á¹€ to M */
+ { 0x1E41, 0x6D, 0x00, 0x00, 0x00 }, /* � to m */
+ { 0x1E56, 0x50, 0x00, 0x00, 0x00 }, /* á¹– to P */
+ { 0x1E57, 0x70, 0x00, 0x00, 0x00 }, /* á¹— to p */
+ { 0x1E60, 0x53, 0x00, 0x00, 0x00 }, /* á¹  to S */
+ { 0x1E61, 0x73, 0x00, 0x00, 0x00 }, /* ṡ to s */
+ { 0x1E6A, 0x54, 0x00, 0x00, 0x00 }, /* Ṫ to T */
+ { 0x1E6B, 0x74, 0x00, 0x00, 0x00 }, /* ṫ to t */
+ { 0x1E80, 0x57, 0x00, 0x00, 0x00 }, /* Ẁ to W */
+ { 0x1E81, 0x77, 0x00, 0x00, 0x00 }, /* � to w */
+ { 0x1E82, 0x57, 0x00, 0x00, 0x00 }, /* Ẃ to W */
+ { 0x1E83, 0x77, 0x00, 0x00, 0x00 }, /* ẃ to w */
+ { 0x1E84, 0x57, 0x00, 0x00, 0x00 }, /* Ẅ to W */
+ { 0x1E85, 0x77, 0x00, 0x00, 0x00 }, /* ẅ to w */
+ { 0x1EF2, 0x59, 0x00, 0x00, 0x00 }, /* Ỳ to Y */
+ { 0x1EF3, 0x79, 0x00, 0x00, 0x00 }, /* ỳ to y */
+ { 0xFB00, 0x66, 0x66, 0x00, 0x00 }, /* ff to ff */
+ { 0xFB01, 0x66, 0x69, 0x00, 0x00 }, /* � to fi */
+ { 0xFB02, 0x66, 0x6C, 0x00, 0x00 }, /* fl to fl */
+ { 0xFB05, 0x73, 0x74, 0x00, 0x00 }, /* ſt to st */
+ { 0xFB06, 0x73, 0x74, 0x00, 0x00 }, /* st to st */
+};
+
+static const Transliteration *spellfixFindTranslit(int c, int *pxTop){
+ *pxTop = (sizeof(translit)/sizeof(translit[0])) - 1;
+ return translit;
+}
+
+/*
+** Convert the input string from UTF-8 into pure ASCII by converting
+** all non-ASCII characters to some combination of characters in the
+** ASCII subset.
+**
+** The returned string might contain more characters than the input.
+**
+** Space to hold the returned string comes from sqlite3_malloc() and
+** should be freed by the caller.
+*/
+static unsigned char *transliterate(const unsigned char *zIn, int nIn){
+#ifdef SQLITE_SPELLFIX_5BYTE_MAPPINGS
+ unsigned char *zOut = sqlite3_malloc( nIn*5 + 1 );
+#else
+ unsigned char *zOut = sqlite3_malloc( nIn*4 + 1 );
+#endif
+ int c, sz, nOut;
+ if( zOut==0 ) return 0;
+ nOut = 0;
+ while( nIn>0 ){
+ c = utf8Read(zIn, nIn, &sz);
+ zIn += sz;
+ nIn -= sz;
+ if( c<=127 ){
+ zOut[nOut++] = (unsigned char)c;
+ }else{
+ int xTop, xBtm, x;
+ const Transliteration *tbl = spellfixFindTranslit(c, &xTop);
+ xBtm = 0;
+ while( xTop>=xBtm ){
+ x = (xTop + xBtm)/2;
+ if( tbl[x].cFrom==c ){
+ zOut[nOut++] = tbl[x].cTo0;
+ if( tbl[x].cTo1 ){
+ zOut[nOut++] = tbl[x].cTo1;
+ if( tbl[x].cTo2 ){
+ zOut[nOut++] = tbl[x].cTo2;
+ if( tbl[x].cTo3 ){
+ zOut[nOut++] = tbl[x].cTo3;
+#ifdef SQLITE_SPELLFIX_5BYTE_MAPPINGS
+ if( tbl[x].cTo4 ){
+ zOut[nOut++] = tbl[x].cTo4;
+ }
+#endif /* SQLITE_SPELLFIX_5BYTE_MAPPINGS */
+ }
+ }
+ }
+ c = 0;
+ break;
+ }else if( tbl[x].cFrom>c ){
+ xTop = x-1;
+ }else{
+ xBtm = x+1;
+ }
+ }
+ if( c ) zOut[nOut++] = '?';
+ }
+ }
+ zOut[nOut] = 0;
+ return zOut;
+}
+
+/*
+** Return the number of characters in the shortest prefix of the input
+** string that transliterates to an ASCII string nTrans bytes or longer.
+** Or, if the transliteration of the input string is less than nTrans
+** bytes in size, return the number of characters in the input string.
+*/
+static int translen_to_charlen(const char *zIn, int nIn, int nTrans){
+ int i, c, sz, nOut;
+ int nChar;
+
+ i = nOut = 0;
+ for(nChar=0; i<nIn && nOut<nTrans; nChar++){
+ c = utf8Read((const unsigned char *)&zIn[i], nIn-i, &sz);
+ i += sz;
+
+ nOut++;
+ if( c>=128 ){
+ int xTop, xBtm, x;
+ const Transliteration *tbl = spellfixFindTranslit(c, &xTop);
+ xBtm = 0;
+ while( xTop>=xBtm ){
+ x = (xTop + xBtm)/2;
+ if( tbl[x].cFrom==c ){
+ if( tbl[x].cTo1 ){
+ nOut++;
+ if( tbl[x].cTo2 ){
+ nOut++;
+ if( tbl[x].cTo3 ){
+ nOut++;
+ }
+ }
+ }
+ break;
+ }else if( tbl[x].cFrom>c ){
+ xTop = x-1;
+ }else{
+ xBtm = x+1;
+ }
+ }
+ }
+ }
+
+ return nChar;
+}
+
+
+/*
+** spellfix1_translit(X)
+**
+** Convert a string that contains non-ASCII Roman characters into
+** pure ASCII.
+*/
+static void transliterateSqlFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const unsigned char *zIn = sqlite3_value_text(argv[0]);
+ int nIn = sqlite3_value_bytes(argv[0]);
+ unsigned char *zOut = transliterate(zIn, nIn);
+ if( zOut==0 ){
+ sqlite3_result_error_nomem(context);
+ }else{
+ sqlite3_result_text(context, (char*)zOut, -1, sqlite3_free);
+ }
+}
+
+/*
+** spellfix1_scriptcode(X)
+**
+** Try to determine the dominant script used by the word X and return
+** its ISO 15924 numeric code.
+**
+** The current implementation only understands the following scripts:
+**
+** 215 (Latin)
+** 220 (Cyrillic)
+** 200 (Greek)
+**
+** This routine will return 998 if the input X contains characters from
+** two or more of the above scripts or 999 if X contains no characters
+** from any of the above scripts.
+*/
+static void scriptCodeSqlFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const unsigned char *zIn = sqlite3_value_text(argv[0]);
+ int nIn = sqlite3_value_bytes(argv[0]);
+ int c, sz;
+ int scriptMask = 0;
+ int res;
+ int seenDigit = 0;
+# define SCRIPT_LATIN 0x0001
+# define SCRIPT_CYRILLIC 0x0002
+# define SCRIPT_GREEK 0x0004
+# define SCRIPT_HEBREW 0x0008
+# define SCRIPT_ARABIC 0x0010
+
+ while( nIn>0 ){
+ c = utf8Read(zIn, nIn, &sz);
+ zIn += sz;
+ nIn -= sz;
+ if( c<0x02af ){
+ if( c>=0x80 || midClass[c&0x7f]<CCLASS_DIGIT ){
+ scriptMask |= SCRIPT_LATIN;
+ }else if( c>='0' && c<='9' ){
+ seenDigit = 1;
+ }
+ }else if( c>=0x0400 && c<=0x04ff ){
+ scriptMask |= SCRIPT_CYRILLIC;
+ }else if( c>=0x0386 && c<=0x03ce ){
+ scriptMask |= SCRIPT_GREEK;
+ }else if( c>=0x0590 && c<=0x05ff ){
+ scriptMask |= SCRIPT_HEBREW;
+ }else if( c>=0x0600 && c<=0x06ff ){
+ scriptMask |= SCRIPT_ARABIC;
+ }
+ }
+ if( scriptMask==0 && seenDigit ) scriptMask = SCRIPT_LATIN;
+ switch( scriptMask ){
+ case 0: res = 999; break;
+ case SCRIPT_LATIN: res = 215; break;
+ case SCRIPT_CYRILLIC: res = 220; break;
+ case SCRIPT_GREEK: res = 200; break;
+ case SCRIPT_HEBREW: res = 125; break;
+ case SCRIPT_ARABIC: res = 160; break;
+ default: res = 998; break;
+ }
+ sqlite3_result_int(context, res);
+}
+
+/* End transliterate
+******************************************************************************
+******************************************************************************
+** Begin spellfix1 virtual table.
+*/
+
+/* Maximum length of a phonehash used for querying the shadow table */
+#define SPELLFIX_MX_HASH 32
+
+/* Maximum number of hash strings to examine per query */
+#define SPELLFIX_MX_RUN 1
+
+typedef struct spellfix1_vtab spellfix1_vtab;
+typedef struct spellfix1_cursor spellfix1_cursor;
+
+/* Fuzzy-search virtual table object */
+struct spellfix1_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection */
+ char *zDbName; /* Name of database holding this table */
+ char *zTableName; /* Name of the virtual table */
+ char *zCostTable; /* Table holding edit-distance cost numbers */
+ EditDist3Config *pConfig3; /* Parsed edit distance costs */
+};
+
+/* Fuzzy-search cursor object */
+struct spellfix1_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ spellfix1_vtab *pVTab; /* The table to which this cursor belongs */
+ char *zPattern; /* rhs of MATCH clause */
+ int idxNum; /* idxNum value passed to xFilter() */
+ int nRow; /* Number of rows of content */
+ int nAlloc; /* Number of allocated rows */
+ int iRow; /* Current row of content */
+ int iLang; /* Value of the langid= constraint */
+ int iTop; /* Value of the top= constraint */
+ int iScope; /* Value of the scope= constraint */
+ int nSearch; /* Number of vocabulary items checked */
+ sqlite3_stmt *pFullScan; /* Shadow query for a full table scan */
+ struct spellfix1_row { /* For each row of content */
+ sqlite3_int64 iRowid; /* Rowid for this row */
+ char *zWord; /* Text for this row */
+ int iRank; /* Rank for this row */
+ int iDistance; /* Distance from pattern for this row */
+ int iScore; /* Score for sorting */
+ int iMatchlen; /* Value of matchlen column (or -1) */
+ char zHash[SPELLFIX_MX_HASH]; /* the phonehash used for this match */
+ } *a;
+};
+
+/*
+** Construct one or more SQL statements from the format string given
+** and then evaluate those statements. The success code is written
+** into *pRc.
+**
+** If *pRc is initially non-zero then this routine is a no-op.
+*/
+static void spellfix1DbExec(
+ int *pRc, /* Success code */
+ sqlite3 *db, /* Database in which to run SQL */
+ const char *zFormat, /* Format string for SQL */
+ ... /* Arguments to the format string */
+){
+ va_list ap;
+ char *zSql;
+ if( *pRc ) return;
+ va_start(ap, zFormat);
+ zSql = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+ if( zSql==0 ){
+ *pRc = SQLITE_NOMEM;
+ }else{
+ *pRc = sqlite3_exec(db, zSql, 0, 0, 0);
+ sqlite3_free(zSql);
+ }
+}
+
+/*
+** xDisconnect/xDestroy method for the fuzzy-search module.
+*/
+static int spellfix1Uninit(int isDestroy, sqlite3_vtab *pVTab){
+ spellfix1_vtab *p = (spellfix1_vtab*)pVTab;
+ int rc = SQLITE_OK;
+ if( isDestroy ){
+ sqlite3 *db = p->db;
+ spellfix1DbExec(&rc, db, "DROP TABLE IF EXISTS \"%w\".\"%w_vocab\"",
+ p->zDbName, p->zTableName);
+ }
+ if( rc==SQLITE_OK ){
+ sqlite3_free(p->zTableName);
+ editDist3ConfigDelete(p->pConfig3);
+ sqlite3_free(p->zCostTable);
+ sqlite3_free(p);
+ }
+ return rc;
+}
+static int spellfix1Disconnect(sqlite3_vtab *pVTab){
+ return spellfix1Uninit(0, pVTab);
+}
+static int spellfix1Destroy(sqlite3_vtab *pVTab){
+ return spellfix1Uninit(1, pVTab);
+}
+
+/*
+** Make a copy of a string. Remove leading and trailing whitespace
+** and dequote it.
+*/
+static char *spellfix1Dequote(const char *zIn){
+ char *zOut;
+ int i, j;
+ char c;
+ while( isspace((unsigned char)zIn[0]) ) zIn++;
+ zOut = sqlite3_mprintf("%s", zIn);
+ if( zOut==0 ) return 0;
+ i = (int)strlen(zOut);
+#if 0 /* The parser will never leave spaces at the end */
+ while( i>0 && isspace(zOut[i-1]) ){ i--; }
+#endif
+ zOut[i] = 0;
+ c = zOut[0];
+ if( c=='\'' || c=='"' ){
+ for(i=1, j=0; ALWAYS(zOut[i]); i++){
+ zOut[j++] = zOut[i];
+ if( zOut[i]==c ){
+ if( zOut[i+1]==c ){
+ i++;
+ }else{
+ zOut[j-1] = 0;
+ break;
+ }
+ }
+ }
+ }
+ return zOut;
+}
+
+
+/*
+** xConnect/xCreate method for the spellfix1 module. Arguments are:
+**
+** argv[0] -> module name ("spellfix1")
+** argv[1] -> database name
+** argv[2] -> table name
+** argv[3].. -> optional arguments (i.e. "edit_cost_table" parameter)
+*/
+static int spellfix1Init(
+ int isCreate,
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVTab,
+ char **pzErr
+){
+ spellfix1_vtab *pNew = 0;
+ /* const char *zModule = argv[0]; // not used */
+ const char *zDbName = argv[1];
+ const char *zTableName = argv[2];
+ int nDbName;
+ int rc = SQLITE_OK;
+ int i;
+
+ nDbName = (int)strlen(zDbName);
+ pNew = sqlite3_malloc( sizeof(*pNew) + nDbName + 1);
+ if( pNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->zDbName = (char*)&pNew[1];
+ memcpy(pNew->zDbName, zDbName, nDbName+1);
+ pNew->zTableName = sqlite3_mprintf("%s", zTableName);
+ pNew->db = db;
+ if( pNew->zTableName==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x(word,rank,distance,langid, "
+ "score, matchlen, phonehash HIDDEN, "
+ "top HIDDEN, scope HIDDEN, srchcnt HIDDEN, "
+ "soundslike HIDDEN, command HIDDEN)"
+ );
+#define SPELLFIX_COL_WORD 0
+#define SPELLFIX_COL_RANK 1
+#define SPELLFIX_COL_DISTANCE 2
+#define SPELLFIX_COL_LANGID 3
+#define SPELLFIX_COL_SCORE 4
+#define SPELLFIX_COL_MATCHLEN 5
+#define SPELLFIX_COL_PHONEHASH 6
+#define SPELLFIX_COL_TOP 7
+#define SPELLFIX_COL_SCOPE 8
+#define SPELLFIX_COL_SRCHCNT 9
+#define SPELLFIX_COL_SOUNDSLIKE 10
+#define SPELLFIX_COL_COMMAND 11
+ }
+ if( rc==SQLITE_OK && isCreate ){
+ spellfix1DbExec(&rc, db,
+ "CREATE TABLE IF NOT EXISTS \"%w\".\"%w_vocab\"(\n"
+ " id INTEGER PRIMARY KEY,\n"
+ " rank INT,\n"
+ " langid INT,\n"
+ " word TEXT,\n"
+ " k1 TEXT,\n"
+ " k2 TEXT\n"
+ ");\n",
+ zDbName, zTableName
+ );
+ spellfix1DbExec(&rc, db,
+ "CREATE INDEX IF NOT EXISTS \"%w\".\"%w_vocab_index_langid_k2\" "
+ "ON \"%w_vocab\"(langid,k2);",
+ zDbName, zTableName, zTableName
+ );
+ }
+ for(i=3; rc==SQLITE_OK && i<argc; i++){
+ if( strncmp(argv[i],"edit_cost_table=",16)==0 && pNew->zCostTable==0 ){
+ pNew->zCostTable = spellfix1Dequote(&argv[i][16]);
+ if( pNew->zCostTable==0 ) rc = SQLITE_NOMEM;
+ continue;
+ }
+ *pzErr = sqlite3_mprintf("bad argument to spellfix1(): \"%s\"", argv[i]);
+ rc = SQLITE_ERROR;
+ }
+ }
+
+ if( rc && pNew ){
+ *ppVTab = 0;
+ spellfix1Uninit(0, &pNew->base);
+ }else{
+ *ppVTab = (sqlite3_vtab *)pNew;
+ }
+ return rc;
+}
+
+/*
+** The xConnect and xCreate methods
+*/
+static int spellfix1Connect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVTab,
+ char **pzErr
+){
+ return spellfix1Init(0, db, pAux, argc, argv, ppVTab, pzErr);
+}
+static int spellfix1Create(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVTab,
+ char **pzErr
+){
+ return spellfix1Init(1, db, pAux, argc, argv, ppVTab, pzErr);
+}
+
+/*
+** Clear all of the content from a cursor.
+*/
+static void spellfix1ResetCursor(spellfix1_cursor *pCur){
+ int i;
+ for(i=0; i<pCur->nRow; i++){
+ sqlite3_free(pCur->a[i].zWord);
+ }
+ pCur->nRow = 0;
+ pCur->iRow = 0;
+ pCur->nSearch = 0;
+ if( pCur->pFullScan ){
+ sqlite3_finalize(pCur->pFullScan);
+ pCur->pFullScan = 0;
+ }
+}
+
+/*
+** Resize the cursor to hold up to N rows of content
+*/
+static void spellfix1ResizeCursor(spellfix1_cursor *pCur, int N){
+ struct spellfix1_row *aNew;
+ assert( N>=pCur->nRow );
+ aNew = sqlite3_realloc(pCur->a, sizeof(pCur->a[0])*N);
+ if( aNew==0 && N>0 ){
+ spellfix1ResetCursor(pCur);
+ sqlite3_free(pCur->a);
+ pCur->nAlloc = 0;
+ pCur->a = 0;
+ }else{
+ pCur->nAlloc = N;
+ pCur->a = aNew;
+ }
+}
+
+
+/*
+** Close a fuzzy-search cursor.
+*/
+static int spellfix1Close(sqlite3_vtab_cursor *cur){
+ spellfix1_cursor *pCur = (spellfix1_cursor *)cur;
+ spellfix1ResetCursor(pCur);
+ spellfix1ResizeCursor(pCur, 0);
+ sqlite3_free(pCur->zPattern);
+ sqlite3_free(pCur);
+ return SQLITE_OK;
+}
+
+#define SPELLFIX_IDXNUM_MATCH 0x01 /* word MATCH $str */
+#define SPELLFIX_IDXNUM_LANGID 0x02 /* langid == $langid */
+#define SPELLFIX_IDXNUM_TOP 0x04 /* top = $top */
+#define SPELLFIX_IDXNUM_SCOPE 0x08 /* scope = $scope */
+#define SPELLFIX_IDXNUM_DISTLT 0x10 /* distance < $distance */
+#define SPELLFIX_IDXNUM_DISTLE 0x20 /* distance <= $distance */
+#define SPELLFIX_IDXNUM_ROWID 0x40 /* rowid = $rowid */
+#define SPELLFIX_IDXNUM_DIST (0x10|0x20) /* DISTLT and DISTLE */
+
+/*
+**
+** The plan number is a bitmask of the SPELLFIX_IDXNUM_* values defined
+** above.
+**
+** filter.argv[*] values contains $str, $langid, $top, $scope and $rowid
+** if specified and in that order.
+*/
+static int spellfix1BestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+ int iPlan = 0;
+ int iLangTerm = -1;
+ int iTopTerm = -1;
+ int iScopeTerm = -1;
+ int iDistTerm = -1;
+ int iRowidTerm = -1;
+ int i;
+ const struct sqlite3_index_constraint *pConstraint;
+ pConstraint = pIdxInfo->aConstraint;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
+ if( pConstraint->usable==0 ) continue;
+
+ /* Terms of the form: word MATCH $str */
+ if( (iPlan & SPELLFIX_IDXNUM_MATCH)==0
+ && pConstraint->iColumn==SPELLFIX_COL_WORD
+ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH
+ ){
+ iPlan |= SPELLFIX_IDXNUM_MATCH;
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ }
+
+ /* Terms of the form: langid = $langid */
+ if( (iPlan & SPELLFIX_IDXNUM_LANGID)==0
+ && pConstraint->iColumn==SPELLFIX_COL_LANGID
+ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
+ ){
+ iPlan |= SPELLFIX_IDXNUM_LANGID;
+ iLangTerm = i;
+ }
+
+ /* Terms of the form: top = $top */
+ if( (iPlan & SPELLFIX_IDXNUM_TOP)==0
+ && pConstraint->iColumn==SPELLFIX_COL_TOP
+ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
+ ){
+ iPlan |= SPELLFIX_IDXNUM_TOP;
+ iTopTerm = i;
+ }
+
+ /* Terms of the form: scope = $scope */
+ if( (iPlan & SPELLFIX_IDXNUM_SCOPE)==0
+ && pConstraint->iColumn==SPELLFIX_COL_SCOPE
+ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
+ ){
+ iPlan |= SPELLFIX_IDXNUM_SCOPE;
+ iScopeTerm = i;
+ }
+
+ /* Terms of the form: distance < $dist or distance <= $dist */
+ if( (iPlan & SPELLFIX_IDXNUM_DIST)==0
+ && pConstraint->iColumn==SPELLFIX_COL_DISTANCE
+ && (pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT
+ || pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE)
+ ){
+ if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ){
+ iPlan |= SPELLFIX_IDXNUM_DISTLT;
+ }else{
+ iPlan |= SPELLFIX_IDXNUM_DISTLE;
+ }
+ iDistTerm = i;
+ }
+
+ /* Terms of the form: distance < $dist or distance <= $dist */
+ if( (iPlan & SPELLFIX_IDXNUM_ROWID)==0
+ && pConstraint->iColumn<0
+ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
+ ){
+ iPlan |= SPELLFIX_IDXNUM_ROWID;
+ iRowidTerm = i;
+ }
+ }
+ if( iPlan&SPELLFIX_IDXNUM_MATCH ){
+ int idx = 2;
+ pIdxInfo->idxNum = iPlan;
+ if( pIdxInfo->nOrderBy==1
+ && pIdxInfo->aOrderBy[0].iColumn==SPELLFIX_COL_SCORE
+ && pIdxInfo->aOrderBy[0].desc==0
+ ){
+ pIdxInfo->orderByConsumed = 1; /* Default order by iScore */
+ }
+ if( iPlan&SPELLFIX_IDXNUM_LANGID ){
+ pIdxInfo->aConstraintUsage[iLangTerm].argvIndex = idx++;
+ pIdxInfo->aConstraintUsage[iLangTerm].omit = 1;
+ }
+ if( iPlan&SPELLFIX_IDXNUM_TOP ){
+ pIdxInfo->aConstraintUsage[iTopTerm].argvIndex = idx++;
+ pIdxInfo->aConstraintUsage[iTopTerm].omit = 1;
+ }
+ if( iPlan&SPELLFIX_IDXNUM_SCOPE ){
+ pIdxInfo->aConstraintUsage[iScopeTerm].argvIndex = idx++;
+ pIdxInfo->aConstraintUsage[iScopeTerm].omit = 1;
+ }
+ if( iPlan&SPELLFIX_IDXNUM_DIST ){
+ pIdxInfo->aConstraintUsage[iDistTerm].argvIndex = idx++;
+ pIdxInfo->aConstraintUsage[iDistTerm].omit = 1;
+ }
+ pIdxInfo->estimatedCost = 1e5;
+ }else if( (iPlan & SPELLFIX_IDXNUM_ROWID) ){
+ pIdxInfo->idxNum = SPELLFIX_IDXNUM_ROWID;
+ pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1;
+ pIdxInfo->estimatedCost = 5;
+ }else{
+ pIdxInfo->idxNum = 0;
+ pIdxInfo->estimatedCost = 1e50;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Open a new fuzzy-search cursor.
+*/
+static int spellfix1Open(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+ spellfix1_vtab *p = (spellfix1_vtab*)pVTab;
+ spellfix1_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ pCur->pVTab = p;
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Adjust a distance measurement by the words rank in order to show
+** preference to common words.
+*/
+static int spellfix1Score(int iDistance, int iRank){
+ int iLog2;
+ for(iLog2=0; iRank>0; iLog2++, iRank>>=1){}
+ return iDistance + 32 - iLog2;
+}
+
+/*
+** Compare two spellfix1_row objects for sorting purposes in qsort() such
+** that they sort in order of increasing distance.
+*/
+static int SQLITE_CDECL spellfix1RowCompare(const void *A, const void *B){
+ const struct spellfix1_row *a = (const struct spellfix1_row*)A;
+ const struct spellfix1_row *b = (const struct spellfix1_row*)B;
+ return a->iScore - b->iScore;
+}
+
+/*
+** A structure used to pass information from spellfix1FilterForMatch()
+** into spellfix1RunQuery().
+*/
+typedef struct MatchQuery {
+ spellfix1_cursor *pCur; /* The cursor being queried */
+ sqlite3_stmt *pStmt; /* shadow table query statment */
+ char zHash[SPELLFIX_MX_HASH]; /* The current phonehash for zPattern */
+ const char *zPattern; /* Transliterated input string */
+ int nPattern; /* Length of zPattern */
+ EditDist3FromString *pMatchStr3; /* Original unicode string */
+ EditDist3Config *pConfig3; /* Edit-distance cost coefficients */
+ const EditDist3Lang *pLang; /* The selected language coefficients */
+ int iLang; /* The language id */
+ int iScope; /* Default scope */
+ int iMaxDist; /* Maximum allowed edit distance, or -1 */
+ int rc; /* Error code */
+ int nRun; /* Number of prior runs for the same zPattern */
+ char azPrior[SPELLFIX_MX_RUN][SPELLFIX_MX_HASH]; /* Prior hashes */
+} MatchQuery;
+
+/*
+** Run a query looking for the best matches against zPattern using
+** zHash as the character class seed hash.
+*/
+static void spellfix1RunQuery(MatchQuery *p, const char *zQuery, int nQuery){
+ const char *zK1;
+ const char *zWord;
+ int iDist;
+ int iRank;
+ int iScore;
+ int iWorst = 0;
+ int idx;
+ int idxWorst = -1;
+ int i;
+ int iScope = p->iScope;
+ spellfix1_cursor *pCur = p->pCur;
+ sqlite3_stmt *pStmt = p->pStmt;
+ char zHash1[SPELLFIX_MX_HASH];
+ char zHash2[SPELLFIX_MX_HASH];
+ char *zClass;
+ int nClass;
+ int rc;
+
+ if( pCur->a==0 || p->rc ) return; /* Prior memory allocation failure */
+ zClass = (char*)phoneticHash((unsigned char*)zQuery, nQuery);
+ if( zClass==0 ){
+ p->rc = SQLITE_NOMEM;
+ return;
+ }
+ nClass = (int)strlen(zClass);
+ if( nClass>SPELLFIX_MX_HASH-2 ){
+ nClass = SPELLFIX_MX_HASH-2;
+ zClass[nClass] = 0;
+ }
+ if( nClass<=iScope ){
+ if( nClass>2 ){
+ iScope = nClass-1;
+ }else{
+ iScope = nClass;
+ }
+ }
+ memcpy(zHash1, zClass, iScope);
+ sqlite3_free(zClass);
+ zHash1[iScope] = 0;
+ memcpy(zHash2, zHash1, iScope);
+ zHash2[iScope] = 'Z';
+ zHash2[iScope+1] = 0;
+#if SPELLFIX_MX_RUN>1
+ for(i=0; i<p->nRun; i++){
+ if( strcmp(p->azPrior[i], zHash1)==0 ) return;
+ }
+#endif
+ assert( p->nRun<SPELLFIX_MX_RUN );
+ memcpy(p->azPrior[p->nRun++], zHash1, iScope+1);
+ if( sqlite3_bind_text(pStmt, 1, zHash1, -1, SQLITE_STATIC)==SQLITE_NOMEM
+ || sqlite3_bind_text(pStmt, 2, zHash2, -1, SQLITE_STATIC)==SQLITE_NOMEM
+ ){
+ p->rc = SQLITE_NOMEM;
+ return;
+ }
+#if SPELLFIX_MX_RUN>1
+ for(i=0; i<pCur->nRow; i++){
+ if( pCur->a[i].iScore>iWorst ){
+ iWorst = pCur->a[i].iScore;
+ idxWorst = i;
+ }
+ }
+#endif
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ int iMatchlen = -1;
+ iRank = sqlite3_column_int(pStmt, 2);
+ if( p->pMatchStr3 ){
+ int nWord = sqlite3_column_bytes(pStmt, 1);
+ zWord = (const char*)sqlite3_column_text(pStmt, 1);
+ iDist = editDist3Core(p->pMatchStr3, zWord, nWord, p->pLang, &iMatchlen);
+ }else{
+ zK1 = (const char*)sqlite3_column_text(pStmt, 3);
+ if( zK1==0 ) continue;
+ iDist = editdist1(p->zPattern, zK1, 0);
+ }
+ if( iDist<0 ){
+ p->rc = SQLITE_NOMEM;
+ break;
+ }
+ pCur->nSearch++;
+
+ /* If there is a "distance < $dist" or "distance <= $dist" constraint,
+ ** check if this row meets it. If not, jump back up to the top of the
+ ** loop to process the next row. Otherwise, if the row does match the
+ ** distance constraint, check if the pCur->a[] array is already full.
+ ** If it is and no explicit "top = ?" constraint was present in the
+ ** query, grow the array to ensure there is room for the new entry. */
+ assert( (p->iMaxDist>=0)==((pCur->idxNum & SPELLFIX_IDXNUM_DIST) ? 1 : 0) );
+ if( p->iMaxDist>=0 ){
+ if( iDist>p->iMaxDist ) continue;
+ if( pCur->nRow>=pCur->nAlloc && (pCur->idxNum & SPELLFIX_IDXNUM_TOP)==0 ){
+ spellfix1ResizeCursor(pCur, pCur->nAlloc*2 + 10);
+ if( pCur->a==0 ) break;
+ }
+ }
+
+ iScore = spellfix1Score(iDist,iRank);
+ if( pCur->nRow<pCur->nAlloc ){
+ idx = pCur->nRow;
+ }else if( iScore<iWorst ){
+ idx = idxWorst;
+ sqlite3_free(pCur->a[idx].zWord);
+ }else{
+ continue;
+ }
+
+ pCur->a[idx].zWord = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
+ if( pCur->a[idx].zWord==0 ){
+ p->rc = SQLITE_NOMEM;
+ break;
+ }
+ pCur->a[idx].iRowid = sqlite3_column_int64(pStmt, 0);
+ pCur->a[idx].iRank = iRank;
+ pCur->a[idx].iDistance = iDist;
+ pCur->a[idx].iScore = iScore;
+ pCur->a[idx].iMatchlen = iMatchlen;
+ memcpy(pCur->a[idx].zHash, zHash1, iScope+1);
+ if( pCur->nRow<pCur->nAlloc ) pCur->nRow++;
+ if( pCur->nRow==pCur->nAlloc ){
+ iWorst = pCur->a[0].iScore;
+ idxWorst = 0;
+ for(i=1; i<pCur->nRow; i++){
+ iScore = pCur->a[i].iScore;
+ if( iWorst<iScore ){
+ iWorst = iScore;
+ idxWorst = i;
+ }
+ }
+ }
+ }
+ rc = sqlite3_reset(pStmt);
+ if( rc ) p->rc = rc;
+}
+
+/*
+** This version of the xFilter method work if the MATCH term is present
+** and we are doing a scan.
+*/
+static int spellfix1FilterForMatch(
+ spellfix1_cursor *pCur,
+ int argc,
+ sqlite3_value **argv
+){
+ int idxNum = pCur->idxNum;
+ const unsigned char *zMatchThis; /* RHS of the MATCH operator */
+ EditDist3FromString *pMatchStr3 = 0; /* zMatchThis as an editdist string */
+ char *zPattern; /* Transliteration of zMatchThis */
+ int nPattern; /* Length of zPattern */
+ int iLimit = 20; /* Max number of rows of output */
+ int iScope = 3; /* Use this many characters of zClass */
+ int iLang = 0; /* Language code */
+ char *zSql; /* SQL of shadow table query */
+ sqlite3_stmt *pStmt = 0; /* Shadow table query */
+ int rc; /* Result code */
+ int idx = 1; /* Next available filter parameter */
+ spellfix1_vtab *p = pCur->pVTab; /* The virtual table that owns pCur */
+ MatchQuery x; /* For passing info to RunQuery() */
+
+ /* Load the cost table if we have not already done so */
+ if( p->zCostTable!=0 && p->pConfig3==0 ){
+ p->pConfig3 = sqlite3_malloc( sizeof(p->pConfig3[0]) );
+ if( p->pConfig3==0 ) return SQLITE_NOMEM;
+ memset(p->pConfig3, 0, sizeof(p->pConfig3[0]));
+ rc = editDist3ConfigLoad(p->pConfig3, p->db, p->zCostTable);
+ if( rc ) return rc;
+ }
+ memset(&x, 0, sizeof(x));
+ x.iScope = 3; /* Default scope if none specified by "WHERE scope=N" */
+ x.iMaxDist = -1; /* Maximum allowed edit distance */
+
+ if( idxNum&2 ){
+ iLang = sqlite3_value_int(argv[idx++]);
+ }
+ if( idxNum&4 ){
+ iLimit = sqlite3_value_int(argv[idx++]);
+ if( iLimit<1 ) iLimit = 1;
+ }
+ if( idxNum&8 ){
+ x.iScope = sqlite3_value_int(argv[idx++]);
+ if( x.iScope<1 ) x.iScope = 1;
+ if( x.iScope>SPELLFIX_MX_HASH-2 ) x.iScope = SPELLFIX_MX_HASH-2;
+ }
+ if( idxNum&(16|32) ){
+ x.iMaxDist = sqlite3_value_int(argv[idx++]);
+ if( idxNum&16 ) x.iMaxDist--;
+ if( x.iMaxDist<0 ) x.iMaxDist = 0;
+ }
+ spellfix1ResetCursor(pCur);
+ spellfix1ResizeCursor(pCur, iLimit);
+ zMatchThis = sqlite3_value_text(argv[0]);
+ if( zMatchThis==0 ) return SQLITE_OK;
+ if( p->pConfig3 ){
+ x.pLang = editDist3FindLang(p->pConfig3, iLang);
+ pMatchStr3 = editDist3FromStringNew(x.pLang, (const char*)zMatchThis, -1);
+ if( pMatchStr3==0 ){
+ x.rc = SQLITE_NOMEM;
+ goto filter_exit;
+ }
+ }else{
+ x.pLang = 0;
+ }
+ zPattern = (char*)transliterate(zMatchThis, sqlite3_value_bytes(argv[0]));
+ sqlite3_free(pCur->zPattern);
+ pCur->zPattern = zPattern;
+ if( zPattern==0 ){
+ x.rc = SQLITE_NOMEM;
+ goto filter_exit;
+ }
+ nPattern = (int)strlen(zPattern);
+ if( zPattern[nPattern-1]=='*' ) nPattern--;
+ zSql = sqlite3_mprintf(
+ "SELECT id, word, rank, coalesce(k1,word)"
+ " FROM \"%w\".\"%w_vocab\""
+ " WHERE langid=%d AND k2>=?1 AND k2<?2",
+ p->zDbName, p->zTableName, iLang
+ );
+ if( zSql==0 ){
+ x.rc = SQLITE_NOMEM;
+ pStmt = 0;
+ goto filter_exit;
+ }
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ pCur->iLang = iLang;
+ x.pCur = pCur;
+ x.pStmt = pStmt;
+ x.zPattern = zPattern;
+ x.nPattern = nPattern;
+ x.pMatchStr3 = pMatchStr3;
+ x.iLang = iLang;
+ x.rc = rc;
+ x.pConfig3 = p->pConfig3;
+ if( x.rc==SQLITE_OK ){
+ spellfix1RunQuery(&x, zPattern, nPattern);
+ }
+
+ if( pCur->a ){
+ qsort(pCur->a, pCur->nRow, sizeof(pCur->a[0]), spellfix1RowCompare);
+ pCur->iTop = iLimit;
+ pCur->iScope = iScope;
+ }else{
+ x.rc = SQLITE_NOMEM;
+ }
+
+filter_exit:
+ sqlite3_finalize(pStmt);
+ editDist3FromStringDelete(pMatchStr3);
+ return x.rc;
+}
+
+/*
+** This version of xFilter handles a full-table scan case
+*/
+static int spellfix1FilterForFullScan(
+ spellfix1_cursor *pCur,
+ int argc,
+ sqlite3_value **argv
+){
+ int rc = SQLITE_OK;
+ int idxNum = pCur->idxNum;
+ char *zSql;
+ spellfix1_vtab *pVTab = pCur->pVTab;
+ spellfix1ResetCursor(pCur);
+ assert( idxNum==0 || idxNum==64 );
+ zSql = sqlite3_mprintf(
+ "SELECT word, rank, NULL, langid, id FROM \"%w\".\"%w_vocab\"%s",
+ pVTab->zDbName, pVTab->zTableName,
+ ((idxNum & 64) ? " WHERE rowid=?" : "")
+ );
+ if( zSql==0 ) return SQLITE_NOMEM;
+ rc = sqlite3_prepare_v2(pVTab->db, zSql, -1, &pCur->pFullScan, 0);
+ sqlite3_free(zSql);
+ if( rc==SQLITE_OK && (idxNum & 64) ){
+ assert( argc==1 );
+ rc = sqlite3_bind_value(pCur->pFullScan, 1, argv[0]);
+ }
+ pCur->nRow = pCur->iRow = 0;
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_step(pCur->pFullScan);
+ if( rc==SQLITE_ROW ){ pCur->iRow = -1; rc = SQLITE_OK; }
+ if( rc==SQLITE_DONE ){ rc = SQLITE_OK; }
+ }else{
+ pCur->iRow = 0;
+ }
+ return rc;
+}
+
+
+/*
+** Called to "rewind" a cursor back to the beginning so that
+** it starts its output over again. Always called at least once
+** prior to any spellfix1Column, spellfix1Rowid, or spellfix1Eof call.
+*/
+static int spellfix1Filter(
+ sqlite3_vtab_cursor *cur,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ spellfix1_cursor *pCur = (spellfix1_cursor *)cur;
+ int rc;
+ pCur->idxNum = idxNum;
+ if( idxNum & 1 ){
+ rc = spellfix1FilterForMatch(pCur, argc, argv);
+ }else{
+ rc = spellfix1FilterForFullScan(pCur, argc, argv);
+ }
+ return rc;
+}
+
+
+/*
+** Advance a cursor to its next row of output
+*/
+static int spellfix1Next(sqlite3_vtab_cursor *cur){
+ spellfix1_cursor *pCur = (spellfix1_cursor *)cur;
+ int rc = SQLITE_OK;
+ if( pCur->iRow < pCur->nRow ){
+ if( pCur->pFullScan ){
+ rc = sqlite3_step(pCur->pFullScan);
+ if( rc!=SQLITE_ROW ) pCur->iRow = pCur->nRow;
+ if( rc==SQLITE_ROW || rc==SQLITE_DONE ) rc = SQLITE_OK;
+ }else{
+ pCur->iRow++;
+ }
+ }
+ return rc;
+}
+
+/*
+** Return TRUE if we are at the end-of-file
+*/
+static int spellfix1Eof(sqlite3_vtab_cursor *cur){
+ spellfix1_cursor *pCur = (spellfix1_cursor *)cur;
+ return pCur->iRow>=pCur->nRow;
+}
+
+/*
+** Return columns from the current row.
+*/
+static int spellfix1Column(
+ sqlite3_vtab_cursor *cur,
+ sqlite3_context *ctx,
+ int i
+){
+ spellfix1_cursor *pCur = (spellfix1_cursor*)cur;
+ if( pCur->pFullScan ){
+ if( i<=SPELLFIX_COL_LANGID ){
+ sqlite3_result_value(ctx, sqlite3_column_value(pCur->pFullScan, i));
+ }else{
+ sqlite3_result_null(ctx);
+ }
+ return SQLITE_OK;
+ }
+ switch( i ){
+ case SPELLFIX_COL_WORD: {
+ sqlite3_result_text(ctx, pCur->a[pCur->iRow].zWord, -1, SQLITE_STATIC);
+ break;
+ }
+ case SPELLFIX_COL_RANK: {
+ sqlite3_result_int(ctx, pCur->a[pCur->iRow].iRank);
+ break;
+ }
+ case SPELLFIX_COL_DISTANCE: {
+ sqlite3_result_int(ctx, pCur->a[pCur->iRow].iDistance);
+ break;
+ }
+ case SPELLFIX_COL_LANGID: {
+ sqlite3_result_int(ctx, pCur->iLang);
+ break;
+ }
+ case SPELLFIX_COL_SCORE: {
+ sqlite3_result_int(ctx, pCur->a[pCur->iRow].iScore);
+ break;
+ }
+ case SPELLFIX_COL_MATCHLEN: {
+ int iMatchlen = pCur->a[pCur->iRow].iMatchlen;
+ if( iMatchlen<0 ){
+ int nPattern = (int)strlen(pCur->zPattern);
+ char *zWord = pCur->a[pCur->iRow].zWord;
+ int nWord = (int)strlen(zWord);
+
+ if( nPattern>0 && pCur->zPattern[nPattern-1]=='*' ){
+ char *zTranslit;
+ int res;
+ zTranslit = (char *)transliterate((unsigned char *)zWord, nWord);
+ if( !zTranslit ) return SQLITE_NOMEM;
+ res = editdist1(pCur->zPattern, zTranslit, &iMatchlen);
+ sqlite3_free(zTranslit);
+ if( res<0 ) return SQLITE_NOMEM;
+ iMatchlen = translen_to_charlen(zWord, nWord, iMatchlen);
+ }else{
+ iMatchlen = utf8Charlen(zWord, nWord);
+ }
+ }
+
+ sqlite3_result_int(ctx, iMatchlen);
+ break;
+ }
+ case SPELLFIX_COL_PHONEHASH: {
+ sqlite3_result_text(ctx, pCur->a[pCur->iRow].zHash, -1, SQLITE_STATIC);
+ break;
+ }
+ case SPELLFIX_COL_TOP: {
+ sqlite3_result_int(ctx, pCur->iTop);
+ break;
+ }
+ case SPELLFIX_COL_SCOPE: {
+ sqlite3_result_int(ctx, pCur->iScope);
+ break;
+ }
+ case SPELLFIX_COL_SRCHCNT: {
+ sqlite3_result_int(ctx, pCur->nSearch);
+ break;
+ }
+ default: {
+ sqlite3_result_null(ctx);
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** The rowid.
+*/
+static int spellfix1Rowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ spellfix1_cursor *pCur = (spellfix1_cursor*)cur;
+ if( pCur->pFullScan ){
+ *pRowid = sqlite3_column_int64(pCur->pFullScan, 4);
+ }else{
+ *pRowid = pCur->a[pCur->iRow].iRowid;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** This function is called by the xUpdate() method. It returns a string
+** containing the conflict mode that xUpdate() should use for the current
+** operation. One of: "ROLLBACK", "IGNORE", "ABORT" or "REPLACE".
+*/
+static const char *spellfix1GetConflict(sqlite3 *db){
+ static const char *const azConflict[] = {
+ /* Note: Instead of "FAIL" - "ABORT". */
+ "ROLLBACK", "IGNORE", "ABORT", "ABORT", "REPLACE"
+ };
+ int eConflict = sqlite3_vtab_on_conflict(db);
+
+ assert( eConflict==SQLITE_ROLLBACK || eConflict==SQLITE_IGNORE
+ || eConflict==SQLITE_FAIL || eConflict==SQLITE_ABORT
+ || eConflict==SQLITE_REPLACE
+ );
+ assert( SQLITE_ROLLBACK==1 );
+ assert( SQLITE_IGNORE==2 );
+ assert( SQLITE_FAIL==3 );
+ assert( SQLITE_ABORT==4 );
+ assert( SQLITE_REPLACE==5 );
+
+ return azConflict[eConflict-1];
+}
+
+/*
+** The xUpdate() method.
+*/
+static int spellfix1Update(
+ sqlite3_vtab *pVTab,
+ int argc,
+ sqlite3_value **argv,
+ sqlite_int64 *pRowid
+){
+ int rc = SQLITE_OK;
+ sqlite3_int64 rowid, newRowid;
+ spellfix1_vtab *p = (spellfix1_vtab*)pVTab;
+ sqlite3 *db = p->db;
+
+ if( argc==1 ){
+ /* A delete operation on the rowid given by argv[0] */
+ rowid = *pRowid = sqlite3_value_int64(argv[0]);
+ spellfix1DbExec(&rc, db, "DELETE FROM \"%w\".\"%w_vocab\" "
+ " WHERE id=%lld",
+ p->zDbName, p->zTableName, rowid);
+ }else{
+ const unsigned char *zWord = sqlite3_value_text(argv[SPELLFIX_COL_WORD+2]);
+ int nWord = sqlite3_value_bytes(argv[SPELLFIX_COL_WORD+2]);
+ int iLang = sqlite3_value_int(argv[SPELLFIX_COL_LANGID+2]);
+ int iRank = sqlite3_value_int(argv[SPELLFIX_COL_RANK+2]);
+ const unsigned char *zSoundslike =
+ sqlite3_value_text(argv[SPELLFIX_COL_SOUNDSLIKE+2]);
+ int nSoundslike = sqlite3_value_bytes(argv[SPELLFIX_COL_SOUNDSLIKE+2]);
+ char *zK1, *zK2;
+ int i;
+ char c;
+ const char *zConflict = spellfix1GetConflict(db);
+
+ if( zWord==0 ){
+ /* Inserts of the form: INSERT INTO table(command) VALUES('xyzzy');
+ ** cause zWord to be NULL, so we look at the "command" column to see
+ ** what special actions to take */
+ const char *zCmd =
+ (const char*)sqlite3_value_text(argv[SPELLFIX_COL_COMMAND+2]);
+ if( zCmd==0 ){
+ pVTab->zErrMsg = sqlite3_mprintf("NOT NULL constraint failed: %s.word",
+ p->zTableName);
+ return SQLITE_CONSTRAINT_NOTNULL;
+ }
+ if( strcmp(zCmd,"reset")==0 ){
+ /* Reset the edit cost table (if there is one). */
+ editDist3ConfigDelete(p->pConfig3);
+ p->pConfig3 = 0;
+ return SQLITE_OK;
+ }
+ if( strncmp(zCmd,"edit_cost_table=",16)==0 ){
+ editDist3ConfigDelete(p->pConfig3);
+ p->pConfig3 = 0;
+ sqlite3_free(p->zCostTable);
+ p->zCostTable = spellfix1Dequote(zCmd+16);
+ if( p->zCostTable==0 ) return SQLITE_NOMEM;
+ if( p->zCostTable[0]==0 || sqlite3_stricmp(p->zCostTable,"null")==0 ){
+ sqlite3_free(p->zCostTable);
+ p->zCostTable = 0;
+ }
+ return SQLITE_OK;
+ }
+ pVTab->zErrMsg = sqlite3_mprintf("unknown value for %s.command: \"%w\"",
+ p->zTableName, zCmd);
+ return SQLITE_ERROR;
+ }
+ if( iRank<1 ) iRank = 1;
+ if( zSoundslike ){
+ zK1 = (char*)transliterate(zSoundslike, nSoundslike);
+ }else{
+ zK1 = (char*)transliterate(zWord, nWord);
+ }
+ if( zK1==0 ) return SQLITE_NOMEM;
+ for(i=0; (c = zK1[i])!=0; i++){
+ if( c>='A' && c<='Z' ) zK1[i] += 'a' - 'A';
+ }
+ zK2 = (char*)phoneticHash((const unsigned char*)zK1, i);
+ if( zK2==0 ){
+ sqlite3_free(zK1);
+ return SQLITE_NOMEM;
+ }
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
+ if( sqlite3_value_type(argv[1])==SQLITE_NULL ){
+ spellfix1DbExec(&rc, db,
+ "INSERT INTO \"%w\".\"%w_vocab\"(rank,langid,word,k1,k2) "
+ "VALUES(%d,%d,%Q,nullif(%Q,%Q),%Q)",
+ p->zDbName, p->zTableName,
+ iRank, iLang, zWord, zK1, zWord, zK2
+ );
+ }else{
+ newRowid = sqlite3_value_int64(argv[1]);
+ spellfix1DbExec(&rc, db,
+ "INSERT OR %s INTO \"%w\".\"%w_vocab\"(id,rank,langid,word,k1,k2) "
+ "VALUES(%lld,%d,%d,%Q,nullif(%Q,%Q),%Q)",
+ zConflict, p->zDbName, p->zTableName,
+ newRowid, iRank, iLang, zWord, zK1, zWord, zK2
+ );
+ }
+ *pRowid = sqlite3_last_insert_rowid(db);
+ }else{
+ rowid = sqlite3_value_int64(argv[0]);
+ newRowid = *pRowid = sqlite3_value_int64(argv[1]);
+ spellfix1DbExec(&rc, db,
+ "UPDATE OR %s \"%w\".\"%w_vocab\" SET id=%lld, rank=%d, langid=%d,"
+ " word=%Q, k1=nullif(%Q,%Q), k2=%Q WHERE id=%lld",
+ zConflict, p->zDbName, p->zTableName, newRowid, iRank, iLang,
+ zWord, zK1, zWord, zK2, rowid
+ );
+ }
+ sqlite3_free(zK1);
+ sqlite3_free(zK2);
+ }
+ return rc;
+}
+
+/*
+** Rename the spellfix1 table.
+*/
+static int spellfix1Rename(sqlite3_vtab *pVTab, const char *zNew){
+ spellfix1_vtab *p = (spellfix1_vtab*)pVTab;
+ sqlite3 *db = p->db;
+ int rc = SQLITE_OK;
+ char *zNewName = sqlite3_mprintf("%s", zNew);
+ if( zNewName==0 ){
+ return SQLITE_NOMEM;
+ }
+ spellfix1DbExec(&rc, db,
+ "ALTER TABLE \"%w\".\"%w_vocab\" RENAME TO \"%w_vocab\"",
+ p->zDbName, p->zTableName, zNewName
+ );
+ if( rc==SQLITE_OK ){
+ sqlite3_free(p->zTableName);
+ p->zTableName = zNewName;
+ }else{
+ sqlite3_free(zNewName);
+ }
+ return rc;
+}
+
+
+/*
+** A virtual table module that provides fuzzy search.
+*/
+static const sqlite3_module spellfix1Module = {
+ 0, /* iVersion */
+ spellfix1Create, /* xCreate - handle CREATE VIRTUAL TABLE */
+ spellfix1Connect, /* xConnect - reconnected to an existing table */
+ spellfix1BestIndex, /* xBestIndex - figure out how to do a query */
+ spellfix1Disconnect, /* xDisconnect - close a connection */
+ spellfix1Destroy, /* xDestroy - handle DROP TABLE */
+ spellfix1Open, /* xOpen - open a cursor */
+ spellfix1Close, /* xClose - close a cursor */
+ spellfix1Filter, /* xFilter - configure scan constraints */
+ spellfix1Next, /* xNext - advance a cursor */
+ spellfix1Eof, /* xEof - check for end of scan */
+ spellfix1Column, /* xColumn - read data */
+ spellfix1Rowid, /* xRowid - read data */
+ spellfix1Update, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ spellfix1Rename, /* xRename */
+};
+
+/*
+** Register the various functions and the virtual table.
+*/
+static int spellfix1Register(sqlite3 *db){
+ int rc = SQLITE_OK;
+ int i;
+ rc = sqlite3_create_function(db, "spellfix1_translit", 1,
+ SQLITE_UTF8|SQLITE_DETERMINISTIC, 0,
+ transliterateSqlFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "spellfix1_editdist", 2,
+ SQLITE_UTF8|SQLITE_DETERMINISTIC, 0,
+ editdistSqlFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "spellfix1_phonehash", 1,
+ SQLITE_UTF8|SQLITE_DETERMINISTIC, 0,
+ phoneticHashSqlFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "spellfix1_scriptcode", 1,
+ SQLITE_UTF8|SQLITE_DETERMINISTIC, 0,
+ scriptCodeSqlFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_module(db, "spellfix1", &spellfix1Module, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = editDist3Install(db);
+ }
+
+ /* Verify sanity of the translit[] table */
+ for(i=0; i<sizeof(translit)/sizeof(translit[0])-1; i++){
+ assert( translit[i].cFrom<translit[i+1].cFrom );
+ }
+
+ return rc;
+}
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+/*
+** Extension load function.
+*/
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_spellfix_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ return spellfix1Register(db);
+#endif
+ return SQLITE_OK;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ return sqlite3_spellfix_init(db, pzErrMsg, pApi);
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/sqlar.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/sqlar.c 2019-10-08 13:42:19.221844800 +0200
@@ -0,0 +1,121 @@
+/*
+** 2017-12-17
+**
+** 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.
+**
+******************************************************************************
+**
+** Utility functions sqlar_compress() and sqlar_uncompress(). Useful
+** for working with sqlar archives and used by the shell tool's built-in
+** sqlar support.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <zlib.h>
+
+/*
+** Implementation of the "sqlar_compress(X)" SQL function.
+**
+** If the type of X is SQLITE_BLOB, and compressing that blob using
+** zlib utility function compress() yields a smaller blob, return the
+** compressed blob. Otherwise, return a copy of X.
+**
+** SQLar uses the "zlib format" for compressed content. The zlib format
+** contains a two-byte identification header and a four-byte checksum at
+** the end. This is different from ZIP which uses the raw deflate format.
+**
+** Future enhancements to SQLar might add support for new compression formats.
+** If so, those new formats will be identified by alternative headers in the
+** compressed data.
+*/
+static void sqlarCompressFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ assert( argc==1 );
+ if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
+ const Bytef *pData = sqlite3_value_blob(argv[0]);
+ uLong nData = sqlite3_value_bytes(argv[0]);
+ uLongf nOut = compressBound(nData);
+ Bytef *pOut;
+
+ pOut = (Bytef*)sqlite3_malloc(nOut);
+ if( pOut==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }else{
+ if( Z_OK!=compress(pOut, &nOut, pData, nData) ){
+ sqlite3_result_error(context, "error in compress()", -1);
+ }else if( nOut<nData ){
+ sqlite3_result_blob(context, pOut, nOut, SQLITE_TRANSIENT);
+ }else{
+ sqlite3_result_value(context, argv[0]);
+ }
+ sqlite3_free(pOut);
+ }
+ }else{
+ sqlite3_result_value(context, argv[0]);
+ }
+}
+
+/*
+** Implementation of the "sqlar_uncompress(X,SZ)" SQL function
+**
+** Parameter SZ is interpreted as an integer. If it is less than or
+** equal to zero, then this function returns a copy of X. Or, if
+** SZ is equal to the size of X when interpreted as a blob, also
+** return a copy of X. Otherwise, decompress blob X using zlib
+** utility function uncompress() and return the results (another
+** blob).
+*/
+static void sqlarUncompressFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ uLong nData;
+ uLongf sz;
+
+ assert( argc==2 );
+ sz = sqlite3_value_int(argv[1]);
+
+ if( sz<=0 || sz==(nData = sqlite3_value_bytes(argv[0])) ){
+ sqlite3_result_value(context, argv[0]);
+ }else{
+ const Bytef *pData= sqlite3_value_blob(argv[0]);
+ Bytef *pOut = sqlite3_malloc(sz);
+ if( Z_OK!=uncompress(pOut, &sz, pData, nData) ){
+ sqlite3_result_error(context, "error in uncompress()", -1);
+ }else{
+ sqlite3_result_blob(context, pOut, sz, SQLITE_TRANSIENT);
+ }
+ sqlite3_free(pOut);
+ }
+}
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_sqlar_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "sqlar_compress", 1, SQLITE_UTF8, 0,
+ sqlarCompressFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "sqlar_uncompress", 2, SQLITE_UTF8, 0,
+ sqlarUncompressFunc, 0, 0);
+ }
+ return rc;
+}
--- origsrc/sqlite-autoconf-3300000/sqldiff.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/sqldiff.c 2019-03-05 13:14:40.864000000 +0100
@@ -0,0 +1,2006 @@
+/*
+** 2015-04-06
+**
+** 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 is a utility program that computes the differences in content
+** between two SQLite databases.
+**
+** To compile, simply link against SQLite.
+**
+** See the showHelp() routine below for a brief description of how to
+** run the utility.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+#include "sqlite3.h"
+
+/*
+** All global variables are gathered into the "g" singleton.
+*/
+struct GlobalVars {
+ const char *zArgv0; /* Name of program */
+ int bSchemaOnly; /* Only show schema differences */
+ int bSchemaPK; /* Use the schema-defined PK, not the true PK */
+ int bHandleVtab; /* Handle fts3, fts4, fts5 and rtree vtabs */
+ unsigned fDebug; /* Debug flags */
+ sqlite3 *db; /* The database connection */
+} g;
+
+/*
+** Allowed values for g.fDebug
+*/
+#define DEBUG_COLUMN_NAMES 0x000001
+#define DEBUG_DIFF_SQL 0x000002
+
+/*
+** Dynamic string object
+*/
+typedef struct Str Str;
+struct Str {
+ char *z; /* Text of the string */
+ int nAlloc; /* Bytes allocated in z[] */
+ int nUsed; /* Bytes actually used in z[] */
+};
+
+/*
+** Initialize a Str object
+*/
+static void strInit(Str *p){
+ p->z = 0;
+ p->nAlloc = 0;
+ p->nUsed = 0;
+}
+
+/*
+** Print an error resulting from faulting command-line arguments and
+** abort the program.
+*/
+static void cmdlineError(const char *zFormat, ...){
+ va_list ap;
+ fprintf(stderr, "%s: ", g.zArgv0);
+ va_start(ap, zFormat);
+ vfprintf(stderr, zFormat, ap);
+ va_end(ap);
+ fprintf(stderr, "\n\"%s --help\" for more help\n", g.zArgv0);
+ exit(1);
+}
+
+/*
+** Print an error message for an error that occurs at runtime, then
+** abort the program.
+*/
+static void runtimeError(const char *zFormat, ...){
+ va_list ap;
+ fprintf(stderr, "%s: ", g.zArgv0);
+ va_start(ap, zFormat);
+ vfprintf(stderr, zFormat, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+/*
+** Free all memory held by a Str object
+*/
+static void strFree(Str *p){
+ sqlite3_free(p->z);
+ strInit(p);
+}
+
+/*
+** Add formatted text to the end of a Str object
+*/
+static void strPrintf(Str *p, const char *zFormat, ...){
+ int nNew;
+ for(;;){
+ if( p->z ){
+ va_list ap;
+ va_start(ap, zFormat);
+ sqlite3_vsnprintf(p->nAlloc-p->nUsed, p->z+p->nUsed, zFormat, ap);
+ va_end(ap);
+ nNew = (int)strlen(p->z + p->nUsed);
+ }else{
+ nNew = p->nAlloc;
+ }
+ if( p->nUsed+nNew < p->nAlloc-1 ){
+ p->nUsed += nNew;
+ break;
+ }
+ p->nAlloc = p->nAlloc*2 + 1000;
+ p->z = sqlite3_realloc(p->z, p->nAlloc);
+ if( p->z==0 ) runtimeError("out of memory");
+ }
+}
+
+
+
+/* Safely quote an SQL identifier. Use the minimum amount of transformation
+** necessary to allow the string to be used with %s.
+**
+** Space to hold the returned string is obtained from sqlite3_malloc(). The
+** caller is responsible for ensuring this space is freed when no longer
+** needed.
+*/
+static char *safeId(const char *zId){
+ int i, x;
+ char c;
+ if( zId[0]==0 ) return sqlite3_mprintf("\"\"");
+ for(i=x=0; (c = zId[i])!=0; i++){
+ if( !isalpha(c) && c!='_' ){
+ if( i>0 && isdigit(c) ){
+ x++;
+ }else{
+ return sqlite3_mprintf("\"%w\"", zId);
+ }
+ }
+ }
+ if( x || !sqlite3_keyword_check(zId,i) ){
+ return sqlite3_mprintf("%s", zId);
+ }
+ return sqlite3_mprintf("\"%w\"", zId);
+}
+
+/*
+** Prepare a new SQL statement. Print an error and abort if anything
+** goes wrong.
+*/
+static sqlite3_stmt *db_vprepare(const char *zFormat, va_list ap){
+ char *zSql;
+ int rc;
+ sqlite3_stmt *pStmt;
+
+ zSql = sqlite3_vmprintf(zFormat, ap);
+ if( zSql==0 ) runtimeError("out of memory");
+ rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt, 0);
+ if( rc ){
+ runtimeError("SQL statement error: %s\n\"%s\"", sqlite3_errmsg(g.db),
+ zSql);
+ }
+ sqlite3_free(zSql);
+ return pStmt;
+}
+static sqlite3_stmt *db_prepare(const char *zFormat, ...){
+ va_list ap;
+ sqlite3_stmt *pStmt;
+ va_start(ap, zFormat);
+ pStmt = db_vprepare(zFormat, ap);
+ va_end(ap);
+ return pStmt;
+}
+
+/*
+** Free a list of strings
+*/
+static void namelistFree(char **az){
+ if( az ){
+ int i;
+ for(i=0; az[i]; i++) sqlite3_free(az[i]);
+ sqlite3_free(az);
+ }
+}
+
+/*
+** Return a list of column names for the table zDb.zTab. Space to
+** hold the list is obtained from sqlite3_malloc() and should released
+** using namelistFree() when no longer needed.
+**
+** Primary key columns are listed first, followed by data columns.
+** The number of columns in the primary key is returned in *pnPkey.
+**
+** Normally, the "primary key" in the previous sentence is the true
+** primary key - the rowid or INTEGER PRIMARY KEY for ordinary tables
+** or the declared PRIMARY KEY for WITHOUT ROWID tables. However, if
+** the g.bSchemaPK flag is set, then the schema-defined PRIMARY KEY is
+** used in all cases. In that case, entries that have NULL values in
+** any of their primary key fields will be excluded from the analysis.
+**
+** If the primary key for a table is the rowid but rowid is inaccessible,
+** then this routine returns a NULL pointer.
+**
+** Examples:
+** CREATE TABLE t1(a INT UNIQUE, b INTEGER, c TEXT, PRIMARY KEY(c));
+** *pnPKey = 1;
+** az = { "rowid", "a", "b", "c", 0 } // Normal case
+** az = { "c", "a", "b", 0 } // g.bSchemaPK==1
+**
+** CREATE TABLE t2(a INT UNIQUE, b INTEGER, c TEXT, PRIMARY KEY(b));
+** *pnPKey = 1;
+** az = { "b", "a", "c", 0 }
+**
+** CREATE TABLE t3(x,y,z,PRIMARY KEY(y,z));
+** *pnPKey = 1 // Normal case
+** az = { "rowid", "x", "y", "z", 0 } // Normal case
+** *pnPKey = 2 // g.bSchemaPK==1
+** az = { "y", "x", "z", 0 } // g.bSchemaPK==1
+**
+** CREATE TABLE t4(x,y,z,PRIMARY KEY(y,z)) WITHOUT ROWID;
+** *pnPKey = 2
+** az = { "y", "z", "x", 0 }
+**
+** CREATE TABLE t5(rowid,_rowid_,oid);
+** az = 0 // The rowid is not accessible
+*/
+static char **columnNames(
+ const char *zDb, /* Database ("main" or "aux") to query */
+ const char *zTab, /* Name of table to return details of */
+ int *pnPKey, /* OUT: Number of PK columns */
+ int *pbRowid /* OUT: True if PK is an implicit rowid */
+){
+ char **az = 0; /* List of column names to be returned */
+ int naz = 0; /* Number of entries in az[] */
+ sqlite3_stmt *pStmt; /* SQL statement being run */
+ char *zPkIdxName = 0; /* Name of the PRIMARY KEY index */
+ int truePk = 0; /* PRAGMA table_info indentifies the PK to use */
+ int nPK = 0; /* Number of PRIMARY KEY columns */
+ int i, j; /* Loop counters */
+
+ if( g.bSchemaPK==0 ){
+ /* Normal case: Figure out what the true primary key is for the table.
+ ** * For WITHOUT ROWID tables, the true primary key is the same as
+ ** the schema PRIMARY KEY, which is guaranteed to be present.
+ ** * For rowid tables with an INTEGER PRIMARY KEY, the true primary
+ ** key is the INTEGER PRIMARY KEY.
+ ** * For all other rowid tables, the rowid is the true primary key.
+ */
+ pStmt = db_prepare("PRAGMA %s.index_list=%Q", zDb, zTab);
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ if( sqlite3_stricmp((const char*)sqlite3_column_text(pStmt,3),"pk")==0 ){
+ zPkIdxName = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
+ break;
+ }
+ }
+ sqlite3_finalize(pStmt);
+ if( zPkIdxName ){
+ int nKey = 0;
+ int nCol = 0;
+ truePk = 0;
+ pStmt = db_prepare("PRAGMA %s.index_xinfo=%Q", zDb, zPkIdxName);
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ nCol++;
+ if( sqlite3_column_int(pStmt,5) ){ nKey++; continue; }
+ if( sqlite3_column_int(pStmt,1)>=0 ) truePk = 1;
+ }
+ if( nCol==nKey ) truePk = 1;
+ if( truePk ){
+ nPK = nKey;
+ }else{
+ nPK = 1;
+ }
+ sqlite3_finalize(pStmt);
+ sqlite3_free(zPkIdxName);
+ }else{
+ truePk = 1;
+ nPK = 1;
+ }
+ pStmt = db_prepare("PRAGMA %s.table_info=%Q", zDb, zTab);
+ }else{
+ /* The g.bSchemaPK==1 case: Use whatever primary key is declared
+ ** in the schema. The "rowid" will still be used as the primary key
+ ** if the table definition does not contain a PRIMARY KEY.
+ */
+ nPK = 0;
+ pStmt = db_prepare("PRAGMA %s.table_info=%Q", zDb, zTab);
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ if( sqlite3_column_int(pStmt,5)>0 ) nPK++;
+ }
+ sqlite3_reset(pStmt);
+ if( nPK==0 ) nPK = 1;
+ truePk = 1;
+ }
+ *pnPKey = nPK;
+ naz = nPK;
+ az = sqlite3_malloc( sizeof(char*)*(nPK+1) );
+ if( az==0 ) runtimeError("out of memory");
+ memset(az, 0, sizeof(char*)*(nPK+1));
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ int iPKey;
+ if( truePk && (iPKey = sqlite3_column_int(pStmt,5))>0 ){
+ az[iPKey-1] = safeId((char*)sqlite3_column_text(pStmt,1));
+ }else{
+ az = sqlite3_realloc(az, sizeof(char*)*(naz+2) );
+ if( az==0 ) runtimeError("out of memory");
+ az[naz++] = safeId((char*)sqlite3_column_text(pStmt,1));
+ }
+ }
+ sqlite3_finalize(pStmt);
+ if( az ) az[naz] = 0;
+
+ /* If it is non-NULL, set *pbRowid to indicate whether or not the PK of
+ ** this table is an implicit rowid (*pbRowid==1) or not (*pbRowid==0). */
+ if( pbRowid ) *pbRowid = (az[0]==0);
+
+ /* If this table has an implicit rowid for a PK, figure out how to refer
+ ** to it. There are three options - "rowid", "_rowid_" and "oid". Any
+ ** of these will work, unless the table has an explicit column of the
+ ** same name. */
+ if( az[0]==0 ){
+ const char *azRowid[] = { "rowid", "_rowid_", "oid" };
+ for(i=0; i<sizeof(azRowid)/sizeof(azRowid[0]); i++){
+ for(j=1; j<naz; j++){
+ if( sqlite3_stricmp(az[j], azRowid[i])==0 ) break;
+ }
+ if( j>=naz ){
+ az[0] = sqlite3_mprintf("%s", azRowid[i]);
+ break;
+ }
+ }
+ if( az[0]==0 ){
+ for(i=1; i<naz; i++) sqlite3_free(az[i]);
+ sqlite3_free(az);
+ az = 0;
+ }
+ }
+ return az;
+}
+
+/*
+** Print the sqlite3_value X as an SQL literal.
+*/
+static void printQuoted(FILE *out, sqlite3_value *X){
+ switch( sqlite3_value_type(X) ){
+ case SQLITE_FLOAT: {
+ double r1;
+ char zBuf[50];
+ r1 = sqlite3_value_double(X);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.15g", r1);
+ fprintf(out, "%s", zBuf);
+ break;
+ }
+ case SQLITE_INTEGER: {
+ fprintf(out, "%lld", sqlite3_value_int64(X));
+ break;
+ }
+ case SQLITE_BLOB: {
+ const unsigned char *zBlob = sqlite3_value_blob(X);
+ int nBlob = sqlite3_value_bytes(X);
+ if( zBlob ){
+ int i;
+ fprintf(out, "x'");
+ for(i=0; i<nBlob; i++){
+ fprintf(out, "%02x", zBlob[i]);
+ }
+ fprintf(out, "'");
+ }else{
+ /* Could be an OOM, could be a zero-byte blob */
+ fprintf(out, "X''");
+ }
+ break;
+ }
+ case SQLITE_TEXT: {
+ const unsigned char *zArg = sqlite3_value_text(X);
+ int i, j;
+
+ if( zArg==0 ){
+ fprintf(out, "NULL");
+ }else{
+ fprintf(out, "'");
+ for(i=j=0; zArg[i]; i++){
+ if( zArg[i]=='\'' ){
+ fprintf(out, "%.*s'", i-j+1, &zArg[j]);
+ j = i+1;
+ }
+ }
+ fprintf(out, "%s'", &zArg[j]);
+ }
+ break;
+ }
+ case SQLITE_NULL: {
+ fprintf(out, "NULL");
+ break;
+ }
+ }
+}
+
+/*
+** Output SQL that will recreate the aux.zTab table.
+*/
+static void dump_table(const char *zTab, FILE *out){
+ char *zId = safeId(zTab); /* Name of the table */
+ char **az = 0; /* List of columns */
+ int nPk; /* Number of true primary key columns */
+ int nCol; /* Number of data columns */
+ int i; /* Loop counter */
+ sqlite3_stmt *pStmt; /* SQL statement */
+ const char *zSep; /* Separator string */
+ Str ins; /* Beginning of the INSERT statement */
+
+ pStmt = db_prepare("SELECT sql FROM aux.sqlite_master WHERE name=%Q", zTab);
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ fprintf(out, "%s;\n", sqlite3_column_text(pStmt,0));
+ }
+ sqlite3_finalize(pStmt);
+ if( !g.bSchemaOnly ){
+ az = columnNames("aux", zTab, &nPk, 0);
+ strInit(&ins);
+ if( az==0 ){
+ pStmt = db_prepare("SELECT * FROM aux.%s", zId);
+ strPrintf(&ins,"INSERT INTO %s VALUES", zId);
+ }else{
+ Str sql;
+ strInit(&sql);
+ zSep = "SELECT";
+ for(i=0; az[i]; i++){
+ strPrintf(&sql, "%s %s", zSep, az[i]);
+ zSep = ",";
+ }
+ strPrintf(&sql," FROM aux.%s", zId);
+ zSep = " ORDER BY";
+ for(i=1; i<=nPk; i++){
+ strPrintf(&sql, "%s %d", zSep, i);
+ zSep = ",";
+ }
+ pStmt = db_prepare("%s", sql.z);
+ strFree(&sql);
+ strPrintf(&ins, "INSERT INTO %s", zId);
+ zSep = "(";
+ for(i=0; az[i]; i++){
+ strPrintf(&ins, "%s%s", zSep, az[i]);
+ zSep = ",";
+ }
+ strPrintf(&ins,") VALUES");
+ namelistFree(az);
+ }
+ nCol = sqlite3_column_count(pStmt);
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ fprintf(out, "%s",ins.z);
+ zSep = "(";
+ for(i=0; i<nCol; i++){
+ fprintf(out, "%s",zSep);
+ printQuoted(out, sqlite3_column_value(pStmt,i));
+ zSep = ",";
+ }
+ fprintf(out, ");\n");
+ }
+ sqlite3_finalize(pStmt);
+ strFree(&ins);
+ } /* endif !g.bSchemaOnly */
+ pStmt = db_prepare("SELECT sql FROM aux.sqlite_master"
+ " WHERE type='index' AND tbl_name=%Q AND sql IS NOT NULL",
+ zTab);
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ fprintf(out, "%s;\n", sqlite3_column_text(pStmt,0));
+ }
+ sqlite3_finalize(pStmt);
+}
+
+
+/*
+** Compute all differences for a single table.
+*/
+static void diff_one_table(const char *zTab, FILE *out){
+ char *zId = safeId(zTab); /* Name of table (translated for us in SQL) */
+ char **az = 0; /* Columns in main */
+ char **az2 = 0; /* Columns in aux */
+ int nPk; /* Primary key columns in main */
+ int nPk2; /* Primary key columns in aux */
+ int n = 0; /* Number of columns in main */
+ int n2; /* Number of columns in aux */
+ int nQ; /* Number of output columns in the diff query */
+ int i; /* Loop counter */
+ const char *zSep; /* Separator string */
+ Str sql; /* Comparison query */
+ sqlite3_stmt *pStmt; /* Query statement to do the diff */
+
+ strInit(&sql);
+ if( g.fDebug==DEBUG_COLUMN_NAMES ){
+ /* Simply run columnNames() on all tables of the origin
+ ** database and show the results. This is used for testing
+ ** and debugging of the columnNames() function.
+ */
+ az = columnNames("aux",zTab, &nPk, 0);
+ if( az==0 ){
+ printf("Rowid not accessible for %s\n", zId);
+ }else{
+ printf("%s:", zId);
+ for(i=0; az[i]; i++){
+ printf(" %s", az[i]);
+ if( i+1==nPk ) printf(" *");
+ }
+ printf("\n");
+ }
+ goto end_diff_one_table;
+ }
+
+
+ if( sqlite3_table_column_metadata(g.db,"aux",zTab,0,0,0,0,0,0) ){
+ if( !sqlite3_table_column_metadata(g.db,"main",zTab,0,0,0,0,0,0) ){
+ /* Table missing from second database. */
+ fprintf(out, "DROP TABLE %s;\n", zId);
+ }
+ goto end_diff_one_table;
+ }
+
+ if( sqlite3_table_column_metadata(g.db,"main",zTab,0,0,0,0,0,0) ){
+ /* Table missing from source */
+ dump_table(zTab, out);
+ goto end_diff_one_table;
+ }
+
+ az = columnNames("main", zTab, &nPk, 0);
+ az2 = columnNames("aux", zTab, &nPk2, 0);
+ if( az && az2 ){
+ for(n=0; az[n] && az2[n]; n++){
+ if( sqlite3_stricmp(az[n],az2[n])!=0 ) break;
+ }
+ }
+ if( az==0
+ || az2==0
+ || nPk!=nPk2
+ || az[n]
+ ){
+ /* Schema mismatch */
+ fprintf(out, "DROP TABLE %s; -- due to schema mismatch\n", zId);
+ dump_table(zTab, out);
+ goto end_diff_one_table;
+ }
+
+ /* Build the comparison query */
+ for(n2=n; az2[n2]; n2++){
+ fprintf(out, "ALTER TABLE %s ADD COLUMN %s;\n", zId, safeId(az2[n2]));
+ }
+ nQ = nPk2+1+2*(n2-nPk2);
+ if( n2>nPk2 ){
+ zSep = "SELECT ";
+ for(i=0; i<nPk; i++){
+ strPrintf(&sql, "%sB.%s", zSep, az[i]);
+ zSep = ", ";
+ }
+ strPrintf(&sql, ", 1%s -- changed row\n", nPk==n ? "" : ",");
+ while( az[i] ){
+ strPrintf(&sql, " A.%s IS NOT B.%s, B.%s%s\n",
+ az[i], az2[i], az2[i], az2[i+1]==0 ? "" : ",");
+ i++;
+ }
+ while( az2[i] ){
+ strPrintf(&sql, " B.%s IS NOT NULL, B.%s%s\n",
+ az2[i], az2[i], az2[i+1]==0 ? "" : ",");
+ i++;
+ }
+ strPrintf(&sql, " FROM main.%s A, aux.%s B\n", zId, zId);
+ zSep = " WHERE";
+ for(i=0; i<nPk; i++){
+ strPrintf(&sql, "%s A.%s=B.%s", zSep, az[i], az[i]);
+ zSep = " AND";
+ }
+ zSep = "\n AND (";
+ while( az[i] ){
+ strPrintf(&sql, "%sA.%s IS NOT B.%s%s\n",
+ zSep, az[i], az2[i], az2[i+1]==0 ? ")" : "");
+ zSep = " OR ";
+ i++;
+ }
+ while( az2[i] ){
+ strPrintf(&sql, "%sB.%s IS NOT NULL%s\n",
+ zSep, az2[i], az2[i+1]==0 ? ")" : "");
+ zSep = " OR ";
+ i++;
+ }
+ strPrintf(&sql, " UNION ALL\n");
+ }
+ zSep = "SELECT ";
+ for(i=0; i<nPk; i++){
+ strPrintf(&sql, "%sA.%s", zSep, az[i]);
+ zSep = ", ";
+ }
+ strPrintf(&sql, ", 2%s -- deleted row\n", nPk==n ? "" : ",");
+ while( az2[i] ){
+ strPrintf(&sql, " NULL, NULL%s\n", i==n2-1 ? "" : ",");
+ i++;
+ }
+ strPrintf(&sql, " FROM main.%s A\n", zId);
+ strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM aux.%s B\n", zId);
+ zSep = " WHERE";
+ for(i=0; i<nPk; i++){
+ strPrintf(&sql, "%s A.%s=B.%s", zSep, az[i], az[i]);
+ zSep = " AND";
+ }
+ strPrintf(&sql, ")\n");
+ zSep = " UNION ALL\nSELECT ";
+ for(i=0; i<nPk; i++){
+ strPrintf(&sql, "%sB.%s", zSep, az[i]);
+ zSep = ", ";
+ }
+ strPrintf(&sql, ", 3%s -- inserted row\n", nPk==n ? "" : ",");
+ while( az2[i] ){
+ strPrintf(&sql, " 1, B.%s%s\n", az2[i], az2[i+1]==0 ? "" : ",");
+ i++;
+ }
+ strPrintf(&sql, " FROM aux.%s B\n", zId);
+ strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM main.%s A\n", zId);
+ zSep = " WHERE";
+ for(i=0; i<nPk; i++){
+ strPrintf(&sql, "%s A.%s=B.%s", zSep, az[i], az[i]);
+ zSep = " AND";
+ }
+ strPrintf(&sql, ")\n ORDER BY");
+ zSep = " ";
+ for(i=1; i<=nPk; i++){
+ strPrintf(&sql, "%s%d", zSep, i);
+ zSep = ", ";
+ }
+ strPrintf(&sql, ";\n");
+
+ if( g.fDebug & DEBUG_DIFF_SQL ){
+ printf("SQL for %s:\n%s\n", zId, sql.z);
+ goto end_diff_one_table;
+ }
+
+ /* Drop indexes that are missing in the destination */
+ pStmt = db_prepare(
+ "SELECT name FROM main.sqlite_master"
+ " WHERE type='index' AND tbl_name=%Q"
+ " AND sql IS NOT NULL"
+ " AND sql NOT IN (SELECT sql FROM aux.sqlite_master"
+ " WHERE type='index' AND tbl_name=%Q"
+ " AND sql IS NOT NULL)",
+ zTab, zTab);
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ char *z = safeId((const char*)sqlite3_column_text(pStmt,0));
+ fprintf(out, "DROP INDEX %s;\n", z);
+ sqlite3_free(z);
+ }
+ sqlite3_finalize(pStmt);
+
+ /* Run the query and output differences */
+ if( !g.bSchemaOnly ){
+ pStmt = db_prepare("%s", sql.z);
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ int iType = sqlite3_column_int(pStmt, nPk);
+ if( iType==1 || iType==2 ){
+ if( iType==1 ){ /* Change the content of a row */
+ fprintf(out, "UPDATE %s", zId);
+ zSep = " SET";
+ for(i=nPk+1; i<nQ; i+=2){
+ if( sqlite3_column_int(pStmt,i)==0 ) continue;
+ fprintf(out, "%s %s=", zSep, az2[(i+nPk-1)/2]);
+ zSep = ",";
+ printQuoted(out, sqlite3_column_value(pStmt,i+1));
+ }
+ }else{ /* Delete a row */
+ fprintf(out, "DELETE FROM %s", zId);
+ }
+ zSep = " WHERE";
+ for(i=0; i<nPk; i++){
+ fprintf(out, "%s %s=", zSep, az2[i]);
+ printQuoted(out, sqlite3_column_value(pStmt,i));
+ zSep = " AND";
+ }
+ fprintf(out, ";\n");
+ }else{ /* Insert a row */
+ fprintf(out, "INSERT INTO %s(%s", zId, az2[0]);
+ for(i=1; az2[i]; i++) fprintf(out, ",%s", az2[i]);
+ fprintf(out, ") VALUES");
+ zSep = "(";
+ for(i=0; i<nPk2; i++){
+ fprintf(out, "%s", zSep);
+ zSep = ",";
+ printQuoted(out, sqlite3_column_value(pStmt,i));
+ }
+ for(i=nPk2+2; i<nQ; i+=2){
+ fprintf(out, ",");
+ printQuoted(out, sqlite3_column_value(pStmt,i));
+ }
+ fprintf(out, ");\n");
+ }
+ }
+ sqlite3_finalize(pStmt);
+ } /* endif !g.bSchemaOnly */
+
+ /* Create indexes that are missing in the source */
+ pStmt = db_prepare(
+ "SELECT sql FROM aux.sqlite_master"
+ " WHERE type='index' AND tbl_name=%Q"
+ " AND sql IS NOT NULL"
+ " AND sql NOT IN (SELECT sql FROM main.sqlite_master"
+ " WHERE type='index' AND tbl_name=%Q"
+ " AND sql IS NOT NULL)",
+ zTab, zTab);
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ fprintf(out, "%s;\n", sqlite3_column_text(pStmt,0));
+ }
+ sqlite3_finalize(pStmt);
+
+end_diff_one_table:
+ strFree(&sql);
+ sqlite3_free(zId);
+ namelistFree(az);
+ namelistFree(az2);
+ return;
+}
+
+/*
+** Check that table zTab exists and has the same schema in both the "main"
+** and "aux" databases currently opened by the global db handle. If they
+** do not, output an error message on stderr and exit(1). Otherwise, if
+** the schemas do match, return control to the caller.
+*/
+static void checkSchemasMatch(const char *zTab){
+ sqlite3_stmt *pStmt = db_prepare(
+ "SELECT A.sql=B.sql FROM main.sqlite_master A, aux.sqlite_master B"
+ " WHERE A.name=%Q AND B.name=%Q", zTab, zTab
+ );
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ if( sqlite3_column_int(pStmt,0)==0 ){
+ runtimeError("schema changes for table %s", safeId(zTab));
+ }
+ }else{
+ runtimeError("table %s missing from one or both databases", safeId(zTab));
+ }
+ sqlite3_finalize(pStmt);
+}
+
+/**************************************************************************
+** The following code is copied from fossil. It is used to generate the
+** fossil delta blobs sometimes used in RBU update records.
+*/
+
+typedef unsigned short u16;
+typedef unsigned int u32;
+typedef unsigned char u8;
+
+/*
+** The width of a hash window in bytes. The algorithm only works if this
+** is a power of 2.
+*/
+#define NHASH 16
+
+/*
+** The current state of the rolling hash.
+**
+** z[] holds the values that have been hashed. z[] is a circular buffer.
+** z[i] is the first entry and z[(i+NHASH-1)%NHASH] is the last entry of
+** the window.
+**
+** Hash.a is the sum of all elements of hash.z[]. Hash.b is a weighted
+** sum. Hash.b is z[i]*NHASH + z[i+1]*(NHASH-1) + ... + z[i+NHASH-1]*1.
+** (Each index for z[] should be module NHASH, of course. The %NHASH operator
+** is omitted in the prior expression for brevity.)
+*/
+typedef struct hash hash;
+struct hash {
+ u16 a, b; /* Hash values */
+ u16 i; /* Start of the hash window */
+ char z[NHASH]; /* The values that have been hashed */
+};
+
+/*
+** Initialize the rolling hash using the first NHASH characters of z[]
+*/
+static void hash_init(hash *pHash, const char *z){
+ u16 a, b, i;
+ a = b = 0;
+ for(i=0; i<NHASH; i++){
+ a += z[i];
+ b += (NHASH-i)*z[i];
+ pHash->z[i] = z[i];
+ }
+ pHash->a = a & 0xffff;
+ pHash->b = b & 0xffff;
+ pHash->i = 0;
+}
+
+/*
+** Advance the rolling hash by a single character "c"
+*/
+static void hash_next(hash *pHash, int c){
+ u16 old = pHash->z[pHash->i];
+ pHash->z[pHash->i] = (char)c;
+ pHash->i = (pHash->i+1)&(NHASH-1);
+ pHash->a = pHash->a - old + (char)c;
+ pHash->b = pHash->b - NHASH*old + pHash->a;
+}
+
+/*
+** Return a 32-bit hash value
+*/
+static u32 hash_32bit(hash *pHash){
+ return (pHash->a & 0xffff) | (((u32)(pHash->b & 0xffff))<<16);
+}
+
+/*
+** Write an base-64 integer into the given buffer.
+*/
+static void putInt(unsigned int v, char **pz){
+ static const char zDigits[] =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~";
+ /* 123456789 123456789 123456789 123456789 123456789 123456789 123 */
+ int i, j;
+ char zBuf[20];
+ if( v==0 ){
+ *(*pz)++ = '0';
+ return;
+ }
+ for(i=0; v>0; i++, v>>=6){
+ zBuf[i] = zDigits[v&0x3f];
+ }
+ for(j=i-1; j>=0; j--){
+ *(*pz)++ = zBuf[j];
+ }
+}
+
+/*
+** Return the number digits in the base-64 representation of a positive integer
+*/
+static int digit_count(int v){
+ unsigned int i, x;
+ for(i=1, x=64; (unsigned int)v>=x; i++, x <<= 6){}
+ return i;
+}
+
+/*
+** Compute a 32-bit checksum on the N-byte buffer. Return the result.
+*/
+static unsigned int checksum(const char *zIn, size_t N){
+ const unsigned char *z = (const unsigned char *)zIn;
+ unsigned sum0 = 0;
+ unsigned sum1 = 0;
+ unsigned sum2 = 0;
+ unsigned sum3 = 0;
+ while(N >= 16){
+ sum0 += ((unsigned)z[0] + z[4] + z[8] + z[12]);
+ sum1 += ((unsigned)z[1] + z[5] + z[9] + z[13]);
+ sum2 += ((unsigned)z[2] + z[6] + z[10]+ z[14]);
+ sum3 += ((unsigned)z[3] + z[7] + z[11]+ z[15]);
+ z += 16;
+ N -= 16;
+ }
+ while(N >= 4){
+ sum0 += z[0];
+ sum1 += z[1];
+ sum2 += z[2];
+ sum3 += z[3];
+ z += 4;
+ N -= 4;
+ }
+ sum3 += (sum2 << 8) + (sum1 << 16) + (sum0 << 24);
+ switch(N){
+ case 3: sum3 += (z[2] << 8);
+ case 2: sum3 += (z[1] << 16);
+ case 1: sum3 += (z[0] << 24);
+ default: ;
+ }
+ return sum3;
+}
+
+/*
+** Create a new delta.
+**
+** The delta is written into a preallocated buffer, zDelta, which
+** should be at least 60 bytes longer than the target file, zOut.
+** The delta string will be NUL-terminated, but it might also contain
+** embedded NUL characters if either the zSrc or zOut files are
+** binary. This function returns the length of the delta string
+** in bytes, excluding the final NUL terminator character.
+**
+** Output Format:
+**
+** The delta begins with a base64 number followed by a newline. This
+** number is the number of bytes in the TARGET file. Thus, given a
+** delta file z, a program can compute the size of the output file
+** simply by reading the first line and decoding the base-64 number
+** found there. The delta_output_size() routine does exactly this.
+**
+** After the initial size number, the delta consists of a series of
+** literal text segments and commands to copy from the SOURCE file.
+** A copy command looks like this:
+**
+** NNN@MMM,
+**
+** where NNN is the number of bytes to be copied and MMM is the offset
+** into the source file of the first byte (both base-64). If NNN is 0
+** it means copy the rest of the input file. Literal text is like this:
+**
+** NNN:TTTTT
+**
+** where NNN is the number of bytes of text (base-64) and TTTTT is the text.
+**
+** The last term is of the form
+**
+** NNN;
+**
+** In this case, NNN is a 32-bit bigendian checksum of the output file
+** that can be used to verify that the delta applied correctly. All
+** numbers are in base-64.
+**
+** Pure text files generate a pure text delta. Binary files generate a
+** delta that may contain some binary data.
+**
+** Algorithm:
+**
+** The encoder first builds a hash table to help it find matching
+** patterns in the source file. 16-byte chunks of the source file
+** sampled at evenly spaced intervals are used to populate the hash
+** table.
+**
+** Next we begin scanning the target file using a sliding 16-byte
+** window. The hash of the 16-byte window in the target is used to
+** search for a matching section in the source file. When a match
+** is found, a copy command is added to the delta. An effort is
+** made to extend the matching section to regions that come before
+** and after the 16-byte hash window. A copy command is only issued
+** if the result would use less space that just quoting the text
+** literally. Literal text is added to the delta for sections that
+** do not match or which can not be encoded efficiently using copy
+** commands.
+*/
+static int rbuDeltaCreate(
+ const char *zSrc, /* The source or pattern file */
+ unsigned int lenSrc, /* Length of the source file */
+ const char *zOut, /* The target file */
+ unsigned int lenOut, /* Length of the target file */
+ char *zDelta /* Write the delta into this buffer */
+){
+ unsigned int i, base;
+ char *zOrigDelta = zDelta;
+ hash h;
+ int nHash; /* Number of hash table entries */
+ int *landmark; /* Primary hash table */
+ int *collide; /* Collision chain */
+ int lastRead = -1; /* Last byte of zSrc read by a COPY command */
+
+ /* Add the target file size to the beginning of the delta
+ */
+ putInt(lenOut, &zDelta);
+ *(zDelta++) = '\n';
+
+ /* If the source file is very small, it means that we have no
+ ** chance of ever doing a copy command. Just output a single
+ ** literal segment for the entire target and exit.
+ */
+ if( lenSrc<=NHASH ){
+ putInt(lenOut, &zDelta);
+ *(zDelta++) = ':';
+ memcpy(zDelta, zOut, lenOut);
+ zDelta += lenOut;
+ putInt(checksum(zOut, lenOut), &zDelta);
+ *(zDelta++) = ';';
+ return (int)(zDelta - zOrigDelta);
+ }
+
+ /* Compute the hash table used to locate matching sections in the
+ ** source file.
+ */
+ nHash = lenSrc/NHASH;
+ collide = sqlite3_malloc( nHash*2*sizeof(int) );
+ landmark = &collide[nHash];
+ memset(landmark, -1, nHash*sizeof(int));
+ memset(collide, -1, nHash*sizeof(int));
+ for(i=0; i<lenSrc-NHASH; i+=NHASH){
+ int hv;
+ hash_init(&h, &zSrc[i]);
+ hv = hash_32bit(&h) % nHash;
+ collide[i/NHASH] = landmark[hv];
+ landmark[hv] = i/NHASH;
+ }
+
+ /* Begin scanning the target file and generating copy commands and
+ ** literal sections of the delta.
+ */
+ base = 0; /* We have already generated everything before zOut[base] */
+ while( base+NHASH<lenOut ){
+ int iSrc, iBlock;
+ int bestCnt, bestOfst=0, bestLitsz=0;
+ hash_init(&h, &zOut[base]);
+ i = 0; /* Trying to match a landmark against zOut[base+i] */
+ bestCnt = 0;
+ while( 1 ){
+ int hv;
+ int limit = 250;
+
+ hv = hash_32bit(&h) % nHash;
+ iBlock = landmark[hv];
+ while( iBlock>=0 && (limit--)>0 ){
+ /*
+ ** The hash window has identified a potential match against
+ ** landmark block iBlock. But we need to investigate further.
+ **
+ ** Look for a region in zOut that matches zSrc. Anchor the search
+ ** at zSrc[iSrc] and zOut[base+i]. Do not include anything prior to
+ ** zOut[base] or after zOut[outLen] nor anything after zSrc[srcLen].
+ **
+ ** Set cnt equal to the length of the match and set ofst so that
+ ** zSrc[ofst] is the first element of the match. litsz is the number
+ ** of characters between zOut[base] and the beginning of the match.
+ ** sz will be the overhead (in bytes) needed to encode the copy
+ ** command. Only generate copy command if the overhead of the
+ ** copy command is less than the amount of literal text to be copied.
+ */
+ int cnt, ofst, litsz;
+ int j, k, x, y;
+ int sz;
+
+ /* Beginning at iSrc, match forwards as far as we can. j counts
+ ** the number of characters that match */
+ iSrc = iBlock*NHASH;
+ for(
+ j=0, x=iSrc, y=base+i;
+ (unsigned int)x<lenSrc && (unsigned int)y<lenOut;
+ j++, x++, y++
+ ){
+ if( zSrc[x]!=zOut[y] ) break;
+ }
+ j--;
+
+ /* Beginning at iSrc-1, match backwards as far as we can. k counts
+ ** the number of characters that match */
+ for(k=1; k<iSrc && (unsigned int)k<=i; k++){
+ if( zSrc[iSrc-k]!=zOut[base+i-k] ) break;
+ }
+ k--;
+
+ /* Compute the offset and size of the matching region */
+ ofst = iSrc-k;
+ cnt = j+k+1;
+ litsz = i-k; /* Number of bytes of literal text before the copy */
+ /* sz will hold the number of bytes needed to encode the "insert"
+ ** command and the copy command, not counting the "insert" text */
+ sz = digit_count(i-k)+digit_count(cnt)+digit_count(ofst)+3;
+ if( cnt>=sz && cnt>bestCnt ){
+ /* Remember this match only if it is the best so far and it
+ ** does not increase the file size */
+ bestCnt = cnt;
+ bestOfst = iSrc-k;
+ bestLitsz = litsz;
+ }
+
+ /* Check the next matching block */
+ iBlock = collide[iBlock];
+ }
+
+ /* We have a copy command that does not cause the delta to be larger
+ ** than a literal insert. So add the copy command to the delta.
+ */
+ if( bestCnt>0 ){
+ if( bestLitsz>0 ){
+ /* Add an insert command before the copy */
+ putInt(bestLitsz,&zDelta);
+ *(zDelta++) = ':';
+ memcpy(zDelta, &zOut[base], bestLitsz);
+ zDelta += bestLitsz;
+ base += bestLitsz;
+ }
+ base += bestCnt;
+ putInt(bestCnt, &zDelta);
+ *(zDelta++) = '@';
+ putInt(bestOfst, &zDelta);
+ *(zDelta++) = ',';
+ if( bestOfst + bestCnt -1 > lastRead ){
+ lastRead = bestOfst + bestCnt - 1;
+ }
+ bestCnt = 0;
+ break;
+ }
+
+ /* If we reach this point, it means no match is found so far */
+ if( base+i+NHASH>=lenOut ){
+ /* We have reached the end of the file and have not found any
+ ** matches. Do an "insert" for everything that does not match */
+ putInt(lenOut-base, &zDelta);
+ *(zDelta++) = ':';
+ memcpy(zDelta, &zOut[base], lenOut-base);
+ zDelta += lenOut-base;
+ base = lenOut;
+ break;
+ }
+
+ /* Advance the hash by one character. Keep looking for a match */
+ hash_next(&h, zOut[base+i+NHASH]);
+ i++;
+ }
+ }
+ /* Output a final "insert" record to get all the text at the end of
+ ** the file that does not match anything in the source file.
+ */
+ if( base<lenOut ){
+ putInt(lenOut-base, &zDelta);
+ *(zDelta++) = ':';
+ memcpy(zDelta, &zOut[base], lenOut-base);
+ zDelta += lenOut-base;
+ }
+ /* Output the final checksum record. */
+ putInt(checksum(zOut, lenOut), &zDelta);
+ *(zDelta++) = ';';
+ sqlite3_free(collide);
+ return (int)(zDelta - zOrigDelta);
+}
+
+/*
+** End of code copied from fossil.
+**************************************************************************/
+
+static void strPrintfArray(
+ Str *pStr, /* String object to append to */
+ const char *zSep, /* Separator string */
+ const char *zFmt, /* Format for each entry */
+ char **az, int n /* Array of strings & its size (or -1) */
+){
+ int i;
+ for(i=0; az[i] && (i<n || n<0); i++){
+ if( i!=0 ) strPrintf(pStr, "%s", zSep);
+ strPrintf(pStr, zFmt, az[i], az[i], az[i]);
+ }
+}
+
+static void getRbudiffQuery(
+ const char *zTab,
+ char **azCol,
+ int nPK,
+ int bOtaRowid,
+ Str *pSql
+){
+ int i;
+
+ /* First the newly inserted rows: **/
+ strPrintf(pSql, "SELECT ");
+ strPrintfArray(pSql, ", ", "%s", azCol, -1);
+ strPrintf(pSql, ", 0, "); /* Set ota_control to 0 for an insert */
+ strPrintfArray(pSql, ", ", "NULL", azCol, -1);
+ strPrintf(pSql, " FROM aux.%Q AS n WHERE NOT EXISTS (\n", zTab);
+ strPrintf(pSql, " SELECT 1 FROM ", zTab);
+ strPrintf(pSql, " main.%Q AS o WHERE ", zTab);
+ strPrintfArray(pSql, " AND ", "(n.%Q = o.%Q)", azCol, nPK);
+ strPrintf(pSql, "\n) AND ");
+ strPrintfArray(pSql, " AND ", "(n.%Q IS NOT NULL)", azCol, nPK);
+
+ /* Deleted rows: */
+ strPrintf(pSql, "\nUNION ALL\nSELECT ");
+ strPrintfArray(pSql, ", ", "%s", azCol, nPK);
+ if( azCol[nPK] ){
+ strPrintf(pSql, ", ");
+ strPrintfArray(pSql, ", ", "NULL", &azCol[nPK], -1);
+ }
+ strPrintf(pSql, ", 1, "); /* Set ota_control to 1 for a delete */
+ strPrintfArray(pSql, ", ", "NULL", azCol, -1);
+ strPrintf(pSql, " FROM main.%Q AS n WHERE NOT EXISTS (\n", zTab);
+ strPrintf(pSql, " SELECT 1 FROM ", zTab);
+ strPrintf(pSql, " aux.%Q AS o WHERE ", zTab);
+ strPrintfArray(pSql, " AND ", "(n.%Q = o.%Q)", azCol, nPK);
+ strPrintf(pSql, "\n) AND ");
+ strPrintfArray(pSql, " AND ", "(n.%Q IS NOT NULL)", azCol, nPK);
+
+ /* Updated rows. If all table columns are part of the primary key, there
+ ** can be no updates. In this case this part of the compound SELECT can
+ ** be omitted altogether. */
+ if( azCol[nPK] ){
+ strPrintf(pSql, "\nUNION ALL\nSELECT ");
+ strPrintfArray(pSql, ", ", "n.%s", azCol, nPK);
+ strPrintf(pSql, ",\n");
+ strPrintfArray(pSql, " ,\n",
+ " CASE WHEN n.%s IS o.%s THEN NULL ELSE n.%s END", &azCol[nPK], -1
+ );
+
+ if( bOtaRowid==0 ){
+ strPrintf(pSql, ", '");
+ strPrintfArray(pSql, "", ".", azCol, nPK);
+ strPrintf(pSql, "' ||\n");
+ }else{
+ strPrintf(pSql, ",\n");
+ }
+ strPrintfArray(pSql, " ||\n",
+ " CASE WHEN n.%s IS o.%s THEN '.' ELSE 'x' END", &azCol[nPK], -1
+ );
+ strPrintf(pSql, "\nAS ota_control, ");
+ strPrintfArray(pSql, ", ", "NULL", azCol, nPK);
+ strPrintf(pSql, ",\n");
+ strPrintfArray(pSql, " ,\n",
+ " CASE WHEN n.%s IS o.%s THEN NULL ELSE o.%s END", &azCol[nPK], -1
+ );
+
+ strPrintf(pSql, "\nFROM main.%Q AS o, aux.%Q AS n\nWHERE ", zTab, zTab);
+ strPrintfArray(pSql, " AND ", "(n.%Q = o.%Q)", azCol, nPK);
+ strPrintf(pSql, " AND ota_control LIKE '%%x%%'");
+ }
+
+ /* Now add an ORDER BY clause to sort everything by PK. */
+ strPrintf(pSql, "\nORDER BY ");
+ for(i=1; i<=nPK; i++) strPrintf(pSql, "%s%d", ((i>1)?", ":""), i);
+}
+
+static void rbudiff_one_table(const char *zTab, FILE *out){
+ int bOtaRowid; /* True to use an ota_rowid column */
+ int nPK; /* Number of primary key columns in table */
+ char **azCol; /* NULL terminated array of col names */
+ int i;
+ int nCol;
+ Str ct = {0, 0, 0}; /* The "CREATE TABLE data_xxx" statement */
+ Str sql = {0, 0, 0}; /* Query to find differences */
+ Str insert = {0, 0, 0}; /* First part of output INSERT statement */
+ sqlite3_stmt *pStmt = 0;
+ int nRow = 0; /* Total rows in data_xxx table */
+
+ /* --rbu mode must use real primary keys. */
+ g.bSchemaPK = 1;
+
+ /* Check that the schemas of the two tables match. Exit early otherwise. */
+ checkSchemasMatch(zTab);
+
+ /* Grab the column names and PK details for the table(s). If no usable PK
+ ** columns are found, bail out early. */
+ azCol = columnNames("main", zTab, &nPK, &bOtaRowid);
+ if( azCol==0 ){
+ runtimeError("table %s has no usable PK columns", zTab);
+ }
+ for(nCol=0; azCol[nCol]; nCol++);
+
+ /* Build and output the CREATE TABLE statement for the data_xxx table */
+ strPrintf(&ct, "CREATE TABLE IF NOT EXISTS 'data_%q'(", zTab);
+ if( bOtaRowid ) strPrintf(&ct, "rbu_rowid, ");
+ strPrintfArray(&ct, ", ", "%s", &azCol[bOtaRowid], -1);
+ strPrintf(&ct, ", rbu_control);");
+
+ /* Get the SQL for the query to retrieve data from the two databases */
+ getRbudiffQuery(zTab, azCol, nPK, bOtaRowid, &sql);
+
+ /* Build the first part of the INSERT statement output for each row
+ ** in the data_xxx table. */
+ strPrintf(&insert, "INSERT INTO 'data_%q' (", zTab);
+ if( bOtaRowid ) strPrintf(&insert, "rbu_rowid, ");
+ strPrintfArray(&insert, ", ", "%s", &azCol[bOtaRowid], -1);
+ strPrintf(&insert, ", rbu_control) VALUES(");
+
+ pStmt = db_prepare("%s", sql.z);
+
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+
+ /* If this is the first row output, print out the CREATE TABLE
+ ** statement first. And then set ct.z to NULL so that it is not
+ ** printed again. */
+ if( ct.z ){
+ fprintf(out, "%s\n", ct.z);
+ strFree(&ct);
+ }
+
+ /* Output the first part of the INSERT statement */
+ fprintf(out, "%s", insert.z);
+ nRow++;
+
+ if( sqlite3_column_type(pStmt, nCol)==SQLITE_INTEGER ){
+ for(i=0; i<=nCol; i++){
+ if( i>0 ) fprintf(out, ", ");
+ printQuoted(out, sqlite3_column_value(pStmt, i));
+ }
+ }else{
+ char *zOtaControl;
+ int nOtaControl = sqlite3_column_bytes(pStmt, nCol);
+
+ zOtaControl = (char*)sqlite3_malloc(nOtaControl+1);
+ memcpy(zOtaControl, sqlite3_column_text(pStmt, nCol), nOtaControl+1);
+
+ for(i=0; i<nCol; i++){
+ int bDone = 0;
+ if( i>=nPK
+ && sqlite3_column_type(pStmt, i)==SQLITE_BLOB
+ && sqlite3_column_type(pStmt, nCol+1+i)==SQLITE_BLOB
+ ){
+ const char *aSrc = sqlite3_column_blob(pStmt, nCol+1+i);
+ int nSrc = sqlite3_column_bytes(pStmt, nCol+1+i);
+ const char *aFinal = sqlite3_column_blob(pStmt, i);
+ int nFinal = sqlite3_column_bytes(pStmt, i);
+ char *aDelta;
+ int nDelta;
+
+ aDelta = sqlite3_malloc(nFinal + 60);
+ nDelta = rbuDeltaCreate(aSrc, nSrc, aFinal, nFinal, aDelta);
+ if( nDelta<nFinal ){
+ int j;
+ fprintf(out, "x'");
+ for(j=0; j<nDelta; j++) fprintf(out, "%02x", (u8)aDelta[j]);
+ fprintf(out, "'");
+ zOtaControl[i-bOtaRowid] = 'f';
+ bDone = 1;
+ }
+ sqlite3_free(aDelta);
+ }
+
+ if( bDone==0 ){
+ printQuoted(out, sqlite3_column_value(pStmt, i));
+ }
+ fprintf(out, ", ");
+ }
+ fprintf(out, "'%s'", zOtaControl);
+ sqlite3_free(zOtaControl);
+ }
+
+ /* And the closing bracket of the insert statement */
+ fprintf(out, ");\n");
+ }
+
+ sqlite3_finalize(pStmt);
+ if( nRow>0 ){
+ Str cnt = {0, 0, 0};
+ strPrintf(&cnt, "INSERT INTO rbu_count VALUES('data_%q', %d);", zTab, nRow);
+ fprintf(out, "%s\n", cnt.z);
+ strFree(&cnt);
+ }
+
+ strFree(&ct);
+ strFree(&sql);
+ strFree(&insert);
+}
+
+/*
+** Display a summary of differences between two versions of the same
+** table table.
+**
+** * Number of rows changed
+** * Number of rows added
+** * Number of rows deleted
+** * Number of identical rows
+*/
+static void summarize_one_table(const char *zTab, FILE *out){
+ char *zId = safeId(zTab); /* Name of table (translated for us in SQL) */
+ char **az = 0; /* Columns in main */
+ char **az2 = 0; /* Columns in aux */
+ int nPk; /* Primary key columns in main */
+ int nPk2; /* Primary key columns in aux */
+ int n = 0; /* Number of columns in main */
+ int n2; /* Number of columns in aux */
+ int i; /* Loop counter */
+ const char *zSep; /* Separator string */
+ Str sql; /* Comparison query */
+ sqlite3_stmt *pStmt; /* Query statement to do the diff */
+ sqlite3_int64 nUpdate; /* Number of updated rows */
+ sqlite3_int64 nUnchanged; /* Number of unmodified rows */
+ sqlite3_int64 nDelete; /* Number of deleted rows */
+ sqlite3_int64 nInsert; /* Number of inserted rows */
+
+ strInit(&sql);
+ if( sqlite3_table_column_metadata(g.db,"aux",zTab,0,0,0,0,0,0) ){
+ if( !sqlite3_table_column_metadata(g.db,"main",zTab,0,0,0,0,0,0) ){
+ /* Table missing from second database. */
+ fprintf(out, "%s: missing from second database\n", zTab);
+ }
+ goto end_summarize_one_table;
+ }
+
+ if( sqlite3_table_column_metadata(g.db,"main",zTab,0,0,0,0,0,0) ){
+ /* Table missing from source */
+ fprintf(out, "%s: missing from first database\n", zTab);
+ goto end_summarize_one_table;
+ }
+
+ az = columnNames("main", zTab, &nPk, 0);
+ az2 = columnNames("aux", zTab, &nPk2, 0);
+ if( az && az2 ){
+ for(n=0; az[n]; n++){
+ if( sqlite3_stricmp(az[n],az2[n])!=0 ) break;
+ }
+ }
+ if( az==0
+ || az2==0
+ || nPk!=nPk2
+ || az[n]
+ ){
+ /* Schema mismatch */
+ fprintf(out, "%s: incompatible schema\n", zTab);
+ goto end_summarize_one_table;
+ }
+
+ /* Build the comparison query */
+ for(n2=n; az[n2]; n2++){}
+ strPrintf(&sql, "SELECT 1, count(*)");
+ if( n2==nPk2 ){
+ strPrintf(&sql, ", 0\n");
+ }else{
+ zSep = ", sum(";
+ for(i=nPk; az[i]; i++){
+ strPrintf(&sql, "%sA.%s IS NOT B.%s", zSep, az[i], az[i]);
+ zSep = " OR ";
+ }
+ strPrintf(&sql, ")\n");
+ }
+ strPrintf(&sql, " FROM main.%s A, aux.%s B\n", zId, zId);
+ zSep = " WHERE";
+ for(i=0; i<nPk; i++){
+ strPrintf(&sql, "%s A.%s=B.%s", zSep, az[i], az[i]);
+ zSep = " AND";
+ }
+ strPrintf(&sql, " UNION ALL\n");
+ strPrintf(&sql, "SELECT 2, count(*), 0\n");
+ strPrintf(&sql, " FROM main.%s A\n", zId);
+ strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM aux.%s B ", zId);
+ zSep = "WHERE";
+ for(i=0; i<nPk; i++){
+ strPrintf(&sql, "%s A.%s=B.%s", zSep, az[i], az[i]);
+ zSep = " AND";
+ }
+ strPrintf(&sql, ")\n");
+ strPrintf(&sql, " UNION ALL\n");
+ strPrintf(&sql, "SELECT 3, count(*), 0\n");
+ strPrintf(&sql, " FROM aux.%s B\n", zId);
+ strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM main.%s A ", zId);
+ zSep = "WHERE";
+ for(i=0; i<nPk; i++){
+ strPrintf(&sql, "%s A.%s=B.%s", zSep, az[i], az[i]);
+ zSep = " AND";
+ }
+ strPrintf(&sql, ")\n ORDER BY 1;\n");
+
+ if( (g.fDebug & DEBUG_DIFF_SQL)!=0 ){
+ printf("SQL for %s:\n%s\n", zId, sql.z);
+ goto end_summarize_one_table;
+ }
+
+ /* Run the query and output difference summary */
+ pStmt = db_prepare("%s", sql.z);
+ nUpdate = 0;
+ nInsert = 0;
+ nDelete = 0;
+ nUnchanged = 0;
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ switch( sqlite3_column_int(pStmt,0) ){
+ case 1:
+ nUpdate = sqlite3_column_int64(pStmt,2);
+ nUnchanged = sqlite3_column_int64(pStmt,1) - nUpdate;
+ break;
+ case 2:
+ nDelete = sqlite3_column_int64(pStmt,1);
+ break;
+ case 3:
+ nInsert = sqlite3_column_int64(pStmt,1);
+ break;
+ }
+ }
+ sqlite3_finalize(pStmt);
+ fprintf(out, "%s: %lld changes, %lld inserts, %lld deletes, %lld unchanged\n",
+ zTab, nUpdate, nInsert, nDelete, nUnchanged);
+
+end_summarize_one_table:
+ strFree(&sql);
+ sqlite3_free(zId);
+ namelistFree(az);
+ namelistFree(az2);
+ return;
+}
+
+/*
+** Write a 64-bit signed integer as a varint onto out
+*/
+static void putsVarint(FILE *out, sqlite3_uint64 v){
+ int i, n;
+ unsigned char p[12];
+ if( v & (((sqlite3_uint64)0xff000000)<<32) ){
+ p[8] = (unsigned char)v;
+ v >>= 8;
+ for(i=7; i>=0; i--){
+ p[i] = (unsigned char)((v & 0x7f) | 0x80);
+ v >>= 7;
+ }
+ fwrite(p, 8, 1, out);
+ }else{
+ n = 9;
+ do{
+ p[n--] = (unsigned char)((v & 0x7f) | 0x80);
+ v >>= 7;
+ }while( v!=0 );
+ p[9] &= 0x7f;
+ fwrite(p+n+1, 9-n, 1, out);
+ }
+}
+
+/*
+** Write an SQLite value onto out.
+*/
+static void putValue(FILE *out, sqlite3_stmt *pStmt, int k){
+ int iDType = sqlite3_column_type(pStmt, k);
+ sqlite3_int64 iX;
+ double rX;
+ sqlite3_uint64 uX;
+ int j;
+
+ putc(iDType, out);
+ switch( iDType ){
+ case SQLITE_INTEGER:
+ iX = sqlite3_column_int64(pStmt, k);
+ memcpy(&uX, &iX, 8);
+ for(j=56; j>=0; j-=8) putc((uX>>j)&0xff, out);
+ break;
+ case SQLITE_FLOAT:
+ rX = sqlite3_column_double(pStmt, k);
+ memcpy(&uX, &rX, 8);
+ for(j=56; j>=0; j-=8) putc((uX>>j)&0xff, out);
+ break;
+ case SQLITE_TEXT:
+ iX = sqlite3_column_bytes(pStmt, k);
+ putsVarint(out, (sqlite3_uint64)iX);
+ fwrite(sqlite3_column_text(pStmt, k),1,(size_t)iX,out);
+ break;
+ case SQLITE_BLOB:
+ iX = sqlite3_column_bytes(pStmt, k);
+ putsVarint(out, (sqlite3_uint64)iX);
+ fwrite(sqlite3_column_blob(pStmt, k),1,(size_t)iX,out);
+ break;
+ case SQLITE_NULL:
+ break;
+ }
+}
+
+/*
+** Generate a CHANGESET for all differences from main.zTab to aux.zTab.
+*/
+static void changeset_one_table(const char *zTab, FILE *out){
+ sqlite3_stmt *pStmt; /* SQL statment */
+ char *zId = safeId(zTab); /* Escaped name of the table */
+ char **azCol = 0; /* List of escaped column names */
+ int nCol = 0; /* Number of columns */
+ int *aiFlg = 0; /* 0 if column is not part of PK */
+ int *aiPk = 0; /* Column numbers for each PK column */
+ int nPk = 0; /* Number of PRIMARY KEY columns */
+ Str sql; /* SQL for the diff query */
+ int i, k; /* Loop counters */
+ const char *zSep; /* List separator */
+
+ /* Check that the schemas of the two tables match. Exit early otherwise. */
+ checkSchemasMatch(zTab);
+
+ pStmt = db_prepare("PRAGMA main.table_info=%Q", zTab);
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ nCol++;
+ azCol = sqlite3_realloc(azCol, sizeof(char*)*nCol);
+ if( azCol==0 ) runtimeError("out of memory");
+ aiFlg = sqlite3_realloc(aiFlg, sizeof(int)*nCol);
+ if( aiFlg==0 ) runtimeError("out of memory");
+ azCol[nCol-1] = safeId((const char*)sqlite3_column_text(pStmt,1));
+ aiFlg[nCol-1] = i = sqlite3_column_int(pStmt,5);
+ if( i>0 ){
+ if( i>nPk ){
+ nPk = i;
+ aiPk = sqlite3_realloc(aiPk, sizeof(int)*nPk);
+ if( aiPk==0 ) runtimeError("out of memory");
+ }
+ aiPk[i-1] = nCol-1;
+ }
+ }
+ sqlite3_finalize(pStmt);
+ if( nPk==0 ) goto end_changeset_one_table;
+ strInit(&sql);
+ if( nCol>nPk ){
+ strPrintf(&sql, "SELECT %d", SQLITE_UPDATE);
+ for(i=0; i<nCol; i++){
+ if( aiFlg[i] ){
+ strPrintf(&sql, ",\n A.%s", azCol[i]);
+ }else{
+ strPrintf(&sql, ",\n A.%s IS NOT B.%s, A.%s, B.%s",
+ azCol[i], azCol[i], azCol[i], azCol[i]);
+ }
+ }
+ strPrintf(&sql,"\n FROM main.%s A, aux.%s B\n", zId, zId);
+ zSep = " WHERE";
+ for(i=0; i<nPk; i++){
+ strPrintf(&sql, "%s A.%s=B.%s", zSep, azCol[aiPk[i]], azCol[aiPk[i]]);
+ zSep = " AND";
+ }
+ zSep = "\n AND (";
+ for(i=0; i<nCol; i++){
+ if( aiFlg[i] ) continue;
+ strPrintf(&sql, "%sA.%s IS NOT B.%s", zSep, azCol[i], azCol[i]);
+ zSep = " OR\n ";
+ }
+ strPrintf(&sql,")\n UNION ALL\n");
+ }
+ strPrintf(&sql, "SELECT %d", SQLITE_DELETE);
+ for(i=0; i<nCol; i++){
+ if( aiFlg[i] ){
+ strPrintf(&sql, ",\n A.%s", azCol[i]);
+ }else{
+ strPrintf(&sql, ",\n 1, A.%s, NULL", azCol[i]);
+ }
+ }
+ strPrintf(&sql, "\n FROM main.%s A\n", zId);
+ strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM aux.%s B\n", zId);
+ zSep = " WHERE";
+ for(i=0; i<nPk; i++){
+ strPrintf(&sql, "%s A.%s=B.%s", zSep, azCol[aiPk[i]], azCol[aiPk[i]]);
+ zSep = " AND";
+ }
+ strPrintf(&sql, ")\n UNION ALL\n");
+ strPrintf(&sql, "SELECT %d", SQLITE_INSERT);
+ for(i=0; i<nCol; i++){
+ if( aiFlg[i] ){
+ strPrintf(&sql, ",\n B.%s", azCol[i]);
+ }else{
+ strPrintf(&sql, ",\n 1, NULL, B.%s", azCol[i]);
+ }
+ }
+ strPrintf(&sql, "\n FROM aux.%s B\n", zId);
+ strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM main.%s A\n", zId);
+ zSep = " WHERE";
+ for(i=0; i<nPk; i++){
+ strPrintf(&sql, "%s A.%s=B.%s", zSep, azCol[aiPk[i]], azCol[aiPk[i]]);
+ zSep = " AND";
+ }
+ strPrintf(&sql, ")\n");
+ strPrintf(&sql, " ORDER BY");
+ zSep = " ";
+ for(i=0; i<nPk; i++){
+ strPrintf(&sql, "%s %d", zSep, aiPk[i]+2);
+ zSep = ",";
+ }
+ strPrintf(&sql, ";\n");
+
+ if( g.fDebug & DEBUG_DIFF_SQL ){
+ printf("SQL for %s:\n%s\n", zId, sql.z);
+ goto end_changeset_one_table;
+ }
+
+ putc('T', out);
+ putsVarint(out, (sqlite3_uint64)nCol);
+ for(i=0; i<nCol; i++) putc(aiFlg[i], out);
+ fwrite(zTab, 1, strlen(zTab), out);
+ putc(0, out);
+
+ pStmt = db_prepare("%s", sql.z);
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ int iType = sqlite3_column_int(pStmt,0);
+ putc(iType, out);
+ putc(0, out);
+ switch( sqlite3_column_int(pStmt,0) ){
+ case SQLITE_UPDATE: {
+ for(k=1, i=0; i<nCol; i++){
+ if( aiFlg[i] ){
+ putValue(out, pStmt, k);
+ k++;
+ }else if( sqlite3_column_int(pStmt,k) ){
+ putValue(out, pStmt, k+1);
+ k += 3;
+ }else{
+ putc(0, out);
+ k += 3;
+ }
+ }
+ for(k=1, i=0; i<nCol; i++){
+ if( aiFlg[i] ){
+ putc(0, out);
+ k++;
+ }else if( sqlite3_column_int(pStmt,k) ){
+ putValue(out, pStmt, k+2);
+ k += 3;
+ }else{
+ putc(0, out);
+ k += 3;
+ }
+ }
+ break;
+ }
+ case SQLITE_INSERT: {
+ for(k=1, i=0; i<nCol; i++){
+ if( aiFlg[i] ){
+ putValue(out, pStmt, k);
+ k++;
+ }else{
+ putValue(out, pStmt, k+2);
+ k += 3;
+ }
+ }
+ break;
+ }
+ case SQLITE_DELETE: {
+ for(k=1, i=0; i<nCol; i++){
+ if( aiFlg[i] ){
+ putValue(out, pStmt, k);
+ k++;
+ }else{
+ putValue(out, pStmt, k+1);
+ k += 3;
+ }
+ }
+ break;
+ }
+ }
+ }
+ sqlite3_finalize(pStmt);
+
+end_changeset_one_table:
+ while( nCol>0 ) sqlite3_free(azCol[--nCol]);
+ sqlite3_free(azCol);
+ sqlite3_free(aiPk);
+ sqlite3_free(zId);
+}
+
+/*
+** Extract the next SQL keyword or quoted string from buffer zIn and copy it
+** (or a prefix of it if it will not fit) into buffer zBuf, size nBuf bytes.
+** Return a pointer to the character within zIn immediately following
+** the token or quoted string just extracted.
+*/
+const char *gobble_token(const char *zIn, char *zBuf, int nBuf){
+ const char *p = zIn;
+ char *pOut = zBuf;
+ char *pEnd = &pOut[nBuf-1];
+ char q = 0; /* quote character, if any */
+
+ if( p==0 ) return 0;
+ while( *p==' ' ) p++;
+ switch( *p ){
+ case '"': q = '"'; break;
+ case '\'': q = '\''; break;
+ case '`': q = '`'; break;
+ case '[': q = ']'; break;
+ }
+
+ if( q ){
+ p++;
+ while( *p && pOut<pEnd ){
+ if( *p==q ){
+ p++;
+ if( *p!=q ) break;
+ }
+ if( pOut<pEnd ) *pOut++ = *p;
+ p++;
+ }
+ }else{
+ while( *p && *p!=' ' && *p!='(' ){
+ if( pOut<pEnd ) *pOut++ = *p;
+ p++;
+ }
+ }
+
+ *pOut = '\0';
+ return p;
+}
+
+/*
+** This function is the implementation of SQL scalar function "module_name":
+**
+** module_name(SQL)
+**
+** The only argument should be an SQL statement of the type that may appear
+** in the sqlite_master table. If the statement is a "CREATE VIRTUAL TABLE"
+** statement, then the value returned is the name of the module that it
+** uses. Otherwise, if the statement is not a CVT, NULL is returned.
+*/
+static void module_name_func(
+ sqlite3_context *pCtx,
+ int nVal, sqlite3_value **apVal
+){
+ const char *zSql;
+ char zToken[32];
+
+ assert( nVal==1 );
+ zSql = (const char*)sqlite3_value_text(apVal[0]);
+
+ zSql = gobble_token(zSql, zToken, sizeof(zToken));
+ if( zSql==0 || sqlite3_stricmp(zToken, "create") ) return;
+ zSql = gobble_token(zSql, zToken, sizeof(zToken));
+ if( zSql==0 || sqlite3_stricmp(zToken, "virtual") ) return;
+ zSql = gobble_token(zSql, zToken, sizeof(zToken));
+ if( zSql==0 || sqlite3_stricmp(zToken, "table") ) return;
+ zSql = gobble_token(zSql, zToken, sizeof(zToken));
+ if( zSql==0 ) return;
+ zSql = gobble_token(zSql, zToken, sizeof(zToken));
+ if( zSql==0 || sqlite3_stricmp(zToken, "using") ) return;
+ zSql = gobble_token(zSql, zToken, sizeof(zToken));
+
+ sqlite3_result_text(pCtx, zToken, -1, SQLITE_TRANSIENT);
+}
+
+/*
+** Return the text of an SQL statement that itself returns the list of
+** tables to process within the database.
+*/
+const char *all_tables_sql(){
+ if( g.bHandleVtab ){
+ int rc;
+
+ rc = sqlite3_exec(g.db,
+ "CREATE TEMP TABLE tblmap(module COLLATE nocase, postfix);"
+ "INSERT INTO temp.tblmap VALUES"
+ "('fts3', '_content'), ('fts3', '_segments'), ('fts3', '_segdir'),"
+
+ "('fts4', '_content'), ('fts4', '_segments'), ('fts4', '_segdir'),"
+ "('fts4', '_docsize'), ('fts4', '_stat'),"
+
+ "('fts5', '_data'), ('fts5', '_idx'), ('fts5', '_content'),"
+ "('fts5', '_docsize'), ('fts5', '_config'),"
+
+ "('rtree', '_node'), ('rtree', '_rowid'), ('rtree', '_parent');"
+ , 0, 0, 0
+ );
+ assert( rc==SQLITE_OK );
+
+ rc = sqlite3_create_function(
+ g.db, "module_name", 1, SQLITE_UTF8, 0, module_name_func, 0, 0
+ );
+ assert( rc==SQLITE_OK );
+
+ return
+ "SELECT name FROM main.sqlite_master\n"
+ " WHERE type='table' AND (\n"
+ " module_name(sql) IS NULL OR \n"
+ " module_name(sql) IN (SELECT module FROM temp.tblmap)\n"
+ " ) AND name NOT IN (\n"
+ " SELECT a.name || b.postfix \n"
+ "FROM main.sqlite_master AS a, temp.tblmap AS b \n"
+ "WHERE module_name(a.sql) = b.module\n"
+ " )\n"
+ "UNION \n"
+ "SELECT name FROM aux.sqlite_master\n"
+ " WHERE type='table' AND (\n"
+ " module_name(sql) IS NULL OR \n"
+ " module_name(sql) IN (SELECT module FROM temp.tblmap)\n"
+ " ) AND name NOT IN (\n"
+ " SELECT a.name || b.postfix \n"
+ "FROM aux.sqlite_master AS a, temp.tblmap AS b \n"
+ "WHERE module_name(a.sql) = b.module\n"
+ " )\n"
+ " ORDER BY name";
+ }else{
+ return
+ "SELECT name FROM main.sqlite_master\n"
+ " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n"
+ " UNION\n"
+ "SELECT name FROM aux.sqlite_master\n"
+ " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n"
+ " ORDER BY name";
+ }
+}
+
+/*
+** Print sketchy documentation for this utility program
+*/
+static void showHelp(void){
+ printf("Usage: %s [options] DB1 DB2\n", g.zArgv0);
+ printf(
+"Output SQL text that would transform DB1 into DB2.\n"
+"Options:\n"
+" --changeset FILE Write a CHANGESET into FILE\n"
+" -L|--lib LIBRARY Load an SQLite extension library\n"
+" --primarykey Use schema-defined PRIMARY KEYs\n"
+" --rbu Output SQL to create/populate RBU table(s)\n"
+" --schema Show only differences in the schema\n"
+" --summary Show only a summary of the differences\n"
+" --table TAB Show only differences in table TAB\n"
+" --transaction Show SQL output inside a transaction\n"
+" --vtab Handle fts3, fts4, fts5 and rtree tables\n"
+ );
+}
+
+int main(int argc, char **argv){
+ const char *zDb1 = 0;
+ const char *zDb2 = 0;
+ int i;
+ int rc;
+ char *zErrMsg = 0;
+ char *zSql;
+ sqlite3_stmt *pStmt;
+ char *zTab = 0;
+ FILE *out = stdout;
+ void (*xDiff)(const char*,FILE*) = diff_one_table;
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ int nExt = 0;
+ char **azExt = 0;
+#endif
+ int useTransaction = 0;
+ int neverUseTransaction = 0;
+
+ g.zArgv0 = argv[0];
+ sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
+ for(i=1; i<argc; i++){
+ const char *z = argv[i];
+ if( z[0]=='-' ){
+ z++;
+ if( z[0]=='-' ) z++;
+ if( strcmp(z,"changeset")==0 ){
+ if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]);
+ out = fopen(argv[++i], "wb");
+ if( out==0 ) cmdlineError("cannot open: %s", argv[i]);
+ xDiff = changeset_one_table;
+ neverUseTransaction = 1;
+ }else
+ if( strcmp(z,"debug")==0 ){
+ if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]);
+ g.fDebug = strtol(argv[++i], 0, 0);
+ }else
+ if( strcmp(z,"help")==0 ){
+ showHelp();
+ return 0;
+ }else
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ if( strcmp(z,"lib")==0 || strcmp(z,"L")==0 ){
+ if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]);
+ azExt = realloc(azExt, sizeof(azExt[0])*(nExt+1));
+ if( azExt==0 ) cmdlineError("out of memory");
+ azExt[nExt++] = argv[++i];
+ }else
+#endif
+ if( strcmp(z,"primarykey")==0 ){
+ g.bSchemaPK = 1;
+ }else
+ if( strcmp(z,"rbu")==0 ){
+ xDiff = rbudiff_one_table;
+ }else
+ if( strcmp(z,"schema")==0 ){
+ g.bSchemaOnly = 1;
+ }else
+ if( strcmp(z,"summary")==0 ){
+ xDiff = summarize_one_table;
+ }else
+ if( strcmp(z,"table")==0 ){
+ if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]);
+ zTab = argv[++i];
+ }else
+ if( strcmp(z,"transaction")==0 ){
+ useTransaction = 1;
+ }else
+ if( strcmp(z,"vtab")==0 ){
+ g.bHandleVtab = 1;
+ }else
+ {
+ cmdlineError("unknown option: %s", argv[i]);
+ }
+ }else if( zDb1==0 ){
+ zDb1 = argv[i];
+ }else if( zDb2==0 ){
+ zDb2 = argv[i];
+ }else{
+ cmdlineError("unknown argument: %s", argv[i]);
+ }
+ }
+ if( zDb2==0 ){
+ cmdlineError("two database arguments required");
+ }
+ rc = sqlite3_open(zDb1, &g.db);
+ if( rc ){
+ cmdlineError("cannot open database file \"%s\"", zDb1);
+ }
+ rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_master", 0, 0, &zErrMsg);
+ if( rc || zErrMsg ){
+ cmdlineError("\"%s\" does not appear to be a valid SQLite database", zDb1);
+ }
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ sqlite3_enable_load_extension(g.db, 1);
+ for(i=0; i<nExt; i++){
+ rc = sqlite3_load_extension(g.db, azExt[i], 0, &zErrMsg);
+ if( rc || zErrMsg ){
+ cmdlineError("error loading %s: %s", azExt[i], zErrMsg);
+ }
+ }
+ free(azExt);
+#endif
+ zSql = sqlite3_mprintf("ATTACH %Q as aux;", zDb2);
+ rc = sqlite3_exec(g.db, zSql, 0, 0, &zErrMsg);
+ if( rc || zErrMsg ){
+ cmdlineError("cannot attach database \"%s\"", zDb2);
+ }
+ rc = sqlite3_exec(g.db, "SELECT * FROM aux.sqlite_master", 0, 0, &zErrMsg);
+ if( rc || zErrMsg ){
+ cmdlineError("\"%s\" does not appear to be a valid SQLite database", zDb2);
+ }
+
+ if( neverUseTransaction ) useTransaction = 0;
+ if( useTransaction ) fprintf(out, "BEGIN TRANSACTION;\n");
+ if( xDiff==rbudiff_one_table ){
+ fprintf(out, "CREATE TABLE IF NOT EXISTS rbu_count"
+ "(tbl TEXT PRIMARY KEY COLLATE NOCASE, cnt INTEGER) "
+ "WITHOUT ROWID;\n"
+ );
+ }
+ if( zTab ){
+ xDiff(zTab, out);
+ }else{
+ /* Handle tables one by one */
+ pStmt = db_prepare("%s", all_tables_sql() );
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ xDiff((const char*)sqlite3_column_text(pStmt,0), out);
+ }
+ sqlite3_finalize(pStmt);
+ }
+ if( useTransaction ) printf("COMMIT;\n");
+
+ /* TBD: Handle trigger differences */
+ /* TBD: Handle view differences */
+ sqlite3_close(g.db);
+ return 0;
+}
--- origsrc/sqlite-autoconf-3300000/sqlite3.1 2019-10-04 18:28:13.000000000 +0200
+++ src/sqlite-autoconf-3300000/sqlite3.1 2019-03-05 13:14:40.874000000 +0100
@@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
-.TH SQLITE3 1 "Fri Oct 31 10:41:31 EDT 2014"
+.TH SQLITE3 1 "Fry Jun 30 15:30:00 EDT 2017"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
@@ -49,7 +49,7 @@ a table named "memos" and insert a coupl
$
.B sqlite3 mydata.db
.br
-SQLite version 3.8.8
+SQLite version 3.19.3
.br
Enter ".help" for instructions
.br
@@ -98,7 +98,7 @@ priority = 100
The interactive interpreter offers a set of meta-commands that can be
used to control the output format, examine the currently attached
database files, or perform administrative operations upon the
-attached databases (such as rebuilding indices). Meta-commands are
+attached databases (such as rebuilding indexes). Meta-commands are
always prefixed with a dot (.).
A list of available meta-commands can be viewed at any time by issuing
@@ -108,39 +108,50 @@ sqlite>
.B .help
.nf
.tr %.
+%auth ON|OFF Show authorizer callbacks
%backup ?DB? FILE Backup DB (default "main") to FILE
%bail on|off Stop after hitting an error. Default OFF
+%binary on|off Turn binary output on or off. Default OFF
+%cd DIRECTORY Change the working directory to DIRECTORY
+%changes on|off Show number of rows changed by SQL
+%check GLOB Fail if output since .testcase does not match
%clone NEWDB Clone data into NEWDB from the existing database
%databases List names and files of attached databases
+%dbinfo ?DB? Show status information about the database
%dump ?TABLE? ... Dump the database in an SQL text format
If TABLE specified, only dump tables matching
LIKE pattern TABLE.
%echo on|off Turn command echo on or off
-%eqp on|off Enable or disable automatic EXPLAIN QUERY PLAN
+%eqp on|off|full Enable or disable automatic EXPLAIN QUERY PLAN
%exit Exit this program
-%explain ?on|off? Turn output mode suitable for EXPLAIN on or off.
- With no args, it turns EXPLAIN on.
-%fullschema Show schema and the content of sqlite_stat tables
+%fullschema ?--indent? Show schema and the content of sqlite_stat tables
%headers on|off Turn display of headers on or off
%help Show this message
%import FILE TABLE Import data from FILE into TABLE
-%indices ?TABLE? Show names of all indices
- If TABLE specified, only show indices for tables
+%imposter INDEX TABLE Create imposter table TABLE on index INDEX
+%indexes ?TABLE? Show names of all indexes
+ If TABLE specified, only show indexes for tables
matching LIKE pattern TABLE.
+%limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT
+%lint OPTIONS Report potential schema issues. Options:
+ fkey-indexes Find missing foreign key indexes
%load FILE ?ENTRY? Load an extension library
%log FILE|off Turn logging on or off. FILE can be stderr/stdout
%mode MODE ?TABLE? Set output mode where MODE is one of:
+ ascii Columns/rows delimited by 0x1F and 0x1E
csv Comma-separated values
column Left-aligned columns. (See .width)
html HTML <table> code
insert SQL insert statements for TABLE
line One value per line
- list Values delimited by .separator string
+ list Values delimited by "|"
+ quote Escape answers as for SQL
tabs Tab-separated values
tcl TCL list elements
%nullvalue STRING Use STRING in place of NULL values
%once FILENAME Output for the next SQL command only to FILENAME
-%open ?FILENAME? Close existing database and reopen FILENAME
+%open ?OPTIONS? ?FILE? Close existing database and reopen FILE
+ The --new option starts with an empty file
%output ?FILENAME? Send output to FILENAME or stdout
%print STRING... Print literal STRING
%prompt MAIN CONTINUE Replace the standard prompts
@@ -148,21 +159,26 @@ sqlite>
%read FILENAME Execute SQL in FILENAME
%restore ?DB? FILE Restore content of DB (default "main") from FILE
%save FILE Write in-memory database into FILE
-%schema ?TABLE? Show the CREATE statements
- If TABLE specified, only show tables matching
- LIKE pattern TABLE.
-%separator STRING ?NL? Change separator used by output mode and .import
- NL is the end-of-line mark for CSV
+%scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off
+%schema ?PATTERN? Show the CREATE statements matching PATTERN
+ Add --indent for pretty-printing
+%separator COL ?ROW? Change the column separator and optionally the row
+ separator for both the output mode and .import
+%session CMD ... Create or control sessions
+%sha3sum ?OPTIONS...? Compute a SHA3 hash of database content
%shell CMD ARGS... Run CMD ARGS... in a system shell
%show Show the current values for various settings
-%stats on|off Turn stats on or off
+%stats ?on|off? Show stats or turn stats on or off
%system CMD ARGS... Run CMD ARGS... in a system shell
%tables ?TABLE? List names of tables
If TABLE specified, only list tables matching
LIKE pattern TABLE.
+%testcase NAME Begin redirecting output to 'testcase-out.txt'
%timeout MS Try opening locked tables for MS milliseconds
%timer on|off Turn SQL timer on or off
%trace FILE|off Output each SQL statement as it is run
+%vfsinfo ?AUX? Information about the top-level VFS
+%vfslist List all available VFSes
%vfsname ?AUX? Print the name of the VFS stack
%width NUM1 NUM2 ... Set column widths for "column" mode
Negative values right-justify
@@ -173,6 +189,9 @@ sqlite>
.B sqlite3
has the following options:
.TP
+.B \-ascii
+Set output mode to ascii.
+.TP
.B \-bail
Stop after hitting an error.
.TP
@@ -226,12 +245,25 @@ Set default mmap size to
.I N
\.
.TP
+.BI \-newline\ separator
+Set output row separator. Default is the newline character.
+.TP
.BI \-nullvalue\ string
Set string used to represent NULL values. Default is ''
(empty string).
.TP
+.BI \-pagecache\ SIZE N
+Use
+.I SIZE
+entries of
+.I N
+bytes each for page cache memory.
+.TP
+.B \-scanstats
+Print scan stats before each finalize.
+.TP
.BI \-separator\ separator
-Set output field separator. Default is '|'.
+Set output column separator. Default is '|'.
.TP
.B \-stats
Print memory stats before each finalize.
@@ -243,6 +275,9 @@ Show SQLite version.
Use
.I name
as the default VFS.
+.TP
+.B \-vfslog
+Enable the vfslog extension.
.SH INIT FILE
--- origsrc/sqlite-autoconf-3300000/sqlite3.c 2019-10-04 18:28:13.000000000 +0200
+++ src/sqlite-autoconf-3300000/sqlite3.c 2019-10-08 13:42:19.049022600 +0200
@@ -233,6 +233,9 @@ static const char * const sqlite3azCompi
#if SQLITE_ENABLE_CURSOR_HINTS
"ENABLE_CURSOR_HINTS",
#endif
+#if SQLITE_ENABLE_DBPAGE_VTAB
+ "ENABLE_DBPAGE_VTAB",
+#endif
#if SQLITE_ENABLE_DBSTAT_VTAB
"ENABLE_DBSTAT_VTAB",
#endif
@@ -275,9 +278,6 @@ static const char * const sqlite3azCompi
#if SQLITE_ENABLE_JSON1
"ENABLE_JSON1",
#endif
-#if SQLITE_ENABLE_LOAD_EXTENSION
- "ENABLE_LOAD_EXTENSION",
-#endif
#ifdef SQLITE_ENABLE_LOCKING_STYLE
"ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
#endif
@@ -344,7 +344,7 @@ static const char * const sqlite3azCompi
#if SQLITE_ENABLE_UNLOCK_NOTIFY
"ENABLE_UNLOCK_NOTIFY",
#endif
-#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
"ENABLE_UPDATE_DELETE_LIMIT",
#endif
#if SQLITE_ENABLE_URI_00_ERROR
@@ -1201,7 +1201,7 @@ extern "C" {
**
** See also: [sqlite_version()] and [sqlite_source_id()].
*/
-SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
+const char sqlite3_version[] = SQLITE_VERSION;
SQLITE_API const char *sqlite3_libversion(void);
SQLITE_API const char *sqlite3_sourceid(void);
SQLITE_API int sqlite3_libversion_number(void);
@@ -3075,6 +3075,8 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */
#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */
+#define SQLITE_CONFIG_MALLOC2 98 /* sqlite3_mem_methods2* */
+#define SQLITE_CONFIG_GETMALLOC2 99 /* sqlite3_mem_methods2* */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -3459,7 +3461,9 @@ SQLITE_API void sqlite3_set_last_insert_
** <li> the [data_version pragma]
** </ul>
*/
-SQLITE_API int sqlite3_changes(sqlite3*);
+SQLITE_API sqlite3_uint64 sqlite3_changes(sqlite3*);
+#define sqlite3_changes(db) ((int)(sqlite3_changes)(db))
+#define sqlite3_changes64(db) ((sqlite3_changes)(db))
/*
** CAPI3REF: Total Number Of Rows Modified
@@ -3496,7 +3500,9 @@ SQLITE_API int sqlite3_changes(sqlite3*)
** <li> the [SQLITE_FCNTL_DATA_VERSION] [file control]
** </ul>
*/
-SQLITE_API int sqlite3_total_changes(sqlite3*);
+SQLITE_API sqlite3_uint64 sqlite3_total_changes(sqlite3*);
+#define sqlite3_total_changes(db) ((int)(sqlite3_total_changes)(db))
+#define sqlite3_total_changes64(db) ((sqlite3_total_changes)(db))
/*
** CAPI3REF: Interrupt A Long-Running Query
@@ -5208,7 +5214,7 @@ typedef struct sqlite3_context sqlite3_c
** See also: [sqlite3_bind_parameter_count()],
** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()].
*/
-SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
+SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, unsigned int n, void(*)(void*));
SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
void(*)(void*));
SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
@@ -5786,8 +5792,8 @@ SQLITE_API sqlite3_int64 sqlite3_column_
SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
+SQLITE_API unsigned int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
+SQLITE_API unsigned int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
/*
@@ -5971,6 +5977,8 @@ SQLITE_API int sqlite3_create_function(
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
+/* A macro is more efficient than a wrapped call */
+#define sqlite3_create_function(a,b,c,d,e,f,g,h) sqlite3_create_function_v2(a,b,c,d,e,f,g,h,0)
SQLITE_API int sqlite3_create_function16(
sqlite3 *db,
const void *zFunctionName,
@@ -6065,9 +6073,12 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3
SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);
SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void);
+#define sqlite3_global_recover() SQLITE_OK
SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void);
+#define sqlite3_thread_cleanup() /**/
SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
void*,sqlite3_int64);
+#define sqlite3_memory_alarm(a,b,c) SQLITE_OK
#endif
/*
@@ -6207,8 +6218,8 @@ SQLITE_API const unsigned char *sqlite3_
SQLITE_API const void *sqlite3_value_text16(sqlite3_value*);
SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*);
SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*);
-SQLITE_API int sqlite3_value_bytes(sqlite3_value*);
-SQLITE_API int sqlite3_value_bytes16(sqlite3_value*);
+SQLITE_API unsigned int sqlite3_value_bytes(sqlite3_value*);
+SQLITE_API unsigned int sqlite3_value_bytes16(sqlite3_value*);
SQLITE_API int sqlite3_value_type(sqlite3_value*);
SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
SQLITE_API int sqlite3_value_nochange(sqlite3_value*);
@@ -6520,7 +6531,7 @@ typedef void (*sqlite3_destructor_type)(
** than the one containing the application-defined function that received
** the [sqlite3_context] pointer, the results are undefined.
*/
-SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
+SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, unsigned int, void(*)(void*));
SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*,
sqlite3_uint64,void(*)(void*));
SQLITE_API void sqlite3_result_double(sqlite3_context*, double);
@@ -6545,6 +6556,19 @@ SQLITE_API int sqlite3_result_zeroblob64
/*
+ * If we are not sure the platform is 32-bit, always use sqlite3_????64()
+ * in stead of sqlite3_????() for certain functions, in order to prevent overflow.
+ */
+#if !defined(i386) && !defined(__i386__) && !defined(_M_IX86) && \
+ !defined(_M_ARM) && !defined(__arm__) && !defined(__x86) && \
+ (!defined(__SIZEOF_POINTER__) || (__SIZEOF_POINTER__ != 4))
+# define sqlite3_bind_blob(pStmt, i, zData, nData, xDel) sqlite3_bind_blob64(pStmt, i, zData, nData, xDel)
+# define sqlite3_result_blob(pCtx, z, n, xDel) sqlite3_result_blob64(pCtx, z, n, xDel)
+# define sqlite3_malloc(x) sqlite3_malloc64(x)
+# define sqlite3_realloc(x,y) sqlite3_realloc64(x,y)
+#endif
+
+/*
** CAPI3REF: Setting The Subtype Of An SQL Function
** METHOD: sqlite3_context
**
@@ -6645,6 +6669,8 @@ SQLITE_API int sqlite3_create_collation(
void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*)
);
+/* A macro is more efficient than a wrapped call */
+#define sqlite3_create_collation(a,b,c,d,e) sqlite3_create_collation_v2(a,b,c,d,e,0)
SQLITE_API int sqlite3_create_collation_v2(
sqlite3*,
const char *zName,
@@ -6829,7 +6855,7 @@ SQLITE_API int sqlite3_sleep(int);
** sqlite3_temp_directory = sqlite3_mprintf("%s", zPathBuf);
** </pre></blockquote>
*/
-SQLITE_API char *sqlite3_temp_directory;
+char *sqlite3_temp_directory;
/*
** CAPI3REF: Name Of The Folder Holding Database Files
@@ -6866,7 +6892,7 @@ SQLITE_API char *sqlite3_temp_directory;
** made NULL or made to point to memory obtained from [sqlite3_malloc]
** or else the use of the [data_store_directory pragma] should be avoided.
*/
-SQLITE_API char *sqlite3_data_directory;
+char *sqlite3_data_directory;
/*
** CAPI3REF: Win32 Specific Interface
@@ -7219,6 +7245,7 @@ SQLITE_API sqlite3_int64 sqlite3_soft_he
*/
SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
+#define sqlite3_soft_heap_limit(N) sqlite3_soft_heap_limit64(N)
/*
** CAPI3REF: Extract Metadata About A Column Of A Table
@@ -7714,6 +7741,8 @@ SQLITE_API int sqlite3_create_module_v2(
void *pClientData, /* Client data for xCreate/xConnect */
void(*xDestroy)(void*) /* Module destructor function */
);
+/* A macro is more efficient than a (possible future) wrapped call */
+#define sqlite3_create_module(a,b,c,d) sqlite3_create_module_v2(a,b,c,d,0);
/*
** CAPI3REF: Remove Unnecessary Virtual Table Implementations
@@ -9728,6 +9757,8 @@ SQLITE_API int sqlite3_wal_autocheckpoin
** complication) of [sqlite3_wal_checkpoint_v2()].
*/
SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
+/* A macro is more efficient than a wrapped call */
+#define sqlite3_wal_checkpoint(a,b) sqlite3_wal_checkpoint_v2(a,b,SQLITE_CHECKPOINT_PASSIVE,0,0);
/*
** CAPI3REF: Checkpoint a database
@@ -12864,7 +12895,7 @@ struct fts5_api {
fts5_api *pApi,
const char *zName,
void *pContext,
- fts5_tokenizer *pTokenizer,
+ const fts5_tokenizer *pTokenizer,
void (*xDestroy)(void*)
);
@@ -12935,7 +12966,7 @@ struct fts5_api {
** to count the size: 2^31-1 or 2147483647.
*/
#ifndef SQLITE_MAX_LENGTH
-# define SQLITE_MAX_LENGTH 1000000000
+# define SQLITE_MAX_LENGTH 2147483647
#endif
/*
@@ -13039,7 +13070,7 @@ struct fts5_api {
** and we have to allow 2 extra counts for the "main" and "temp" databases.
*/
#ifndef SQLITE_MAX_ATTACHED
-# define SQLITE_MAX_ATTACHED 10
+# define SQLITE_MAX_ATTACHED 62
#endif
@@ -13086,7 +13117,7 @@ struct fts5_api {
** SQLite will choose on its own.
*/
#ifndef SQLITE_MAX_DEFAULT_PAGE_SIZE
-# define SQLITE_MAX_DEFAULT_PAGE_SIZE 8192
+# define SQLITE_MAX_DEFAULT_PAGE_SIZE 32768
#endif
#if SQLITE_MAX_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
# undef SQLITE_MAX_DEFAULT_PAGE_SIZE
@@ -13124,6 +13155,13 @@ struct fts5_api {
# define SQLITE_MAX_TRIGGER_DEPTH 1000
#endif
+/*
+** Maximum supported path-length..
+*/
+#ifndef SQLITE_MAX_PATH_LENGTH
+# define SQLITE_MAX_PATH_LENGTH 4096
+#endif
+
/************** End of sqliteLimit.h *****************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
@@ -13495,6 +13533,8 @@ SQLITE_PRIVATE void sqlite3Coverage(in
#ifndef SQLITE_HASH_H
#define SQLITE_HASH_H
+#include <stddef.h>
+
/* Forward declarations of structures. */
typedef struct Hash Hash;
typedef struct HashElem HashElem;
@@ -13521,11 +13561,11 @@ typedef struct HashElem HashElem;
** the hash table.
*/
struct Hash {
- unsigned int htsize; /* Number of buckets in the hash table */
- unsigned int count; /* Number of entries in this table */
+ size_t htsize; /* Number of buckets in the hash table */
+ size_t count; /* Number of entries in this table */
HashElem *first; /* The first element of the array */
struct _ht { /* the hash table */
- unsigned int count; /* Number of entries with this hash */
+ size_t count; /* Number of entries with this hash */
HashElem *chain; /* Pointer to first entry with this hash */
} *ht;
};
@@ -13764,7 +13804,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Has
#include <stdlib.h>
#include <string.h>
#include <assert.h>
-#include <stddef.h>
+/* #include <stddef.h> */
/*
** Use a macro to replace memcpy() if compiled with SQLITE_INLINE_MEMCPY.
@@ -14144,6 +14184,7 @@ typedef INT16_TYPE LogEst;
#ifndef SQLITE_MAX_MMAP_SIZE
# if defined(__linux__) \
|| defined(_WIN32) \
+ || defined(__CYGWIN__) \
|| (defined(__APPLE__) && defined(__MACH__)) \
|| defined(__sun) \
|| defined(__FreeBSD__) \
@@ -14489,7 +14530,7 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuu
#define BTREE_BLOBKEY 2 /* Table has keys only - no data */
SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*);
-SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*);
+SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, u64*);
SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor*);
SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree*, int, int);
@@ -14835,7 +14876,7 @@ struct VdbeOp {
#endif
int (*xAdvance)(BtCursor *, int);
} p4;
-#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+#if 1
char *zComment; /* Comment to improve readability */
#endif
#ifdef VDBE_PROFILE
@@ -15262,11 +15303,11 @@ SQLITE_PRIVATE int sqlite3MemCompare(con
SQLITE_PRIVATE int sqlite3BlobCompare(const Mem*, const Mem*);
SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
-SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);
-SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(int, const void *, UnpackedRecord *, int);
+SQLITE_PRIVATE int sqlite3VdbeRecordCompare(size_t,const void*,UnpackedRecord*);
+SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(size_t, const void *, UnpackedRecord *, int);
SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo*);
-typedef int (*RecordCompare)(int,const void*,UnpackedRecord*);
+typedef int (*RecordCompare)(size_t,const void*,UnpackedRecord*);
SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
#ifndef SQLITE_OMIT_TRIGGER
@@ -15282,7 +15323,7 @@ SQLITE_PRIVATE int sqlite3NotPureFunc(sq
** comments in VDBE programs that show key decision points in the code
** generator.
*/
-#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+#if 0
SQLITE_PRIVATE void sqlite3VdbeComment(Vdbe*, const char*, ...);
# define VdbeComment(X) sqlite3VdbeComment X
SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
@@ -15293,9 +15334,13 @@ SQLITE_PRIVATE void sqlite3VdbeNoopCom
# define VdbeModuleComment(X)
# endif
#else
-# define VdbeComment(X)
-# define VdbeNoopComment(X)
-# define VdbeModuleComment(X)
+# define VdbeComment(X) if (sqlite3GlobalConfig.bVdbeComments) sqlite3VdbeComment X
+# define VdbeNoopComment(X) if (sqlite3GlobalConfig.bVdbeComments) sqlite3VdbeNoopComment X
+# ifdef SQLITE_ENABLE_MODULE_COMMENTS
+# define VdbeModuleComment(X) if (sqlite3GlobalConfig.bVdbeComments) sqlite3VdbeNoopComment X
+#else
+# define VdbeModuleComment(X)
+#endif
#endif
/*
@@ -15698,7 +15743,7 @@ SQLITE_PRIVATE void sqlite3PcacheShutdow
/* Page cache buffer management:
** These routines implement SQLITE_CONFIG_PAGECACHE.
*/
-SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *, int sz, int n);
+SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *, size_t sz, int n);
/* Create a new pager cache.
** Under memory stress, invoke xStress to try to make pages clean.
@@ -15800,7 +15845,7 @@ SQLITE_PRIVATE void sqlite3PcacheShrink(
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/* Try to return memory used by the pcache module to the main memory heap */
-SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int);
+SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(size_t);
#endif
#ifdef SQLITE_TEST
@@ -15893,10 +15938,13 @@ SQLITE_PRIVATE int sqlite3PCacheIsDirty(
#if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER)
# define SQLITE_OS_OTHER 0
# ifndef SQLITE_OS_WIN
-# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \
+# if defined(_WIN32) || defined(WIN32) || defined(__MSVCRT__) || \
defined(__MINGW32__) || defined(__BORLANDC__)
# define SQLITE_OS_WIN 1
# define SQLITE_OS_UNIX 0
+# elif defined(__CYGWIN__)
+# define SQLITE_OS_WIN 1
+# define SQLITE_OS_UNIX 1
# else
# define SQLITE_OS_WIN 0
# define SQLITE_OS_UNIX 1
@@ -16147,7 +16195,7 @@ SQLITE_PRIVATE void sqlite3OsCloseFree(s
# define SQLITE_MUTEX_OMIT
#endif
#if SQLITE_THREADSAFE && !defined(SQLITE_MUTEX_NOOP)
-# if SQLITE_OS_UNIX
+# if SQLITE_OS_UNIX || (defined(__CYGWIN__) && !defined(SQLITE_TEST))
# define SQLITE_MUTEX_PTHREADS
# elif SQLITE_OS_WIN
# define SQLITE_MUTEX_W32
@@ -16218,7 +16266,7 @@ SQLITE_API int sqlite3_mutex_held(sqlite
** databases may be attached.
*/
struct Db {
- char *zDbSName; /* Name of this database. (schema name, not filename) */
+ const char *zDbSName; /* Name of this database. (schema name, not filename) */
Btree *pBt; /* The B*Tree structure for this database file */
u8 safety_level; /* How aggressive at syncing data to disk */
u8 bSyncSet; /* True if "PRAGMA synchronous=N" has been run */
@@ -16421,8 +16469,8 @@ struct sqlite3 {
u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */
int nextPagesize; /* Pagesize after VACUUM if >0 */
u32 magic; /* Magic number for detect library misuse */
- int nChange; /* Value returned by sqlite3_changes() */
- int nTotalChange; /* Value returned by sqlite3_total_changes() */
+ u64 nChange; /* Value returned by sqlite3_changes() */
+ u64 nTotalChange; /* Value returned by sqlite3_total_changes() */
int aLimit[SQLITE_N_LIMIT]; /* Limits */
int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */
struct sqlite3InitInfo { /* Information used during initialization */
@@ -16500,7 +16548,7 @@ struct sqlite3 {
int nStatement; /* Number of nested statement-transactions */
i64 nDeferredCons; /* Net deferred constraints this transaction. */
i64 nDeferredImmCons; /* Net deferred immediate constraints */
- int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
+ size_t *pnBytesFreed; /* If not NULL, increment this in DbFree() */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
/* The following variables are all protected by the STATIC_MASTER
** mutex, not by sqlite3.mutex. They are used by code in notify.c.
@@ -18084,7 +18132,7 @@ struct TriggerPrg {
/*
** The yDbMask datatype for the bitmask of all attached databases.
*/
-#if SQLITE_MAX_ATTACHED>30
+#if SQLITE_MAX_ATTACHED>62
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))
@@ -18092,7 +18140,11 @@ struct TriggerPrg {
# define DbMaskAllZero(M) sqlite3DbMaskAllZero(M)
# define DbMaskNonZero(M) (sqlite3DbMaskAllZero(M)==0)
#else
+#if SQLITE_MAX_ATTACHED>30
+ typedef u64 yDbMask;
+#else
typedef unsigned int yDbMask;
+#endif
# define DbMaskTest(M,I) (((M)&(((yDbMask)1)<<(I)))!=0)
# define DbMaskZero(M) (M)=0
# define DbMaskSet(M,I) (M)|=(((yDbMask)1)<<(I))
@@ -18136,7 +18188,7 @@ struct Parse {
int nErr; /* Number of errors seen */
int nTab; /* Number of previously allocated VDBE cursors */
int nMem; /* Number of memory cells used so far */
- int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */
+ size_t szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */
int iSelfTab; /* Table associated with an index on expr, or negative
** of the base register during check-constraint eval */
int nLabel; /* The *negative* of the number of labels used */
@@ -18408,8 +18460,8 @@ struct DbFixer {
struct sqlite3_str {
sqlite3 *db; /* Optional database for lookaside. Can be NULL */
char *zText; /* The string collected so far */
- u32 nAlloc; /* Amount of space allocated in zText */
- u32 mxAlloc; /* Maximum allowed allocation. 0 for no malloc usage */
+ size_t nAlloc; /* Amount of space allocated in zText */
+ size_t mxAlloc; /* Maximum allowed allocation. 0 for no malloc usage */
u32 nChar; /* Length of the string so far */
u8 accError; /* SQLITE_NOMEM or SQLITE_TOOBIG */
u8 printfFlags; /* SQLITE_PRINTF flags below */
@@ -18435,6 +18487,22 @@ typedef struct {
} InitData;
/*
+** Moved here from sqlite.h, made private on purpose
+*/
+
+typedef struct sqlite3_mem_methods2 sqlite3_mem_methods2;
+struct sqlite3_mem_methods2 {
+ void *(*xMalloc)(size_t); /* Memory allocation function */
+ void (*xFree)(void*); /* Free a prior allocation */
+ void *(*xRealloc)(void*,size_t);/* Resize an allocation */
+ size_t (*xSize)(void*); /* Return the size of an allocation */
+ size_t (*xRoundup)(size_t); /* Round up request size to allocation size */
+ int (*xInit)(void*); /* Initialize the memory allocator */
+ void (*xShutdown)(void*); /* Deinitialize the memory allocator */
+ void *pAppData; /* Argument to xInit() and xShutdown() */
+};
+
+/*
** Allowed values for mInitFlags
*/
#define INITFLAG_AlterTable 0x0001 /* This is a reparse after ALTER TABLE */
@@ -18458,6 +18526,7 @@ struct Sqlite3Config {
int nLookaside; /* Default lookaside buffer count */
int nStmtSpill; /* Stmt-journal spill-to-disk threshold */
sqlite3_mem_methods m; /* Low-level memory allocation interface */
+ sqlite3_mem_methods2 m2; /* Low-level memory allocation interface */
sqlite3_mutex_methods mutex; /* Low-level mutex interface */
sqlite3_pcache_methods2 pcache2; /* Low-level page-cache interface */
void *pHeap; /* Heap storage space */
@@ -18482,6 +18551,8 @@ struct Sqlite3Config {
sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */
void (*xLog)(void*,int,const char*); /* Function for logging */
void *pLogArg; /* First argument to xLog() */
+ int bVdbeComments; /* True to enable VDBE comments */
+ int bEnableUnknownSqlFunction; /* True to enable VDBE comments */
#ifdef SQLITE_ENABLE_SQLLOG
void(*xSqllog)(void*,sqlite3*,const char*, int);
void *pSqllogArg;
@@ -18498,8 +18569,8 @@ struct Sqlite3Config {
#endif
#ifndef SQLITE_UNTESTABLE
int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */
-#endif
int bLocaltimeFault; /* True to fail localtime() calls */
+#endif
int bInternalFunctions; /* Internal SQL functions are visible */
int iOnceResetThreshold; /* When to reset OP_Once counters */
u32 szSorterRef; /* Min size in bytes to use sorter-refs */
@@ -18771,29 +18842,29 @@ SQLITE_PRIVATE int sqlite3IsIdChar(u8);
** Internal function prototypes
*/
SQLITE_PRIVATE int sqlite3StrICmp(const char*,const char*);
-SQLITE_PRIVATE int sqlite3Strlen30(const char*);
+SQLITE_PRIVATE size_t sqlite3Strlen30(const char*);
#define sqlite3Strlen30NN(C) (strlen(C)&0x3fffffff)
-SQLITE_PRIVATE char *sqlite3ColumnType(Column*,char*);
+SQLITE_PRIVATE const char *sqlite3ColumnType(Column*,const char*);
#define sqlite3StrNICmp sqlite3_strnicmp
SQLITE_PRIVATE int sqlite3MallocInit(void);
SQLITE_PRIVATE void sqlite3MallocEnd(void);
-SQLITE_PRIVATE void *sqlite3Malloc(u64);
-SQLITE_PRIVATE void *sqlite3MallocZero(u64);
-SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3*, u64);
-SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3*, u64);
+SQLITE_PRIVATE void *sqlite3Malloc(size_t);
+SQLITE_PRIVATE void *sqlite3MallocZero(size_t);
+SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3*, size_t);
+SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3*, size_t);
SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3*, u64);
SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3*,const char*);
-SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, u64);
+SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, size_t);
SQLITE_PRIVATE char *sqlite3DbSpanDup(sqlite3*,const char*,const char*);
-SQLITE_PRIVATE void *sqlite3Realloc(void*, u64);
-SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64);
-SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64);
+SQLITE_PRIVATE void *sqlite3Realloc(void*, size_t);
+SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, size_t);
+SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, size_t);
SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*);
SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3*, void*);
-SQLITE_PRIVATE int sqlite3MallocSize(void*);
-SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, void*);
-SQLITE_PRIVATE void *sqlite3PageMalloc(int);
+SQLITE_PRIVATE size_t sqlite3MallocSize(void*);
+SQLITE_PRIVATE size_t sqlite3DbMallocSize(sqlite3*, void*);
+SQLITE_PRIVATE void *sqlite3PageMalloc(size_t);
SQLITE_PRIVATE void sqlite3PageFree(void*);
SQLITE_PRIVATE void sqlite3MemSetDefault(void);
#ifndef SQLITE_UNTESTABLE
@@ -18810,6 +18881,9 @@ SQLITE_PRIVATE int sqlite3HeapNearlyFull
** that deal with sqlite3StackAlloc() failures to be unreachable.
*/
#ifdef SQLITE_USE_ALLOCA
+#if !defined(alloca) && defined(_WIN32)
+# define alloca _alloca
+#endif
# define sqlite3StackAllocRaw(D,N) alloca(N)
# define sqlite3StackAllocZero(D,N) memset(alloca(N), 0, N)
# define sqlite3StackFree(D,P)
@@ -18823,11 +18897,11 @@ SQLITE_PRIVATE int sqlite3HeapNearlyFull
** are, disable MEMSYS3
*/
#ifdef SQLITE_ENABLE_MEMSYS5
-SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void);
+SQLITE_PRIVATE const sqlite3_mem_methods2 *sqlite3MemGetMemsys5(void);
#undef SQLITE_ENABLE_MEMSYS3
#endif
#ifdef SQLITE_ENABLE_MEMSYS3
-SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
+SQLITE_PRIVATE const sqlite3_mem_methods2 *sqlite3MemGetMemsys3(void);
#endif
@@ -18844,10 +18918,10 @@ SQLITE_PRIVATE void sqlite3MemoryBarri
# define sqlite3MemoryBarrier()
#endif
-SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int);
-SQLITE_PRIVATE void sqlite3StatusUp(int, int);
-SQLITE_PRIVATE void sqlite3StatusDown(int, int);
-SQLITE_PRIVATE void sqlite3StatusHighwater(int, int);
+SQLITE_PRIVATE size_t sqlite3StatusValue(int);
+SQLITE_PRIVATE void sqlite3StatusUp(int, size_t);
+SQLITE_PRIVATE void sqlite3StatusDown(int, size_t);
+SQLITE_PRIVATE void sqlite3StatusHighwater(int, size_t);
SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3*,int*);
/* Access to mutexes used by sqlite3_status() */
@@ -18895,7 +18969,7 @@ SQLITE_PRIVATE void sqlite3TreeViewBar
SQLITE_PRIVATE void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*);
SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView*, const SrcList*);
SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView*, const Select*, u8);
-SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView*, const With*, u8);
+SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView*, const With*);
#ifndef SQLITE_OMIT_WINDOWFUNC
SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView*, const Window*, u8);
SQLITE_PRIVATE void sqlite3TreeViewWinFunc(TreeView*, const Window*, u8);
@@ -19011,7 +19085,7 @@ SQLITE_PRIVATE int sqlite3ViewGetColum
# define sqlite3ViewGetColumnNames(A,B) 0
#endif
-#if SQLITE_MAX_ATTACHED>30
+#if SQLITE_MAX_ATTACHED>62
SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask);
#endif
SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int);
@@ -19052,7 +19126,7 @@ SQLITE_PRIVATE Table *sqlite3SrcListLook
SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int);
SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
-SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*);
+SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,const char*);
#endif
SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*);
SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*,
@@ -19324,7 +19398,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipColl
SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *);
SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3*);
SQLITE_PRIVATE int sqlite3CheckObjectName(Parse*, const char*,const char*,const char*);
-SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int);
+SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, u64);
SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64);
SQLITE_PRIVATE int sqlite3SubInt64(i64*,i64);
SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64);
@@ -19337,7 +19411,7 @@ SQLITE_PRIVATE void sqlite3FileSuffix3(c
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 size_t sqlite3ValueBytes(sqlite3_value*, u8);
SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
void(*)(void*));
SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value*);
@@ -19428,7 +19502,7 @@ SQLITE_PRIVATE void sqlite3OomClear(sqli
SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int);
SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *);
-SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
+SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, size_t, size_t);
SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*);
SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest*,int,int);
SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int);
@@ -19455,7 +19529,7 @@ SQLITE_PRIVATE char sqlite3IndexColumnAf
** The interface to the LEMON-generated parser
*/
#ifndef SQLITE_AMALGAMATION
-SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(u64), Parse*);
+SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(size_t), Parse*);
SQLITE_PRIVATE void sqlite3ParserFree(void*, void(*)(void*));
#endif
SQLITE_PRIVATE void sqlite3Parser(void*, int, Token);
@@ -19975,6 +20049,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3
SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */
SQLITE_STMTJRNL_SPILL, /* nStmtSpill */
{0,0,0,0,0,0,0,0}, /* m */
+ {0,0,0,0,0,0,0,0}, /* m2 */
{0,0,0,0,0,0,0,0,0}, /* mutex */
{0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
(void*)0, /* pHeap */
@@ -19998,6 +20073,16 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3
0, /* pInitMutex */
0, /* xLog */
0, /* pLogArg */
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+ 1, /* bVdbeComments */
+#else
+ 0, /* bVdbeComments */
+#endif
+#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+ 1, /* bEnableUnknownSqlFunction */
+#else
+ 0, /* bEnableUnknownSqlFunction */
+#endif
#ifdef SQLITE_ENABLE_SQLLOG
0, /* xSqllog */
0, /* pSqllogArg */
@@ -20011,8 +20096,8 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3
#endif
#ifndef SQLITE_UNTESTABLE
0, /* xTestCallback */
-#endif
0, /* bLocaltimeFault */
+#endif
0, /* bInternalFunctions */
0x7ffffffe, /* iOnceResetThreshold */
SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */
@@ -20270,8 +20355,8 @@ struct VdbeFrame {
int nMem; /* Number of entries in aMem */
int nChildMem; /* Number of memory cells for child frame */
int nChildCsr; /* Number of cursors for child frame */
- int nChange; /* Statement changes (Vdbe.nChange) */
- int nDbChange; /* Value of db->nChange */
+ u64 nChange; /* Statement changes (Vdbe.nChange) */
+ u64 nDbChange; /* Value of db->nChange */
};
/* Magic number for sanity checking on VdbeFrame objects */
@@ -20292,18 +20377,18 @@ struct sqlite3_value {
union MemValue {
double r; /* Real value used when MEM_Real is set in flags */
i64 i; /* Integer value used when MEM_Int is set in flags */
- int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */
+ size_t nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */
const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */
FuncDef *pDef; /* Used only when flags==MEM_Agg */
} u;
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
u8 eSubtype; /* Subtype for this value */
- int n; /* Number of characters in string value, excluding '\0' */
+ size_t n; /* Number of characters in string value, excluding '\0' */
char *z; /* String or BLOB value */
/* ShallowCopy only needs to copy the information above */
char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */
- int szMalloc; /* Size of the zMalloc allocation */
+ size_t szMalloc; /* Size of the zMalloc allocation */
u32 uTemp; /* Transient storage for serial_type in OP_MakeRecord */
sqlite3 *db; /* The associated database connection */
void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */
@@ -20378,7 +20463,8 @@ struct sqlite3_value {
** True if Mem X is a NULL-nochng type.
*/
#define MemNullNochng(X) \
- ((X)->flags==(MEM_Null|MEM_Zero) && (X)->n==0 && (X)->u.nZero==0)
+ (((X)->flags&MEM_TypeMask)==(MEM_Null|MEM_Zero) \
+ && (X)->n==0 && (X)->u.nZero==0)
/*
** Return true if a memory cell is not marked as invalid. This macro
@@ -20477,7 +20563,7 @@ struct Vdbe {
u32 cacheCtr; /* VdbeCursor row cache generation counter */
int pc; /* The program counter */
int rc; /* Value to return */
- int nChange; /* Number of db changes made since last reset */
+ u64 nChange; /* Number of db changes made since last reset */
int iStatement; /* Statement number (or 0 if has no opened stmt) */
i64 iCurrentTime; /* Value of julianday('now') for this statement */
i64 nFkConstraint; /* Number of imm. FK constraints this VM */
@@ -20576,7 +20662,7 @@ SQLITE_PRIVATE void sqlite3VdbeFreeCurso
void sqliteVdbePopStack(Vdbe*,int);
SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*);
-SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32);
+SQLITE_PRIVATE size_t sqlite3VdbeSerialTypeLen(u32);
SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8);
SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
@@ -20596,7 +20682,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemCopy(Me
SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int);
SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem*, Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem*);
-SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*));
+SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, size_t, u8, void(*)(void*));
SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64);
#ifdef SQLITE_OMIT_FLOATING_POINT
# define sqlite3VdbeMemSetDouble sqlite3VdbeMemSetInt64
@@ -20606,7 +20692,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetD
SQLITE_PRIVATE void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*));
SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem*,sqlite3*,u16);
SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*);
-SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int);
+SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,size_t);
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3VdbeMemIsRowSet(const Mem*);
#endif
@@ -20630,8 +20716,8 @@ SQLITE_PRIVATE int sqlite3VdbeMemAggValu
#ifndef SQLITE_OMIT_EXPLAIN
SQLITE_PRIVATE const char *sqlite3OpcodeName(int);
#endif
-SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
-SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int n);
+SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, size_t n, int preserve);
+SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, size_t n);
SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int);
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3VdbeFrameIsValid(VdbeFrame*);
@@ -20709,15 +20795,10 @@ SQLITE_PRIVATE int sqlite3VdbeMemExpan
/*
** Variables in which to record status information.
*/
-#if SQLITE_PTRSIZE>4
-typedef sqlite3_int64 sqlite3StatValueType;
-#else
-typedef u32 sqlite3StatValueType;
-#endif
typedef struct sqlite3StatType sqlite3StatType;
static SQLITE_WSD struct sqlite3StatType {
- sqlite3StatValueType nowValue[10]; /* Current value */
- sqlite3StatValueType mxValue[10]; /* Maximum value */
+ size_t nowValue[10]; /* Current value */
+ size_t mxValue[10]; /* Maximum value */
} sqlite3Stat = { {0,}, {0,} };
/*
@@ -20756,7 +20837,7 @@ static const char statMutex[] = {
** Return the current value of a status parameter. The caller must
** be holding the appropriate mutex.
*/
-SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int op){
+SQLITE_PRIVATE size_t sqlite3StatusValue(int op){
wsdStatInit;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
assert( op>=0 && op<ArraySize(statMutex) );
@@ -20776,7 +20857,7 @@ SQLITE_PRIVATE sqlite3_int64 sqlite3Stat
** The StatusDown() routine lowers the current value by N. The highwater
** mark is unchanged. N must be non-negative for StatusDown().
*/
-SQLITE_PRIVATE void sqlite3StatusUp(int op, int N){
+SQLITE_PRIVATE void sqlite3StatusUp(int op, size_t N){
wsdStatInit;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
assert( op>=0 && op<ArraySize(statMutex) );
@@ -20787,9 +20868,8 @@ SQLITE_PRIVATE void sqlite3StatusUp(int
wsdStat.mxValue[op] = wsdStat.nowValue[op];
}
}
-SQLITE_PRIVATE void sqlite3StatusDown(int op, int N){
+SQLITE_PRIVATE void sqlite3StatusDown(int op, size_t N){
wsdStatInit;
- assert( N>=0 );
assert( op>=0 && op<ArraySize(statMutex) );
assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
: sqlite3MallocMutex()) );
@@ -20801,11 +20881,8 @@ SQLITE_PRIVATE void sqlite3StatusDown(in
** Adjust the highwater mark if necessary.
** The caller must hold the appropriate mutex.
*/
-SQLITE_PRIVATE void sqlite3StatusHighwater(int op, int X){
- sqlite3StatValueType newValue;
+SQLITE_PRIVATE void sqlite3StatusHighwater(int op, size_t newValue){
wsdStatInit;
- assert( X>=0 );
- newValue = (sqlite3StatValueType)X;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
assert( op>=0 && op<ArraySize(statMutex) );
assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
@@ -20964,7 +21041,7 @@ SQLITE_API int sqlite3_db_status(
*/
case SQLITE_DBSTATUS_SCHEMA_USED: {
int i; /* Used to iterate through schemas */
- int nByte = 0; /* Used to accumulate return value */
+ size_t nByte = 0; /* Used to accumulate return value */
sqlite3BtreeEnterAll(db);
db->pnBytesFreed = &nByte;
@@ -20973,16 +21050,16 @@ SQLITE_API int sqlite3_db_status(
if( ALWAYS(pSchema!=0) ){
HashElem *p;
- nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * (
+ nByte += sqlite3GlobalConfig.m2.xRoundup(sizeof(HashElem)) * (
pSchema->tblHash.count
+ pSchema->trigHash.count
+ pSchema->idxHash.count
+ pSchema->fkeyHash.count
);
- nByte += sqlite3_msize(pSchema->tblHash.ht);
- nByte += sqlite3_msize(pSchema->trigHash.ht);
- nByte += sqlite3_msize(pSchema->idxHash.ht);
- nByte += sqlite3_msize(pSchema->fkeyHash.ht);
+ nByte += sqlite3MallocSize(pSchema->tblHash.ht);
+ nByte += sqlite3MallocSize(pSchema->trigHash.ht);
+ nByte += sqlite3MallocSize(pSchema->idxHash.ht);
+ nByte += sqlite3MallocSize(pSchema->fkeyHash.ht);
for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
@@ -20996,7 +21073,7 @@ SQLITE_API int sqlite3_db_status(
sqlite3BtreeLeaveAll(db);
*pHighwater = 0;
- *pCurrent = nByte;
+ *pCurrent = (int)nByte;
break;
}
@@ -21007,7 +21084,7 @@ SQLITE_API int sqlite3_db_status(
*/
case SQLITE_DBSTATUS_STMT_USED: {
struct Vdbe *pVdbe; /* Used to iterate through VMs */
- int nByte = 0; /* Used to accumulate return value */
+ size_t nByte = 0; /* Used to accumulate return value */
db->pnBytesFreed = &nByte;
for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
@@ -21017,7 +21094,7 @@ SQLITE_API int sqlite3_db_status(
db->pnBytesFreed = 0;
*pHighwater = 0; /* IMP: R-64479-57858 */
- *pCurrent = nByte;
+ *pCurrent = (int)nByte;
break;
}
@@ -21182,8 +21259,8 @@ struct DateTime {
*/
static int getDigits(const char *zDate, const char *zFormat, ...){
/* The aMx[] array translates the 3rd character of each format
- ** spec into a max size: a b c d e f */
- static const u16 aMx[] = { 12, 14, 24, 31, 59, 9999 };
+ ** spec into a max size: a b c d e f g */
+ static const u16 aMx[] = { 12, 14, 24, 31, 59, 9999, 60 };
va_list ap;
int cnt = 0;
char nextC;
@@ -21279,7 +21356,7 @@ static int parseHhMmSs(const char *zDate
zDate += 5;
if( *zDate==':' ){
zDate++;
- if( getDigits(zDate, "20e", &s)!=1 ){
+ if( getDigits(zDate, "20g", &s)!=1 ){
return 1;
}
zDate += 2;
@@ -21613,7 +21690,7 @@ static int osLocaltime(time_t *t, struct
#endif /* SQLITE_OMIT_LOCALTIME */
-#ifndef SQLITE_OMIT_LOCALTIME
+#if 1
/*
** Compute the difference (in milliseconds) between localtime and UTC
** (a.k.a. GMT) for the time value p where p is in UTC. If no error occurs,
@@ -21627,6 +21704,16 @@ static sqlite3_int64 localtimeOffset(
sqlite3_context *pCtx, /* Write error here if one occurs */
int *pRc /* OUT: Error code. SQLITE_OK or ERROR */
){
+#ifdef SQLITE_OMIT_LOCALTIME
+#ifndef SQLITE_UNTESTABLE
+ if( sqlite3GlobalConfig.bLocaltimeFault ) {
+ sqlite3_result_error(pCtx, "local time unavailable", -1);
+ *pRc = SQLITE_ERROR;
+ } else
+#endif
+ *pRc = SQLITE_OK;
+ return 0;
+#else
DateTime x, y;
time_t t;
struct tm sLocal;
@@ -21676,6 +21763,7 @@ static sqlite3_int64 localtimeOffset(
computeJD(&y);
*pRc = SQLITE_OK;
return y.iJD - x.iJD;
+#endif /* SQLITE_OMIT_LOCALTIME */
}
#endif /* SQLITE_OMIT_LOCALTIME */
@@ -21690,16 +21778,16 @@ static sqlite3_int64 localtimeOffset(
static const struct {
u8 eType; /* Transformation type code */
u8 nName; /* Length of th name */
- char *zName; /* Name of the transformation */
+ const char *zName; /* Name of the transformation */
double rLimit; /* Maximum NNN value for this transform */
double rXform; /* Constant used for this transform */
} aXformType[] = {
- { 0, 6, "second", 464269060800.0, 86400000.0/(24.0*60.0*60.0) },
- { 0, 6, "minute", 7737817680.0, 86400000.0/(24.0*60.0) },
- { 0, 4, "hour", 128963628.0, 86400000.0/24.0 },
+ { 0, 6, "second", 464269060800.0, 1000.0 },
+ { 0, 6, "minute", 7737817680.0, 60000.0 },
+ { 0, 4, "hour", 128963628.0, 3600000.0 },
{ 0, 3, "day", 5373485.0, 86400000.0 },
- { 1, 5, "month", 176546.0, 30.0*86400000.0 },
- { 2, 4, "year", 14713.0, 365.0*86400000.0 },
+ { 1, 5, "month", 176546.0, 2592000000.0 },
+ { 2, 4, "year", 14713.0, 31536000000.0 },
};
/*
@@ -21735,7 +21823,7 @@ static int parseModifier(
int rc = 1;
double r;
switch(sqlite3UpperToLower[(u8)z[0]] ){
-#ifndef SQLITE_OMIT_LOCALTIME
+#if 1
case 'l': {
/* localtime
**
@@ -21767,7 +21855,7 @@ static int parseModifier(
rc = 0;
}
}
-#ifndef SQLITE_OMIT_LOCALTIME
+#if 1
else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){
if( p->tzSet==0 ){
sqlite3_int64 c1;
@@ -22652,7 +22740,7 @@ SQLITE_PRIVATE void sqlite3OsCloseFree(s
** error in sqlite3_os_init() by the upper layers can be tested.
*/
SQLITE_PRIVATE int sqlite3OsInit(void){
- void *p = sqlite3_malloc(10);
+ void *p = sqlite3Malloc(10);
if( p==0 ) return SQLITE_NOMEM_BKPT;
sqlite3_free(p);
return sqlite3_os_init();
@@ -22877,11 +22965,11 @@ SQLITE_PRIVATE void sqlite3EndBenignMall
/*
** No-op versions of all memory allocation routines
*/
-static void *sqlite3MemMalloc(int nByte){ return 0; }
+static void *sqlite3MemMalloc(size_t nByte){ return 0; }
static void sqlite3MemFree(void *pPrior){ return; }
-static void *sqlite3MemRealloc(void *pPrior, int nByte){ return 0; }
-static int sqlite3MemSize(void *pPrior){ return 0; }
-static int sqlite3MemRoundup(int n){ return n; }
+static void *sqlite3MemRealloc(void *pPrior, size_t nByte){ return 0; }
+static size_t sqlite3MemSize(void *pPrior){ return 0; }
+static size_t sqlite3MemRoundup(size_t n){ return n; }
static int sqlite3MemInit(void *NotUsed){ return SQLITE_OK; }
static void sqlite3MemShutdown(void *NotUsed){ return; }
@@ -22892,7 +22980,7 @@ static void sqlite3MemShutdown(void *Not
** sqlite3GlobalConfig.m with pointers to the routines in this file.
*/
SQLITE_PRIVATE void sqlite3MemSetDefault(void){
- static const sqlite3_mem_methods defaultMethods = {
+ static const sqlite3_mem_methods2 defaultMethods = {
sqlite3MemMalloc,
sqlite3MemFree,
sqlite3MemRealloc,
@@ -22902,7 +22990,7 @@ SQLITE_PRIVATE void sqlite3MemSetDefault
sqlite3MemShutdown,
0
};
- sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
+ sqlite3_config(SQLITE_CONFIG_MALLOC2, &defaultMethods);
}
#endif /* SQLITE_ZERO_MALLOC */
@@ -23001,7 +23089,7 @@ static malloc_zone_t* _sqliteZone_;
** -DSQLITE_WITHOUT_MSIZE. Using the _msize() function also requires
** the malloc.h header file.
*/
-#elif defined(_MSC_VER) && !defined(SQLITE_WITHOUT_MSIZE)
+#elif (defined(_MSC_VER) || defined(__MSVCRT__)) && !defined(SQLITE_WITHOUT_MSIZE)
# define SQLITE_USE_MALLOC_H
# define SQLITE_USE_MSIZE
#endif
@@ -23015,6 +23103,9 @@ static malloc_zone_t* _sqliteZone_;
*/
#if defined(SQLITE_USE_MALLOC_H)
# include <malloc.h>
+#if !defined(alloca) && defined(_WIN32)
+# define alloca _alloca
+#endif
# if defined(SQLITE_USE_MALLOC_USABLE_SIZE)
# if !defined(SQLITE_MALLOCSIZE)
# define SQLITE_MALLOCSIZE(x) malloc_usable_size(x)
@@ -23036,14 +23127,14 @@ static malloc_zone_t* _sqliteZone_;
** cases of nByte<=0 will be intercepted and dealt with by higher level
** routines.
*/
-static void *sqlite3MemMalloc(int nByte){
+static void *sqlite3MemMalloc(size_t nByte){
#ifdef SQLITE_MALLOCSIZE
void *p;
testcase( ROUND8(nByte)==nByte );
p = SQLITE_MALLOC( nByte );
if( p==0 ){
testcase( sqlite3GlobalConfig.xLog!=0 );
- sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
+ sqlite3_log(SQLITE_NOMEM, "failed to allocate %llu bytes of memory", (u64)nByte);
}
return p;
#else
@@ -23056,7 +23147,7 @@ static void *sqlite3MemMalloc(int nByte)
p++;
}else{
testcase( sqlite3GlobalConfig.xLog!=0 );
- sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
+ sqlite3_log(SQLITE_NOMEM, "failed to allocate %llu bytes of memory", (u64)nByte);
}
return (void *)p;
#endif
@@ -23085,16 +23176,16 @@ static void sqlite3MemFree(void *pPrior)
** Report the allocated size of a prior return from xMalloc()
** or xRealloc().
*/
-static int sqlite3MemSize(void *pPrior){
+static size_t sqlite3MemSize(void *pPrior){
#ifdef SQLITE_MALLOCSIZE
assert( pPrior!=0 );
- return (int)SQLITE_MALLOCSIZE(pPrior);
+ return SQLITE_MALLOCSIZE(pPrior);
#else
sqlite3_int64 *p;
assert( pPrior!=0 );
p = (sqlite3_int64*)pPrior;
p--;
- return (int)p[0];
+ return (size_t)p[0];
#endif
}
@@ -23108,14 +23199,14 @@ static int sqlite3MemSize(void *pPrior){
** cases where nByte<=0 will have been intercepted by higher-level
** routines and redirected to xFree.
*/
-static void *sqlite3MemRealloc(void *pPrior, int nByte){
+static void *sqlite3MemRealloc(void *pPrior, size_t nByte){
#ifdef SQLITE_MALLOCSIZE
void *p = SQLITE_REALLOC(pPrior, nByte);
if( p==0 ){
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(SQLITE_NOMEM,
- "failed memory resize %u to %u bytes",
- SQLITE_MALLOCSIZE(pPrior), nByte);
+ "failed memory resize %llu to %llu bytes",
+ (u64)SQLITE_MALLOCSIZE(pPrior), (u64)nByte);
}
return p;
#else
@@ -23130,8 +23221,8 @@ static void *sqlite3MemRealloc(void *pPr
}else{
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(SQLITE_NOMEM,
- "failed memory resize %u to %u bytes",
- sqlite3MemSize(pPrior), nByte);
+ "failed memory resize %llu to %llu bytes",
+ (u64)sqlite3MemSize(pPrior), (u64)nByte);
}
return (void*)p;
#endif
@@ -23140,7 +23231,7 @@ static void *sqlite3MemRealloc(void *pPr
/*
** Round up a request size to the next valid allocation size.
*/
-static int sqlite3MemRoundup(int n){
+static size_t sqlite3MemRoundup(size_t n){
return ROUND8(n);
}
@@ -23186,7 +23277,7 @@ static void sqlite3MemShutdown(void *Not
** sqlite3GlobalConfig.m with pointers to the routines in this file.
*/
SQLITE_PRIVATE void sqlite3MemSetDefault(void){
- static const sqlite3_mem_methods defaultMethods = {
+ static const sqlite3_mem_methods2 defaultMethods = {
sqlite3MemMalloc,
sqlite3MemFree,
sqlite3MemRealloc,
@@ -23196,7 +23287,7 @@ SQLITE_PRIVATE void sqlite3MemSetDefault
sqlite3MemShutdown,
0
};
- sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
+ sqlite3_config(SQLITE_CONFIG_MALLOC2, &defaultMethods);
}
#endif /* SQLITE_SYSTEM_MALLOC */
@@ -23258,20 +23349,20 @@ SQLITE_PRIVATE void sqlite3MemSetDefault
** MemBlockHdr.
*/
struct MemBlockHdr {
- i64 iSize; /* Size of this allocation */
+ size_t iSize; /* Size of this allocation */
struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */
char nBacktrace; /* Number of backtraces on this alloc */
char nBacktraceSlots; /* Available backtrace slots */
u8 nTitle; /* Bytes of title; includes '\0' */
u8 eType; /* Allocation type code */
- int iForeGuard; /* Guard word for sanity */
+ unsigned int iForeGuard; /* Guard word for sanity */
};
/*
** Guard words
*/
-#define FOREGUARD 0x80F5E153
-#define REARGUARD 0xE4676B53
+#define FOREGUARD 0x80F5E153U
+#define REARGUARD 0xE4676B53U
/*
** Number of malloc size increments to track.
@@ -23356,13 +23447,16 @@ static void adjustStats(int iSize, int i
*/
static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){
struct MemBlockHdr *p;
+#ifndef NDEBUG
int *pInt;
u8 *pU8;
- int nReserve;
+ size_t nReserve;
+#endif /* NDEBUG */
p = (struct MemBlockHdr*)pAllocation;
p--;
- assert( p->iForeGuard==(int)FOREGUARD );
+#ifndef NDEBUG
+ assert( p->iForeGuard==FOREGUARD );
nReserve = ROUND8(p->iSize);
pInt = (int*)pAllocation;
pU8 = (u8*)pAllocation;
@@ -23372,19 +23466,20 @@ static struct MemBlockHdr *sqlite3Memsys
** they haven't been overwritten.
*/
while( nReserve-- > p->iSize ) assert( pU8[nReserve]==0x65 );
+#endif /* NDEBUG */
return p;
}
/*
** Return the number of bytes currently allocated at address p.
*/
-static int sqlite3MemSize(void *p){
+static size_t sqlite3MemSize(void *p){
struct MemBlockHdr *pHdr;
if( !p ){
return 0;
}
pHdr = sqlite3MemsysGetHeader(p);
- return (int)pHdr->iSize;
+ return (size_t)pHdr->iSize;
}
/*
@@ -23412,7 +23507,7 @@ static void sqlite3MemShutdown(void *Not
/*
** Round up a request size to the next valid allocation size.
*/
-static int sqlite3MemRoundup(int n){
+static size_t sqlite3MemRoundup(size_t n){
return ROUND8(n);
}
@@ -23421,7 +23516,7 @@ static int sqlite3MemRoundup(int n){
** the content of a new memory allocation to unpredictable values and
** to clear the content of a freed allocation to unpredictable values.
*/
-static void randomFill(char *pBuf, int nByte){
+static void randomFill(char *pBuf, size_t nByte){
unsigned int x, y, r;
x = SQLITE_PTR_TO_INT(pBuf);
y = nByte | 1;
@@ -23444,14 +23539,14 @@ static void randomFill(char *pBuf, int n
/*
** Allocate nByte bytes of memory.
*/
-static void *sqlite3MemMalloc(int nByte){
+static void *sqlite3MemMalloc(size_t nByte){
struct MemBlockHdr *pHdr;
void **pBt;
char *z;
int *pInt;
void *p = 0;
- int totalSize;
- int nReserve;
+ size_t totalSize;
+ size_t nReserve;
sqlite3_mutex_enter(mem.mutex);
assert( mem.disallow==0 );
nReserve = ROUND8(nByte);
@@ -23545,7 +23640,7 @@ static void sqlite3MemFree(void *pPrior)
** much more likely to break and we are much more liking to find
** the error.
*/
-static void *sqlite3MemRealloc(void *pPrior, int nByte){
+static void *sqlite3MemRealloc(void *pPrior, size_t nByte){
struct MemBlockHdr *pOldHdr;
void *pNew;
assert( mem.disallow==0 );
@@ -23567,7 +23662,7 @@ static void *sqlite3MemRealloc(void *pPr
** sqlite3GlobalConfig.m with pointers to the routines in this file.
*/
SQLITE_PRIVATE void sqlite3MemSetDefault(void){
- static const sqlite3_mem_methods defaultMethods = {
+ static const sqlite3_mem_methods2 defaultMethods = {
sqlite3MemMalloc,
sqlite3MemFree,
sqlite3MemRealloc,
@@ -23577,14 +23672,14 @@ SQLITE_PRIVATE void sqlite3MemSetDefault
sqlite3MemShutdown,
0
};
- sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
+ sqlite3_config(SQLITE_CONFIG_MALLOC2, &defaultMethods);
}
/*
** Set the "type" of an allocation.
*/
SQLITE_PRIVATE void sqlite3MemdebugSetType(void *p, u8 eType){
- if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
+ if( p && sqlite3GlobalConfig.m2.xMalloc==sqlite3MemMalloc ){
struct MemBlockHdr *pHdr;
pHdr = sqlite3MemsysGetHeader(p);
assert( pHdr->iForeGuard==FOREGUARD );
@@ -23603,7 +23698,7 @@ SQLITE_PRIVATE void sqlite3MemdebugSetTy
*/
SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){
int rc = 1;
- if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
+ if( p && sqlite3GlobalConfig.m2.xMalloc==sqlite3MemMalloc ){
struct MemBlockHdr *pHdr;
pHdr = sqlite3MemsysGetHeader(p);
assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
@@ -23625,7 +23720,7 @@ SQLITE_PRIVATE int sqlite3MemdebugHasTyp
*/
SQLITE_PRIVATE int sqlite3MemdebugNoType(void *p, u8 eType){
int rc = 1;
- if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
+ if( p && sqlite3GlobalConfig.m2.xMalloc==sqlite3MemMalloc ){
struct MemBlockHdr *pHdr;
pHdr = sqlite3MemsysGetHeader(p);
assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
@@ -23692,8 +23787,8 @@ SQLITE_PRIVATE void sqlite3MemdebugDump(
for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){
char *z = (char*)pHdr;
z -= pHdr->nBacktraceSlots*sizeof(void*) + pHdr->nTitle;
- fprintf(out, "**** %lld bytes at %p from %s ****\n",
- pHdr->iSize, &pHdr[1], pHdr->nTitle ? z : "???");
+ fprintf(out, "**** %llu bytes at %p from %s ****\n",
+ (u64)pHdr->iSize, &pHdr[1], pHdr->nTitle ? z : "???");
if( pHdr->nBacktrace ){
fflush(out);
pBt = (void**)pHdr;
@@ -23968,12 +24063,14 @@ static void memsys3Leave(void){
/*
** Called when we are unable to satisfy an allocation of nBytes.
*/
-static void memsys3OutOfMemory(int nByte){
+static void memsys3OutOfMemory(size_t nByte){
if( !mem3.alarmBusy ){
mem3.alarmBusy = 1;
assert( sqlite3_mutex_held(mem3.mutex) );
sqlite3_mutex_leave(mem3.mutex);
- sqlite3_release_memory(nByte);
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ sqlite3PcacheReleaseMemory(nByte);
+#endif
sqlite3_mutex_enter(mem3.mutex);
mem3.alarmBusy = 0;
}
@@ -24087,9 +24184,9 @@ static void memsys3Merge(u32 *pRoot){
** This function assumes that the necessary mutexes, if any, are
** already held by the caller. Hence "Unsafe".
*/
-static void *memsys3MallocUnsafe(int nByte){
+static void *memsys3MallocUnsafe(size_t nByte){
u32 i;
- u32 nBlock;
+ size_t nBlock;
u32 toFree;
assert( sqlite3_mutex_held(mem3.mutex) );
@@ -24113,7 +24210,7 @@ static void *memsys3MallocUnsafe(int nBy
return memsys3Checkout(i, nBlock);
}
}else{
- int hash = nBlock % N_HASH;
+ size_t hash = nBlock % N_HASH;
for(i=mem3.aiHash[hash]; i>0; i=mem3.aPool[i].u.list.next){
if( mem3.aPool[i-1].u.hdr.size4x/4==nBlock ){
memsys3UnlinkFromList(i, &mem3.aiHash[hash]);
@@ -24210,7 +24307,7 @@ static void memsys3FreeUnsafe(void *pOld
** size returned omits the 8-byte header overhead. This only
** works for chunks that are currently checked out.
*/
-static int memsys3Size(void *p){
+static size_t memsys3Size(void *p){
Mem3Block *pBlock;
assert( p!=0 );
pBlock = (Mem3Block*)p;
@@ -24221,7 +24318,7 @@ static int memsys3Size(void *p){
/*
** Round up a request size to the next valid allocation size.
*/
-static int memsys3Roundup(int n){
+static size_t memsys3Roundup(size_t n){
if( n<=12 ){
return 12;
}else{
@@ -24232,7 +24329,7 @@ static int memsys3Roundup(int n){
/*
** Allocate nBytes of memory.
*/
-static void *memsys3Malloc(int nBytes){
+static void *memsys3Malloc(size_t nBytes){
sqlite3_int64 *p;
assert( nBytes>0 ); /* malloc.c filters out 0 byte requests */
memsys3Enter();
@@ -24254,11 +24351,11 @@ static void memsys3Free(void *pPrior){
/*
** Change the size of an existing memory allocation
*/
-static void *memsys3Realloc(void *pPrior, int nBytes){
- int nOld;
+static void *memsys3Realloc(void *pPrior, size_t nBytes){
+ size_t nOld;
void *p;
if( pPrior==0 ){
- return sqlite3_malloc(nBytes);
+ return memsys3Malloc(nBytes);
}
if( nBytes<=0 ){
sqlite3_free(pPrior);
@@ -24322,8 +24419,8 @@ static void memsys3Shutdown(void *NotUse
** Open the file indicated and write a log of all unfreed memory
** allocations into that log.
*/
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){
-#ifdef SQLITE_DEBUG
FILE *out;
u32 i, j;
u32 size;
@@ -24390,10 +24487,8 @@ SQLITE_PRIVATE void sqlite3Memsys3Dump(c
}else{
fclose(out);
}
-#else
- UNUSED_PARAMETER(zFilename);
-#endif
}
+#endif
/*
** This routine is the only routine in this file with external
@@ -24406,8 +24501,8 @@ SQLITE_PRIVATE void sqlite3Memsys3Dump(c
** This routine is only called by sqlite3_config(), and therefore
** is not required to be threadsafe (it is not).
*/
-SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){
- static const sqlite3_mem_methods mempoolMethods = {
+SQLITE_PRIVATE const sqlite3_mem_methods2 *sqlite3MemGetMemsys3(void){
+ static const sqlite3_mem_methods2 mempoolMethods = {
memsys3Malloc,
memsys3Free,
memsys3Realloc,
@@ -24519,8 +24614,8 @@ static SQLITE_WSD struct Mem5Global {
/*
** Memory available for allocation
*/
- int szAtom; /* Smallest possible allocation in bytes */
- int nBlock; /* Number of szAtom sized blocks in zPool */
+ size_t szAtom; /* Smallest possible allocation in bytes */
+ size_t nBlock; /* Number of szAtom sized blocks in zPool */
u8 *zPool; /* Memory available to be allocated */
/*
@@ -24539,7 +24634,7 @@ static SQLITE_WSD struct Mem5Global {
u32 currentCount; /* Current number of distinct checkouts */
u32 maxOut; /* Maximum instantaneous currentOut */
u32 maxCount; /* Maximum instantaneous currentCount */
- u32 maxRequest; /* Largest allocation (exclusive of internal frag) */
+ size_t maxRequest; /* Largest allocation (exclusive of internal frag) */
#endif
/*
@@ -24572,10 +24667,10 @@ static SQLITE_WSD struct Mem5Global {
** Unlink the chunk at mem5.aPool[i] from list it is currently
** on. It should be found on mem5.aiFreelist[iLogsize].
*/
-static void memsys5Unlink(int i, int iLogsize){
+static void memsys5Unlink(size_t i, size_t iLogsize){
int next, prev;
- assert( i>=0 && i<mem5.nBlock );
- assert( iLogsize>=0 && iLogsize<=LOGMAX );
+ assert( i<mem5.nBlock );
+ assert( iLogsize<=LOGMAX );
assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );
next = MEM5LINK(i)->next;
@@ -24624,8 +24719,9 @@ static void memsys5Leave(void){
** Return the size of an outstanding allocation, in bytes.
** This only works for chunks that are currently checked out.
*/
-static int memsys5Size(void *p){
- int iSize, i;
+static size_t memsys5Size(void *p){
+ size_t iSize;
+ int i;
assert( p!=0 );
i = (int)(((u8 *)p-mem5.zPool)/mem5.szAtom);
assert( i>=0 && i<mem5.nBlock );
@@ -24643,22 +24739,24 @@ static int memsys5Size(void *p){
** routine so there is never any chance that two or more
** threads can be in this routine at the same time.
*/
-static void *memsys5MallocUnsafe(int nByte){
+static void *memsys5MallocUnsafe(size_t nByte){
int i; /* Index of a mem5.aPool[] slot */
int iBin; /* Index into mem5.aiFreelist[] */
- int iFullSz; /* Size of allocation rounded up to power of 2 */
+ size_t iFullSz; /* Size of allocation rounded up to power of 2 */
int iLogsize; /* Log2 of iFullSz/POW2_MIN */
/* nByte must be a positive */
assert( nByte>0 );
+#if 0
/* No more than 1GiB per allocation */
if( nByte > 0x40000000 ) return 0;
+#endif
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
/* Keep track of the maximum allocation request. Even unfulfilled
** requests are counted */
- if( (u32)nByte>mem5.maxRequest ){
+ if( nByte>mem5.maxRequest ){
mem5.maxRequest = nByte;
}
#endif
@@ -24680,10 +24778,10 @@ static void *memsys5MallocUnsafe(int nBy
i = mem5.aiFreelist[iBin];
memsys5Unlink(i, iBin);
while( iBin>iLogsize ){
- int newSize;
+ size_t newSize;
iBin--;
- newSize = 1 << iBin;
+ newSize = (size_t)1 << iBin;
mem5.aCtrl[i+newSize] = CTRL_FREE | iBin;
memsys5Link(i+newSize, iBin);
}
@@ -24714,21 +24812,21 @@ static void *memsys5MallocUnsafe(int nBy
** Free an outstanding memory allocation.
*/
static void memsys5FreeUnsafe(void *pOld){
- u32 size, iLogsize;
- int iBlock;
+ size_t size, iLogsize;
+ size_t iBlock;
/* Set iBlock to the index of the block pointed to by pOld in
** the array of mem5.szAtom byte blocks pointed to by mem5.zPool.
*/
- iBlock = (int)(((u8 *)pOld-mem5.zPool)/mem5.szAtom);
+ iBlock = (((u8 *)pOld-mem5.zPool)/mem5.szAtom);
/* Check that the pointer pOld points to a valid, non-free block. */
- assert( iBlock>=0 && iBlock<mem5.nBlock );
+ assert( iBlock<mem5.nBlock );
assert( ((u8 *)pOld-mem5.zPool)%mem5.szAtom==0 );
assert( (mem5.aCtrl[iBlock] & CTRL_FREE)==0 );
iLogsize = mem5.aCtrl[iBlock] & CTRL_LOGSIZE;
- size = 1<<iLogsize;
+ size = (size_t)1<<iLogsize;
assert( iBlock+size-1<(u32)mem5.nBlock );
mem5.aCtrl[iBlock] |= CTRL_FREE;
@@ -24745,7 +24843,7 @@ static void memsys5FreeUnsafe(void *pOld
mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
while( ALWAYS(iLogsize<LOGMAX) ){
- int iBuddy;
+ size_t iBuddy;
if( (iBlock>>iLogsize) & 1 ){
iBuddy = iBlock - size;
assert( iBuddy>=0 );
@@ -24779,7 +24877,7 @@ static void memsys5FreeUnsafe(void *pOld
/*
** Allocate nBytes of memory.
*/
-static void *memsys5Malloc(int nBytes){
+static void *memsys5Malloc(size_t nBytes){
sqlite3_int64 *p = 0;
if( nBytes>0 ){
memsys5Enter();
@@ -24814,8 +24912,8 @@ static void memsys5Free(void *pPrior){
** (an allocation larger than 0x40000000) was requested and this
** routine should return 0 without freeing pPrior.
*/
-static void *memsys5Realloc(void *pPrior, int nBytes){
- int nOld;
+static void *memsys5Realloc(void *pPrior, size_t nBytes){
+ unsigned int nOld;
void *p;
assert( pPrior!=0 );
assert( (nBytes&(nBytes-1))==0 ); /* EV: R-46199-30249 */
@@ -24844,9 +24942,8 @@ static void *memsys5Realloc(void *pPrior
** 32-bit signed integer. Hence the largest allocation is 0x40000000
** or 1073741824 bytes.
*/
-static int memsys5Roundup(int n){
- int iFullSz;
- if( n > 0x40000000 ) return 0;
+static size_t memsys5Roundup(size_t n){
+ size_t iFullSz;
for(iFullSz=mem5.szAtom; iFullSz<n; iFullSz *= 2);
return iFullSz;
}
@@ -24861,9 +24958,9 @@ static int memsys5Roundup(int n){
** memsys5Log(8) -> 3
** memsys5Log(9) -> 4
*/
-static int memsys5Log(int iValue){
+static int memsys5Log(size_t iValue){
int iLog;
- for(iLog=0; (iLog<(int)((sizeof(int)*8)-1)) && (1<<iLog)<iValue; iLog++);
+ for(iLog=0; (iLog<(int)((sizeof(int)*8)-1)) && ((size_t)1<<iLog)<iValue; iLog++);
return iLog;
}
@@ -24875,10 +24972,10 @@ static int memsys5Log(int iValue){
*/
static int memsys5Init(void *NotUsed){
int ii; /* Loop counter */
- int nByte; /* Number of bytes of memory available to this allocator */
+ size_t nByte; /* Number of bytes of memory available to this allocator */
u8 *zByte; /* Memory usable by this allocator */
int nMinLog; /* Log base 2 of minimum allocation size in bytes */
- int iOffset; /* An offset into mem5.aCtrl[] */
+ size_t iOffset; /* An offset into mem5.aCtrl[] */
UNUSED_PARAMETER(NotUsed);
@@ -24896,8 +24993,8 @@ static int memsys5Init(void *NotUsed){
/* boundaries on sqlite3GlobalConfig.mnReq are enforced in sqlite3_config() */
nMinLog = memsys5Log(sqlite3GlobalConfig.mnReq);
- mem5.szAtom = (1<<nMinLog);
- while( (int)sizeof(Mem5Link)>mem5.szAtom ){
+ mem5.szAtom = ((size_t)1<<nMinLog);
+ while( sizeof(Mem5Link)>mem5.szAtom ){
mem5.szAtom = mem5.szAtom << 1;
}
@@ -24911,7 +25008,7 @@ static int memsys5Init(void *NotUsed){
iOffset = 0;
for(ii=LOGMAX; ii>=0; ii--){
- int nAlloc = (1<<ii);
+ size_t nAlloc = ((size_t)1<<ii);
if( (iOffset+nAlloc)<=mem5.nBlock ){
mem5.aCtrl[iOffset] = ii | CTRL_FREE;
memsys5Link(iOffset, ii);
@@ -24963,14 +25060,14 @@ SQLITE_PRIVATE void sqlite3Memsys5Dump(c
for(n=0, j=mem5.aiFreelist[i]; j>=0; j = MEM5LINK(j)->next, n++){}
fprintf(out, "freelist items of size %d: %d\n", mem5.szAtom << i, n);
}
- fprintf(out, "mem5.nAlloc = %llu\n", mem5.nAlloc);
- fprintf(out, "mem5.totalAlloc = %llu\n", mem5.totalAlloc);
- fprintf(out, "mem5.totalExcess = %llu\n", mem5.totalExcess);
+ fprintf(out, "mem5.nAlloc = %llu\n", (u64)mem5.nAlloc);
+ fprintf(out, "mem5.totalAlloc = %llu\n", (u64)mem5.totalAlloc);
+ fprintf(out, "mem5.totalExcess = %llu\n", (u64)mem5.totalExcess);
fprintf(out, "mem5.currentOut = %u\n", mem5.currentOut);
fprintf(out, "mem5.currentCount = %u\n", mem5.currentCount);
fprintf(out, "mem5.maxOut = %u\n", mem5.maxOut);
fprintf(out, "mem5.maxCount = %u\n", mem5.maxCount);
- fprintf(out, "mem5.maxRequest = %u\n", mem5.maxRequest);
+ fprintf(out, "mem5.maxRequest = %llu\n", (u64)mem5.maxRequest);
memsys5Leave();
if( out==stdout ){
fflush(stdout);
@@ -24985,8 +25082,8 @@ SQLITE_PRIVATE void sqlite3Memsys5Dump(c
** linkage. It returns a pointer to a static sqlite3_mem_methods
** struct populated with the memsys5 methods.
*/
-SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void){
- static const sqlite3_mem_methods memsys5Methods = {
+SQLITE_PRIVATE const sqlite3_mem_methods2 *sqlite3MemGetMemsys5(void){
+ static const sqlite3_mem_methods2 memsys5Methods = {
memsys5Malloc,
memsys5Free,
memsys5Realloc,
@@ -26227,9 +26324,16 @@ SQLITE_API extern int sqlite3_open_file_
*/
#include "windows.h"
+#include <errno.h> /* amalgamator: dontcache */
#ifdef __CYGWIN__
# include <sys/cygwin.h>
-# include <errno.h> /* amalgamator: dontcache */
+# include <sys/stat.h> /* amalgamator: dontcache */
+# include <unistd.h> /* amalgamator: dontcache */
+#elif defined(_WIN32)
+enum {
+ CCP_POSIX_TO_WIN_W = 1, /* from is char*, to is wchar_t* */
+ CCP_RELATIVE = 0x100 /* Request to keep path relative. */
+};
#endif
/*
@@ -26286,7 +26390,7 @@ SQLITE_API extern int sqlite3_open_file_
** functions are not available (e.g. those not using MSVC, Cygwin, etc).
*/
#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \
- SQLITE_THREADSAFE>0 && !defined(__CYGWIN__)
+ SQLITE_THREADSAFE>0 && (defined(_MSC_VER) || defined(__MSVCRT__))
# define SQLITE_OS_WIN_THREADS 1
#else
# define SQLITE_OS_WIN_THREADS 0
@@ -26309,8 +26413,10 @@ SQLITE_API extern int sqlite3_open_file_
*/
struct sqlite3_mutex {
CRITICAL_SECTION mutex; /* Mutex controlling the lock */
+#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_API_ARMOR)
int id; /* Mutex type */
-#ifdef SQLITE_DEBUG
+#endif
+#if defined(SQLITE_DEBUG)
volatile int nRef; /* Number of enterances */
volatile DWORD owner; /* Thread holding this mutex */
volatile LONG trace; /* True to trace changes */
@@ -26327,6 +26433,8 @@ struct sqlite3_mutex {
#ifdef SQLITE_DEBUG
#define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id, \
0L, (DWORD)0, 0 }
+#elif !defined(SQLITE_ENABLE_API_ARMOR)
+#define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER }
#else
#define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id }
#endif
@@ -26386,7 +26494,6 @@ static sqlite3_mutex winMutex_staticMute
};
static int winMutex_isInit = 0;
-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
@@ -26394,7 +26501,9 @@ static int winMutex_isNt = -1; /* <0 mea
*/
static LONG SQLITE_WIN32_VOLATILE winMutex_lock = 0;
-SQLITE_API int sqlite3_win32_is_nt(void); /* os_win.c */
+#if defined(__CYGWIN__) && defined(SQLITE_AMALGAMATION)
+static
+#endif
SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */
static int winMutexInit(void){
@@ -26490,9 +26599,9 @@ static sqlite3_mutex *winMutexAlloc(int
case SQLITE_MUTEX_RECURSIVE: {
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
+#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_API_ARMOR)
p->id = iType;
-#ifdef SQLITE_DEBUG
-#ifdef SQLITE_WIN32_MUTEX_TRACE_DYNAMIC
+#if defined(SQLITE_DEBUG) && defined(SQLITE_WIN32_MUTEX_TRACE_DYNAMIC)
p->trace = 1;
#endif
#endif
@@ -26512,8 +26621,8 @@ static sqlite3_mutex *winMutexAlloc(int
}
#endif
p = &winMutex_staticMutexes[iType-2];
-#ifdef SQLITE_DEBUG
-#ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC
+#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_API_ARMOR)
+#if defined(SQLITE_DEBUG) && defined(SQLITE_WIN32_MUTEX_TRACE_DYNAMIC)
InterlockedCompareExchange(&p->trace, 1, 0);
#endif
#endif
@@ -26533,14 +26642,19 @@ static sqlite3_mutex *winMutexAlloc(int
static void winMutexFree(sqlite3_mutex *p){
assert( p );
assert( p->nRef==0 && p->owner==0 );
- if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ){
+#if SQLITE_ENABLE_API_ARMOR
+ if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE )
+#endif
+ {
DeleteCriticalSection(&p->mutex);
sqlite3_free(p);
- }else{
+ }
#ifdef SQLITE_ENABLE_API_ARMOR
+ else{
(void)SQLITE_MISUSE_BKPT;
-#endif
}
+#endif
+
}
/*
@@ -26588,30 +26702,15 @@ static int winMutexTry(sqlite3_mutex *p)
** 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.
- **
- ** 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 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) ){
+ if( TryEnterCriticalSection(&p->mutex) ){
#ifdef SQLITE_DEBUG
p->owner = tid;
p->nRef++;
#endif
rc = SQLITE_OK;
}
-#else
- UNUSED_PARAMETER(p);
-#endif
#ifdef SQLITE_DEBUG
if( p->trace ){
OSTRACE(("TRY-MUTEX tid=%lu, mutex(%d)=%p (%d), owner=%lu, nRef=%d, rc=%s\n",
@@ -26712,7 +26811,7 @@ SQLITE_API int sqlite3_release_memory(in
*/
static SQLITE_WSD struct Mem0Global {
sqlite3_mutex *mutex; /* Mutex to serialize access */
- sqlite3_int64 alarmThreshold; /* The soft heap limit */
+ size_t alarmThreshold; /* The soft heap limit */
/*
** True if heap is nearly "full" where "full" is defined by the
@@ -26736,6 +26835,7 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3Mal
** that was invoked when memory usage grew too large. Now it is a
** no-op.
*/
+#undef sqlite3_memory_alarm
SQLITE_API int sqlite3_memory_alarm(
void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
void *pArg,
@@ -26753,9 +26853,8 @@ SQLITE_API int sqlite3_memory_alarm(
** negative value indicates no limit.
*/
SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
- sqlite3_int64 priorLimit;
- sqlite3_int64 excess;
- sqlite3_int64 nUsed;
+ size_t priorLimit;
+ size_t nUsed;
#ifndef SQLITE_OMIT_AUTOINIT
int rc = sqlite3_initialize();
if( rc ) return -1;
@@ -26768,23 +26867,27 @@ SQLITE_API sqlite3_int64 sqlite3_soft_he
}
mem0.alarmThreshold = n;
nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
- mem0.nearlyFull = (n>0 && n<=nUsed);
+ mem0.nearlyFull = (n>0 && (size_t)n<=nUsed);
sqlite3_mutex_leave(mem0.mutex);
- excess = sqlite3_memory_used() - n;
- if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff));
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ if( sqlite3_memory_used() > n ) sqlite3PcacheReleaseMemory(sqlite3_memory_used() - n);
+#endif
return priorLimit;
}
+#ifndef SQLITE_OMIT_DEPRECATED
+#undef sqlite3_soft_heap_limit
SQLITE_API void sqlite3_soft_heap_limit(int n){
if( n<0 ) n = 0;
sqlite3_soft_heap_limit64(n);
}
+#endif
/*
** Initialize the memory allocation subsystem.
*/
SQLITE_PRIVATE int sqlite3MallocInit(void){
int rc;
- if( sqlite3GlobalConfig.m.xMalloc==0 ){
+ if( sqlite3GlobalConfig.m2.xMalloc==0 ){
sqlite3MemSetDefault();
}
memset(&mem0, 0, sizeof(mem0));
@@ -26794,7 +26897,7 @@ SQLITE_PRIVATE int sqlite3MallocInit(voi
sqlite3GlobalConfig.pPage = 0;
sqlite3GlobalConfig.szPage = 0;
}
- rc = sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData);
+ rc = sqlite3GlobalConfig.m2.xInit(sqlite3GlobalConfig.m2.pAppData);
if( rc!=SQLITE_OK ) memset(&mem0, 0, sizeof(mem0));
return rc;
}
@@ -26812,8 +26915,8 @@ SQLITE_PRIVATE int sqlite3HeapNearlyFull
** Deinitialize the memory allocation subsystem.
*/
SQLITE_PRIVATE void sqlite3MallocEnd(void){
- if( sqlite3GlobalConfig.m.xShutdown ){
- sqlite3GlobalConfig.m.xShutdown(sqlite3GlobalConfig.m.pAppData);
+ if( sqlite3GlobalConfig.m2.xShutdown ){
+ sqlite3GlobalConfig.m2.xShutdown(sqlite3GlobalConfig.m2.pAppData);
}
memset(&mem0, 0, sizeof(mem0));
}
@@ -26841,10 +26944,12 @@ SQLITE_API sqlite3_int64 sqlite3_memory_
/*
** Trigger the alarm
*/
-static void sqlite3MallocAlarm(int nByte){
+static void sqlite3MallocAlarm(size_t nByte){
if( mem0.alarmThreshold<=0 ) return;
sqlite3_mutex_leave(mem0.mutex);
- sqlite3_release_memory(nByte);
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ sqlite3PcacheReleaseMemory(nByte);
+#endif
sqlite3_mutex_enter(mem0.mutex);
}
@@ -26852,9 +26957,9 @@ static void sqlite3MallocAlarm(int nByte
** Do a memory allocation with statistics and alarms. Assume the
** lock is already held.
*/
-static void mallocWithAlarm(int n, void **pp){
+static void mallocWithAlarm(size_t n, void **pp){
void *p;
- int nFull;
+ size_t nFull;
assert( sqlite3_mutex_held(mem0.mutex) );
assert( n>0 );
@@ -26863,7 +26968,7 @@ static void mallocWithAlarm(int n, void
** mode and specifically when the DMD "Dark Matter Detector" is enabled
** or else a crash results. Hence, do not attempt to optimize out the
** following xRoundup() call. */
- nFull = sqlite3GlobalConfig.m.xRoundup(n);
+ nFull = sqlite3GlobalConfig.m2.xRoundup(n);
#ifdef SQLITE_MAX_MEMORY
if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nFull>SQLITE_MAX_MEMORY ){
@@ -26874,19 +26979,19 @@ static void mallocWithAlarm(int n, void
sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, n);
if( mem0.alarmThreshold>0 ){
- sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
- if( nUsed >= mem0.alarmThreshold - nFull ){
+ size_t nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
+ if( (nUsed + nFull >= mem0.alarmThreshold) || (nUsed + nFull < nUsed) ){
mem0.nearlyFull = 1;
sqlite3MallocAlarm(nFull);
}else{
mem0.nearlyFull = 0;
}
}
- p = sqlite3GlobalConfig.m.xMalloc(nFull);
+ p = sqlite3GlobalConfig.m2.xMalloc(nFull);
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
if( p==0 && mem0.alarmThreshold>0 ){
sqlite3MallocAlarm(nFull);
- p = sqlite3GlobalConfig.m.xMalloc(nFull);
+ p = sqlite3GlobalConfig.m2.xMalloc(nFull);
}
#endif
if( p ){
@@ -26901,9 +27006,9 @@ static void mallocWithAlarm(int n, void
** Allocate memory. This routine is like sqlite3_malloc() except that it
** assumes the memory subsystem has already been initialized.
*/
-SQLITE_PRIVATE void *sqlite3Malloc(u64 n){
+SQLITE_PRIVATE void *sqlite3Malloc(size_t n){
void *p;
- if( n==0 || n>=0x7fffff00 ){
+ if( n==0 ){
/* A memory allocation of a number of bytes which is near the maximum
** signed integer value might cause an integer overflow inside of the
** xMalloc(). Hence we limit the maximum size to 0x7fffff00, giving
@@ -26912,10 +27017,10 @@ SQLITE_PRIVATE void *sqlite3Malloc(u64 n
p = 0;
}else if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
- mallocWithAlarm((int)n, &p);
+ mallocWithAlarm(n, &p);
sqlite3_mutex_leave(mem0.mutex);
}else{
- p = sqlite3GlobalConfig.m.xMalloc((int)n);
+ p = sqlite3GlobalConfig.m2.xMalloc(n);
}
assert( EIGHT_BYTE_ALIGNMENT(p) ); /* IMP: R-11148-40995 */
return p;
@@ -26926,18 +27031,26 @@ SQLITE_PRIVATE void *sqlite3Malloc(u64 n
** First make sure the memory subsystem is initialized, then do the
** allocation.
*/
+#undef sqlite3_malloc
+#if !defined(SQLITE_OMIT_DEPRECATED) || SQLITE_PTRSIZE<8
SQLITE_API void *sqlite3_malloc(int n){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
- return n<=0 ? 0 : sqlite3Malloc(n);
+ return sqlite3Malloc((unsigned int)n);
}
+#endif
+#define sqlite3_malloc(x) sqlite3Malloc(x)
SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 n){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
+#if SQLITE_PTRSIZE<8
+ if(n > (sqlite3_uint64)(size_t)-1) return 0;
+#endif
return sqlite3Malloc(n);
}
+#define sqlite3_malloc64(x) sqlite3Malloc(x)
/*
** TRUE if p is a lookaside memory allocation from db
@@ -26954,11 +27067,11 @@ static int isLookaside(sqlite3 *db, void
** Return the size of a memory allocation previously obtained from
** sqlite3Malloc() or sqlite3_malloc().
*/
-SQLITE_PRIVATE int sqlite3MallocSize(void *p){
+SQLITE_PRIVATE size_t sqlite3MallocSize(void *p){
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
- return sqlite3GlobalConfig.m.xSize(p);
+ return sqlite3GlobalConfig.m2.xSize(p);
}
-SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
+SQLITE_PRIVATE size_t sqlite3DbMallocSize(sqlite3 *db, void *p){
assert( p!=0 );
if( db==0 || !isLookaside(db,p) ){
#ifdef SQLITE_DEBUG
@@ -26970,7 +27083,7 @@ SQLITE_PRIVATE int sqlite3DbMallocSize(s
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
}
#endif
- return sqlite3GlobalConfig.m.xSize(p);
+ return sqlite3GlobalConfig.m2.xSize(p);
}else{
assert( sqlite3_mutex_held(db->mutex) );
return db->lookaside.sz;
@@ -26979,7 +27092,7 @@ SQLITE_PRIVATE int sqlite3DbMallocSize(s
SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){
assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
- return p ? sqlite3GlobalConfig.m.xSize(p) : 0;
+ return p ? sqlite3GlobalConfig.m2.xSize(p) : 0;
}
/*
@@ -26993,10 +27106,10 @@ SQLITE_API void sqlite3_free(void *p){
sqlite3_mutex_enter(mem0.mutex);
sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, sqlite3MallocSize(p));
sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1);
- sqlite3GlobalConfig.m.xFree(p);
+ sqlite3GlobalConfig.m2.xFree(p);
sqlite3_mutex_leave(mem0.mutex);
}else{
- sqlite3GlobalConfig.m.xFree(p);
+ sqlite3GlobalConfig.m2.xFree(p);
}
}
@@ -27046,8 +27159,8 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite
/*
** Change the size of an existing memory allocation
*/
-SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){
- int nOld, nNew, nDiff;
+SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, size_t nBytes){
+ size_t nOld, nNew;
void *pNew;
assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) );
assert( sqlite3MemdebugNoType(pOld, (u8)~MEMTYPE_HEAP) );
@@ -27058,37 +27171,33 @@ SQLITE_PRIVATE void *sqlite3Realloc(void
sqlite3_free(pOld); /* IMP: R-26507-47431 */
return 0;
}
- if( nBytes>=0x7fffff00 ){
- /* The 0x7ffff00 limit term is explained in comments on sqlite3Malloc() */
- return 0;
- }
nOld = sqlite3MallocSize(pOld);
/* IMPLEMENTATION-OF: R-46199-30249 SQLite guarantees that the second
** argument to xRealloc is always a value returned by a prior call to
** xRoundup. */
- nNew = sqlite3GlobalConfig.m.xRoundup((int)nBytes);
+ nNew = sqlite3GlobalConfig.m2.xRoundup(nBytes);
if( nOld==nNew ){
pNew = pOld;
}else if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
- nDiff = nNew - nOld;
- if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
- mem0.alarmThreshold-nDiff ){
- sqlite3MallocAlarm(nDiff);
+ sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, nBytes);
+ if( nNew > nOld && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nNew >=
+ mem0.alarmThreshold+nOld ){
+ sqlite3MallocAlarm(nNew - nOld);
}
- pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
+ pNew = sqlite3GlobalConfig.m2.xRealloc(pOld, nNew);
if( pNew==0 && mem0.alarmThreshold>0 ){
- sqlite3MallocAlarm((int)nBytes);
- pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
+ sqlite3MallocAlarm(nBytes);
+ pNew = sqlite3GlobalConfig.m2.xRealloc(pOld, nNew);
}
if( pNew ){
nNew = sqlite3MallocSize(pNew);
- sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
+ sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, nOld);
+ sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew);
}
sqlite3_mutex_leave(mem0.mutex);
}else{
- pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
+ pNew = sqlite3GlobalConfig.m2.xRealloc(pOld, nNew);
}
assert( EIGHT_BYTE_ALIGNMENT(pNew) ); /* IMP: R-11148-40995 */
return pNew;
@@ -27098,28 +27207,35 @@ SQLITE_PRIVATE void *sqlite3Realloc(void
** The public interface to sqlite3Realloc. Make sure that the memory
** subsystem is initialized prior to invoking sqliteRealloc.
*/
+#undef sqlite3_realloc
+#if !defined(SQLITE_OMIT_DEPRECATED) || SQLITE_PTRSIZE<8
SQLITE_API void *sqlite3_realloc(void *pOld, int n){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
- if( n<0 ) n = 0; /* IMP: R-26507-47431 */
- return sqlite3Realloc(pOld, n);
+ return sqlite3Realloc(pOld, (unsigned int)n);
}
+#endif
+#define sqlite3_realloc(x,y) sqlite3Realloc(x,y)
SQLITE_API void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
+#if SQLITE_PTRSIZE<8
+ if(n > (sqlite3_uint64)(size_t)-1) n = 0;
+#endif
return sqlite3Realloc(pOld, n);
}
+#define sqlite3_realloc64(x,y) sqlite3Realloc(x,y)
/*
** Allocate and zero memory.
*/
-SQLITE_PRIVATE void *sqlite3MallocZero(u64 n){
+SQLITE_PRIVATE void *sqlite3MallocZero(size_t n){
void *p = sqlite3Malloc(n);
if( p ){
- memset(p, 0, (size_t)n);
+ memset(p, 0, n);
}
return p;
}
@@ -27128,11 +27244,11 @@ SQLITE_PRIVATE void *sqlite3MallocZero(u
** Allocate and zero memory. If the allocation fails, make
** the mallocFailed flag in the connection pointer.
*/
-SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, u64 n){
+SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, size_t n){
void *p;
testcase( db==0 );
p = sqlite3DbMallocRaw(db, n);
- if( p ) memset(p, 0, (size_t)n);
+ if( p ) memset(p, 0, n);
return p;
}
@@ -27140,7 +27256,7 @@ SQLITE_PRIVATE void *sqlite3DbMallocZero
/* Finish the work of sqlite3DbMallocRawNN for the unusual and
** slower case when the allocation cannot be fulfilled using lookaside.
*/
-static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){
+static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, size_t n){
void *p;
assert( db!=0 );
p = sqlite3Malloc(n);
@@ -27172,7 +27288,7 @@ static SQLITE_NOINLINE void *dbMallocRaw
** The sqlite3MallocRawNN() variant guarantees that the "db" parameter is
** not a NULL pointer.
*/
-SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){
+SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, size_t n){
void *p;
if( db ) return sqlite3DbMallocRawNN(db, n);
p = sqlite3Malloc(n);
@@ -27215,20 +27331,20 @@ SQLITE_PRIVATE void *sqlite3DbMallocRawN
}
/* Forward declaration */
-static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n);
+static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, size_t n);
/*
** Resize the block of memory pointed to by p to n bytes. If the
** resize fails, set the mallocFailed flag in the connection object.
*/
-SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){
+SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, size_t n){
assert( db!=0 );
if( p==0 ) return sqlite3DbMallocRawNN(db, n);
assert( sqlite3_mutex_held(db->mutex) );
if( isLookaside(db,p) && n<=db->lookaside.sz ) return p;
return dbReallocFinish(db, p, n);
}
-static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){
+static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, size_t n){
void *pNew = 0;
assert( db!=0 );
assert( p!=0 );
@@ -27258,7 +27374,7 @@ static SQLITE_NOINLINE void *dbReallocFi
** Attempt to reallocate p. If the reallocation fails, then free p
** and set the mallocFailed flag in the database connection.
*/
-SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, u64 n){
+SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, size_t n){
void *pNew;
pNew = sqlite3DbRealloc(db, p, n);
if( !pNew ){
@@ -27287,7 +27403,7 @@ SQLITE_PRIVATE char *sqlite3DbStrDup(sql
}
return zNew;
}
-SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
+SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, size_t n){
char *zNew;
assert( db!=0 );
if( z==0 ){
@@ -27296,7 +27412,7 @@ SQLITE_PRIVATE char *sqlite3DbStrNDup(sq
assert( (n&0x7fffffff)==n );
zNew = sqlite3DbMallocRawNN(db, n+1);
if( zNew ){
- memcpy(zNew, z, (size_t)n);
+ memcpy(zNew, z, n);
zNew[n] = 0;
}
return zNew;
@@ -27904,6 +28020,8 @@ SQLITE_API void sqlite3_str_vappendf(
case etGENERIC:
if( bArgList ){
realvalue = getDoubleArg(pArgList);
+ }else if( flag_long==2 ){
+ realvalue = va_arg(ap,long double);
}else{
realvalue = va_arg(ap,double);
}
@@ -27934,7 +28052,7 @@ SQLITE_API void sqlite3_str_vappendf(
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
exp = 0;
if( sqlite3IsNaN((double)realvalue) ){
- bufpt = "NaN";
+ bufpt = (char *)"NaN";
length = 3;
break;
}
@@ -28134,7 +28252,7 @@ SQLITE_API void sqlite3_str_vappendf(
bufpt = va_arg(ap,char*);
}
if( bufpt==0 ){
- bufpt = "";
+ bufpt = (char *)"";
}else if( xtype==etDYNSTRING ){
if( pAccum->nChar==0
&& pAccum->mxAlloc
@@ -28184,7 +28302,7 @@ SQLITE_API void sqlite3_str_vappendf(
int needQuote;
char ch;
char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */
- char *escarg;
+ const char *escarg;
if( bArgList ){
escarg = getTextArg(pArgList);
@@ -28290,7 +28408,7 @@ SQLITE_API void sqlite3_str_vappendf(
** Return the number of bytes of text that StrAccum is able to accept
** after the attempted enlargement. The value returned might be zero.
*/
-static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
+static int sqlite3StrAccumEnlarge(StrAccum *p, size_t N){
char *zNew;
assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */
if( p->accError ){
@@ -28303,7 +28421,7 @@ static int sqlite3StrAccumEnlarge(StrAcc
return p->nAlloc - p->nChar - 1;
}else{
char *zOld = isMalloced(p) ? p->zText : 0;
- i64 szNew = p->nChar;
+ size_t szNew = p->nChar;
szNew += N + 1;
if( szNew+p->nChar<=p->mxAlloc ){
/* Force exponential buffer size growth as long as it does not overflow,
@@ -28315,12 +28433,12 @@ static int sqlite3StrAccumEnlarge(StrAcc
setStrAccumError(p, SQLITE_TOOBIG);
return 0;
}else{
- p->nAlloc = (int)szNew;
+ p->nAlloc = szNew;
}
if( p->db ){
zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
}else{
- zNew = sqlite3_realloc64(zOld, p->nAlloc);
+ zNew = sqlite3Realloc(zOld, p->nAlloc);
}
if( zNew ){
assert( p->zText!=0 || p->nChar==0 );
@@ -28342,7 +28460,7 @@ static int sqlite3StrAccumEnlarge(StrAcc
*/
SQLITE_API void sqlite3_str_appendchar(sqlite3_str *p, int N, char c){
testcase( p->nChar + (i64)N > 0x7fffffff );
- if( p->nChar+(i64)N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){
+ if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){
return;
}
while( (N--)>0 ) p->zText[p->nChar++] = c;
@@ -28356,7 +28474,7 @@ SQLITE_API void sqlite3_str_appendchar(s
** work (enlarging the buffer) using tail recursion, so that the
** sqlite3_str_append() routine can use fast calling semantics.
*/
-static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){
+static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, size_t N){
N = sqlite3StrAccumEnlarge(p, N);
if( N>0 ){
memcpy(&p->zText[p->nChar], z, N);
@@ -28371,7 +28489,6 @@ static void SQLITE_NOINLINE enlargeAndAp
SQLITE_API void sqlite3_str_append(sqlite3_str *p, const char *z, int N){
assert( z!=0 || N==0 );
assert( p->zText!=0 || p->nChar==0 || p->accError );
- assert( N>=0 );
assert( p->accError==0 || p->nAlloc==0 || p->mxAlloc==0 );
if( p->nChar+N >= p->nAlloc ){
enlargeAndAppend(p,z,N);
@@ -28485,7 +28602,7 @@ SQLITE_API void sqlite3_str_reset(StrAcc
** mx: Maximum number of bytes to accumulate. If mx==0 then no memory
** allocations will ever occur.
*/
-SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){
+SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, size_t n, size_t mx){
p->zText = zBase;
p->db = db;
p->nAlloc = n;
@@ -28722,14 +28839,14 @@ SQLITE_API void sqlite3_str_appendf(StrA
*/
static TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){
if( p==0 ){
- p = sqlite3_malloc64( sizeof(*p) );
+ p = sqlite3Malloc( sizeof(*p) );
if( p==0 ) return 0;
memset(p, 0, sizeof(*p));
}else{
p->iLevel++;
}
assert( moreToFollow==0 || moreToFollow==1 );
- if( p->iLevel<sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow;
+ if( (unsigned)p->iLevel<sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow;
return p;
}
@@ -28753,7 +28870,7 @@ static void sqlite3TreeViewLine(TreeView
char zBuf[500];
sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
if( p ){
- for(i=0; i<p->iLevel && i<sizeof(p->bLine)-1; i++){
+ for(i=0; i<p->iLevel && (unsigned)i<sizeof(p->bLine)-1; i++){
sqlite3_str_append(&acc, p->bLine[i] ? "| " : " ", 4);
}
sqlite3_str_append(&acc, p->bLine[i] ? "|-- " : "'-- ", 4);
@@ -28781,7 +28898,7 @@ static void sqlite3TreeViewItem(TreeView
/*
** Generate a human-readable description of a WITH clause.
*/
-SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
+SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith){
int i;
if( pWith==0 ) return;
if( pWith->nCte==0 ) return;
@@ -28867,7 +28984,7 @@ SQLITE_PRIVATE void sqlite3TreeViewSelec
}
pView = sqlite3TreeViewPush(pView, moreToFollow);
if( p->pWith ){
- sqlite3TreeViewWith(pView, p->pWith, 1);
+ sqlite3TreeViewWith(pView, p->pWith);
cnt = 1;
sqlite3TreeViewPush(pView, 1);
}
@@ -29612,7 +29729,8 @@ SQLITE_PRIVATE void sqlite3PrngRestoreSt
#if SQLITE_MAX_WORKER_THREADS>0
/********************************* Unix Pthreads ****************************/
-#if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0
+#if (SQLITE_OS_UNIX || defined(__CYGWIN__)) && \
+ defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0
#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
/* #include <pthread.h> */
@@ -29679,7 +29797,8 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQL
return rc;
}
-#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */
+#endif /* (SQLITE_OS_UNIX || defined(__CYGWIN__)) && \
+ defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0 */
/******************************** End Unix Pthreads *************************/
@@ -29762,7 +29881,6 @@ SQLITE_PRIVATE DWORD sqlite3Win32Wait(HA
/* Get the results of the thread */
SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
DWORD rc;
- BOOL bRc;
assert( ppOut!=0 );
if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
@@ -29774,8 +29892,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQL
assert( p->id!=0 && p->id!=GetCurrentThreadId() );
rc = sqlite3Win32Wait((HANDLE)p->tid);
assert( rc!=WAIT_IO_COMPLETION );
- bRc = CloseHandle((HANDLE)p->tid);
- assert( bRc );
+ CloseHandle((HANDLE)p->tid);
}
if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult;
sqlite3_free(p);
@@ -30056,7 +30173,7 @@ SQLITE_PRIVATE u32 sqlite3Utf8Read(
** encoding, or if *pMem does not contain a string value.
*/
SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
- sqlite3_int64 len; /* Maximum length of output string in bytes */
+ size_t len; /* Maximum length of output string in bytes */
unsigned char *zOut; /* Output buffer */
unsigned char *zIn; /* Input iterator */
unsigned char *zTerm; /* End of input */
@@ -30067,7 +30184,6 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlit
assert( pMem->flags&MEM_Str );
assert( pMem->enc!=desiredEnc );
assert( pMem->enc!=0 );
- assert( pMem->n>=0 );
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
{
@@ -30204,7 +30320,6 @@ SQLITE_PRIVATE int sqlite3VdbeMemHandleB
int rc = SQLITE_OK;
u8 bom = 0;
- assert( pMem->n>=0 );
if( pMem->n>1 ){
u8 b1 = *(u8 *)pMem->z;
u8 b2 = *(((u8 *)pMem->z) + 1);
@@ -30465,9 +30580,14 @@ SQLITE_PRIVATE int sqlite3IsNaN(double x
** than the actual length of the string. For very long strings (greater
** than 1GiB) the value returned might be less than the true string length.
*/
-SQLITE_PRIVATE int sqlite3Strlen30(const char *z){
+SQLITE_PRIVATE size_t sqlite3Strlen30(const char *z){
+ size_t result;
if( z==0 ) return 0;
- return 0x3fffffff & (int)strlen(z);
+ result = strlen(z);
+ if( result > SQLITE_MAX_LENGTH ) {
+ result &= 0x3fffffff;
+ }
+ return result;
}
/*
@@ -30477,7 +30597,7 @@ SQLITE_PRIVATE int sqlite3Strlen30(const
** The column type is an extra string stored after the zero-terminator on
** the column name if and only if the COLFLAG_HASTYPE flag is set.
*/
-SQLITE_PRIVATE char *sqlite3ColumnType(Column *pCol, char *zDflt){
+SQLITE_PRIVATE const char *sqlite3ColumnType(Column *pCol, const char *zDflt){
if( (pCol->colFlags & COLFLAG_HASTYPE)==0 ) return zDflt;
return pCol->zName + strlen(pCol->zName) + 1;
}
@@ -30693,7 +30813,7 @@ SQLITE_PRIVATE int sqlite3StrICmp(const
return c;
}
SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
- register unsigned char *a, *b;
+ unsigned char *a, *b;
if( zLeft==0 ){
return zRight ? -1 : 0;
}else if( zRight==0 ){
@@ -32125,7 +32245,7 @@ static void insertElement(
** if the new size is the same as the prior size.
** Return TRUE if the resize occurs and false if not.
*/
-static int rehash(Hash *pH, unsigned int new_size){
+static int rehash(Hash *pH, size_t new_size){
struct _ht *new_ht; /* The new hash table */
HashElem *elem, *next_elem; /* For looping over existing elements */
@@ -32585,7 +32705,7 @@ SQLITE_PRIVATE const char *sqlite3Opcode
# include <sys/mman.h>
#endif
-#if SQLITE_ENABLE_LOCKING_STYLE
+#if SQLITE_ENABLE_LOCKING_STYLE || defined(__CYGWIN__) || defined(__GNU__) || defined(HAVE_FLOCK)
/* # include <sys/ioctl.h> */
# include <sys/file.h>
# include <sys/param.h>
@@ -32661,7 +32781,7 @@ SQLITE_PRIVATE const char *sqlite3Opcode
/*
** Maximum supported path-length.
*/
-#define MAX_PATHNAME 512
+#define MAX_PATHNAME SQLITE_MAX_PATH_LENGTH
/*
** Maximum supported symbolic links
@@ -33013,7 +33133,7 @@ SQLITE_API extern int sqlite3_open_file_
** HAVE_MREMAP defaults to true on Linux and false everywhere else.
*/
#if !defined(HAVE_MREMAP)
-# if defined(__linux__) && defined(_GNU_SOURCE)
+# if (defined(__linux__) || defined(__ANDROID__)) && defined(_GNU_SOURCE)
# define HAVE_MREMAP 1
# else
# define HAVE_MREMAP 0
@@ -33064,6 +33184,7 @@ static int unixGetpagesize(void);
** testing and sandboxing. The following array holds the names and pointers
** to all overrideable system calls.
*/
+#define aSyscall aUnixSyscall
static struct unix_syscall {
const char *zName; /* Name of the system call */
sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
@@ -33653,7 +33774,7 @@ static struct vxworksFileId *vxworksFind
assert( zAbsoluteName[0]=='/' );
n = (int)strlen(zAbsoluteName);
- pNew = sqlite3_malloc64( sizeof(*pNew) + (n+1) );
+ pNew = sqlite3Malloc( sizeof(*pNew) + (n+1) );
if( pNew==0 ) return 0;
pNew->zCanonicalName = (char*)&pNew[1];
memcpy(pNew->zCanonicalName, zAbsoluteName, n+1);
@@ -33908,7 +34029,7 @@ static int unixLogErrorAtLine(
const char *zPath, /* File path associated with error */
int iLine /* Source line number where error occurred */
){
- char *zErr; /* Message from strerror() or equivalent */
+ const char *zErr; /* Message from strerror() or equivalent */
int iErrno = errno; /* Saved syscall error number */
/* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use
@@ -34104,7 +34225,7 @@ static int findInodeInfo(
pInode = pInode->pNext;
}
if( pInode==0 ){
- pInode = sqlite3_malloc64( sizeof(*pInode) );
+ pInode = sqlite3Malloc( sizeof(*pInode) );
if( pInode==0 ){
return SQLITE_NOMEM_BKPT;
}
@@ -35072,7 +35193,7 @@ static int dotlockClose(sqlite3_file *id
**
** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off
*/
-#if SQLITE_ENABLE_LOCKING_STYLE
+#if SQLITE_ENABLE_LOCKING_STYLE || defined(__CYGWIN__) || defined(__GNU__) || defined(HAVE_FLOCK)
/*
** Retry flock() calls that fail with EINTR
@@ -36210,9 +36331,13 @@ static int unixWrite(
** Count the number of fullsyncs and normal syncs. This is used to test
** that syncs and fullsyncs are occurring at the right times.
*/
+#if SQLITE_OS_WIN
+extern int sqlite3_sync_count, sqlite3_fullsync_count;
+#else
SQLITE_API int sqlite3_sync_count = 0;
SQLITE_API int sqlite3_fullsync_count = 0;
#endif
+#endif
/*
** We do not trust systems to provide a working fdatasync(). Some do.
@@ -36666,7 +36791,7 @@ static int unixFileControl(sqlite3_file
return SQLITE_OK;
}
case SQLITE_FCNTL_TEMPFILENAME: {
- char *zTFile = sqlite3_malloc64( pFile->pVfs->mxPathname );
+ char *zTFile = sqlite3Malloc( pFile->pVfs->mxPathname );
if( zTFile ){
unixGetTempname(pFile->pVfs->mxPathname, zTFile);
*(char**)pArg = zTFile;
@@ -37200,7 +37325,7 @@ static int unixOpenSharedMemory(unixFile
int nShmFilename; /* Size of the SHM filename in bytes */
/* Allocate space for the new unixShm object. */
- p = sqlite3_malloc64( sizeof(*p) );
+ p = sqlite3Malloc( sizeof(*p) );
if( p==0 ) return SQLITE_NOMEM_BKPT;
memset(p, 0, sizeof(*p));
assert( pDbFd->pShm==0 );
@@ -37232,7 +37357,7 @@ static int unixOpenSharedMemory(unixFile
#else
nShmFilename = 6 + (int)strlen(zBasePath);
#endif
- pShmNode = sqlite3_malloc64( sizeof(*pShmNode) + nShmFilename );
+ pShmNode = sqlite3Malloc( sizeof(*pShmNode) + nShmFilename );
if( pShmNode==0 ){
rc = SQLITE_NOMEM_BKPT;
goto shm_open_err;
@@ -37440,7 +37565,7 @@ static int unixShmMap(
goto shmpage_out;
}
}else{
- pMem = sqlite3_malloc64(nMap);
+ pMem = sqlite3Malloc(nMap);
if( pMem==0 ){
rc = SQLITE_NOMEM_BKPT;
goto shmpage_out;
@@ -37980,7 +38105,7 @@ IOMETHODS(
0 /* xShmMap method */
)
-#if SQLITE_ENABLE_LOCKING_STYLE
+#if SQLITE_ENABLE_LOCKING_STYLE || defined(__CYGWIN__) || defined(__GNU__) || defined(HAVE_FLOCK)
IOMETHODS(
flockIoFinder, /* Finder function name */
flockIoMethods, /* sqlite3_io_methods object name */
@@ -38019,6 +38144,19 @@ IOMETHODS(
)
#endif
+#if defined(__CYGWIN__)
+IOMETHODS(
+ cygwinIoFinder, /* Finder function name */
+ cygwinIoMethods, /* sqlite3_io_methods object name */
+ 1, /* shared memory is disabled */
+ flockClose, /* xClose method */
+ flockLock, /* xLock method */
+ flockUnlock, /* xUnlock method */
+ flockCheckReservedLock, /* xCheckReservedLock method */
+ 0 /* xShmMap method */
+)
+#endif
+
/*
** The proxy locking method is a "super-method" in the sense that it
** opens secondary file descriptors for the conch and lock files and
@@ -38267,7 +38405,7 @@ static int fillInUnixFile(
** the afpLockingContext.
*/
afpLockingContext *pCtx;
- pNew->lockingContext = pCtx = sqlite3_malloc64( sizeof(*pCtx) );
+ pNew->lockingContext = pCtx = sqlite3Malloc( sizeof(*pCtx) );
if( pCtx==0 ){
rc = SQLITE_NOMEM_BKPT;
}else{
@@ -38297,7 +38435,7 @@ static int fillInUnixFile(
int nFilename;
assert( zFilename!=0 );
nFilename = (int)strlen(zFilename) + 6;
- zLockFile = (char *)sqlite3_malloc64(nFilename);
+ zLockFile = (char *)sqlite3Malloc(nFilename);
if( zLockFile==0 ){
rc = SQLITE_NOMEM_BKPT;
}else{
@@ -38329,6 +38467,15 @@ static int fillInUnixFile(
unixLeaveMutex();
}
#endif
+
+#if defined(__CYGWIN__)
+ else if( pLockingStyle == &cygwinIoMethods ){
+ if ((osFcntl(h, F_LCK_MANDATORY, 1) != 0) && (errno != EINVAL)) {
+ /* The API exists but it refused to enable mandatory locking! */
+ rc = SQLITE_IOERR_ACCESS;
+ }
+ }
+#endif
storeLastErrno(pNew, 0);
#if OS_VXWORKS
@@ -38357,6 +38504,8 @@ static const char *unixTempFileDir(void)
static const char *azDirs[] = {
0,
0,
+ 0,
+ 0,
"/var/tmp",
"/usr/tmp",
"/tmp",
@@ -38368,6 +38517,8 @@ static const char *unixTempFileDir(void)
if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR");
if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
+ if( !azDirs[3] ) azDirs[2] = getenv("TMP");
+ if( !azDirs[4] ) azDirs[3] = getenv("TEMP");
while(1){
if( zDir!=0
&& osStat(zDir, &buf)==0
@@ -38689,7 +38840,7 @@ static int unixOpen(
if( pUnused ){
fd = pUnused->fd;
}else{
- pUnused = sqlite3_malloc64(sizeof(*pUnused));
+ pUnused = sqlite3Malloc(sizeof(*pUnused));
if( !pUnused ){
return SQLITE_NOMEM_BKPT;
}
@@ -39025,7 +39176,7 @@ static int unixFullPathname(
if( bLink ){
if( zDel==0 ){
- zDel = sqlite3_malloc(nOut);
+ zDel = sqlite3Malloc(nOut);
if( zDel==0 ) rc = SQLITE_NOMEM_BKPT;
}else if( ++nLink>SQLITE_MAX_SYMLINKS ){
rc = SQLITE_CANTOPEN_BKPT;
@@ -39076,7 +39227,7 @@ static int unixFullPathname(
#include <dlfcn.h>
static void *unixDlOpen(sqlite3_vfs *NotUsed, const char *zFilename){
UNUSED_PARAMETER(NotUsed);
- return dlopen(zFilename, RTLD_NOW | RTLD_GLOBAL);
+ return dlopen(zFilename, RTLD_NOW | RTLD_LOCAL);
}
/*
@@ -39207,7 +39358,11 @@ static int unixSleep(sqlite3_vfs *NotUse
** sqlite3OsCurrentTime() during testing.
*/
#ifdef SQLITE_TEST
+# if SQLITE_OS_WIN
+SQLITE_API extern int sqlite3_current_time; /* Fake system time in seconds since 1970. */
+# else
SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */
+# endif
#endif
/*
@@ -39563,7 +39718,7 @@ static int proxyCreateUnixFile(
if( pUnused ){
fd = pUnused->fd;
}else{
- pUnused = sqlite3_malloc64(sizeof(*pUnused));
+ pUnused = sqlite3Malloc(sizeof(*pUnused));
if( !pUnused ){
return SQLITE_NOMEM_BKPT;
}
@@ -39596,7 +39751,7 @@ static int proxyCreateUnixFile(
}
}
- pNew = (unixFile *)sqlite3_malloc64(sizeof(*pNew));
+ pNew = (unixFile *)sqlite3Malloc(sizeof(*pNew));
if( pNew==NULL ){
rc = SQLITE_NOMEM_BKPT;
goto end_create_proxy;
@@ -40074,7 +40229,7 @@ static int proxyCreateConchPathname(char
/* Allocate space for the conch filename and initialize the name to
** the name of the original database file. */
- *pConchPath = conchPath = (char *)sqlite3_malloc64(len + 8);
+ *pConchPath = conchPath = (char *)sqlite3Malloc(len + 8);
if( conchPath==0 ){
return SQLITE_NOMEM_BKPT;
}
@@ -40190,7 +40345,7 @@ static int proxyTransformUnixFile(unixFi
OSTRACE(("TRANSPROXY %d for %s pid=%d\n", pFile->h,
(lockPath ? lockPath : ":auto:"), osGetpid(0)));
- pCtx = sqlite3_malloc64( sizeof(*pCtx) );
+ pCtx = sqlite3Malloc( sizeof(*pCtx) );
if( pCtx==0 ){
return SQLITE_NOMEM_BKPT;
}
@@ -40475,7 +40630,14 @@ static int proxyClose(sqlite3_file *id)
** necessarily been initialized when this routine is called, and so they
** should not be used.
*/
+#if SQLITE_OS_WIN
+#if defined(SQLITE_AMALGAMATION)
+static
+#endif
+SQLITE_API int sqlite3_os_unix_init(void){
+#else
SQLITE_API int sqlite3_os_init(void){
+#endif
/*
** The following macro defines an initializer for an sqlite3_vfs object.
** The name of the VFS is NAME. The pAppData is a pointer to a pointer
@@ -40531,21 +40693,32 @@ SQLITE_API int sqlite3_os_init(void){
static sqlite3_vfs aVfs[] = {
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
UNIXVFS("unix", autolockIoFinder ),
+#elif defined(__CYGWIN__)
+ UNIXVFS("unix", cygwinIoFinder ),
#elif OS_VXWORKS
UNIXVFS("unix", vxworksIoFinder ),
+#elif defined(__GNU__) || defined(HAVE_FLOCK)
+ UNIXVFS("unix", flockIoFinder ),
#else
UNIXVFS("unix", posixIoFinder ),
#endif
+#if !SQLITE_OS_WIN
+ UNIXVFS("none", nolockIoFinder ),
+#endif
UNIXVFS("unix-none", nolockIoFinder ),
UNIXVFS("unix-dotfile", dotlockIoFinder ),
+#if defined(__CYGWIN__)
+ UNIXVFS("unix-excl", cygwinIoFinder ),
+#else
UNIXVFS("unix-excl", posixIoFinder ),
+#endif
#if OS_VXWORKS
UNIXVFS("unix-namedsem", semIoFinder ),
#endif
-#if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS
+#if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS || defined(__CYGWIN__) || defined(__GNU__)
UNIXVFS("unix-posix", posixIoFinder ),
#endif
-#if SQLITE_ENABLE_LOCKING_STYLE
+#if SQLITE_ENABLE_LOCKING_STYLE || defined(__CYGWIN__) || defined(__GNU__) || defined(HAVE_FLOCK)
UNIXVFS("unix-flock", flockIoFinder ),
#endif
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
@@ -40568,6 +40741,8 @@ SQLITE_API int sqlite3_os_init(void){
return SQLITE_OK;
}
+#undef aSyscall
+#if !SQLITE_OS_WIN
/*
** Shutdown the operating system interface.
**
@@ -40579,6 +40754,7 @@ SQLITE_API int sqlite3_os_end(void){
unixBigLock = 0;
return SQLITE_OK;
}
+#endif /* !SQLITE_OS_WIN */
#endif /* SQLITE_OS_UNIX */
@@ -40809,6 +40985,13 @@ SQLITE_API extern int sqlite3_open_file_
*/
/* #include "os_win.h" */
+struct cygwinstat {
+ i64 st_dev;
+ i64 st_ino;
+ i64 st_mode;
+ char dummy[40 + 8*SQLITE_PTRSIZE];
+};
+
/*
** Compiling and using WAL mode requires several APIs that are only
** available in Windows platforms based on the NT kernel.
@@ -40827,7 +41010,7 @@ SQLITE_API extern int sqlite3_open_file_
** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions
** based on the sub-platform)?
*/
-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(SQLITE_WIN32_NO_ANSI)
+#if 0
# define SQLITE_WIN32_HAS_ANSI
#endif
@@ -40925,7 +41108,11 @@ SQLITE_API extern int sqlite3_open_file_
** 4-bytes-per-character for UTF8.
*/
#ifndef SQLITE_WIN32_MAX_PATH_BYTES
+# if defined(SQLITE_MAX_PATH_LENGTH) && SQLITE_MAX_PATH_LENGTH > (SQLITE_WIN32_MAX_PATH_CHARS*4)
+# define SQLITE_WIN32_MAX_PATH_BYTES SQLITE_MAX_PATH_LENGTH
+# else
# define SQLITE_WIN32_MAX_PATH_BYTES (SQLITE_WIN32_MAX_PATH_CHARS*4)
+# endif
#endif
/*
@@ -41239,15 +41426,15 @@ static struct winMemData win_mem_data =
#define winMemGetHeap() win_mem_data.hHeap
#define winMemGetOwned() win_mem_data.bOwned
-static void *winMemMalloc(int nBytes);
+static void *winMemMalloc(size_t nBytes);
static void winMemFree(void *pPrior);
-static void *winMemRealloc(void *pPrior, int nBytes);
-static int winMemSize(void *p);
-static int winMemRoundup(int n);
+static void *winMemRealloc(void *pPrior, size_t nBytes);
+static size_t winMemSize(void *p);
+static size_t winMemRoundup(size_t n);
static int winMemInit(void *pAppData);
static void winMemShutdown(void *pAppData);
-SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void);
+SQLITE_PRIVATE const sqlite3_mem_methods2 *sqlite3MemGetWin32(void);
#endif /* SQLITE_WIN32_MALLOC */
/*
@@ -41264,8 +41451,6 @@ SQLITE_PRIVATE const sqlite3_mem_methods
*/
#ifdef SQLITE_TEST
SQLITE_API LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0;
-#else
-static LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0;
#endif
#ifndef SYSCALL
@@ -41360,7 +41545,7 @@ static struct win_syscall {
#define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
DWORD,DWORD,DWORD,LPCWSTR))aSyscall[7].pCurrent)
-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
+#if SQLITE_OS_WINCE
{ "CreateMutexW", (SYSCALL)CreateMutexW, 0 },
#else
{ "CreateMutexW", (SYSCALL)0, 0 },
@@ -41510,7 +41695,7 @@ static struct win_syscall {
#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent)
-#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
+#if !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(_WIN32)
#if SQLITE_OS_WINCE
/* The GetProcAddressA() routine is only available on Windows CE. */
{ "GetProcAddressA", (SYSCALL)GetProcAddressA, 0 },
@@ -41668,7 +41853,7 @@ static struct win_syscall {
#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[46].pCurrent)
-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
+#ifdef SQLITE_WIN32_HAS_ANSI
{ "LockFile", (SYSCALL)LockFile, 0 },
#else
{ "LockFile", (SYSCALL)0, 0 },
@@ -41736,12 +41921,16 @@ static struct win_syscall {
#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[55].pCurrent)
+#if SQLITE_OS_WINCE
{ "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 },
+#else
+ { "SystemTimeToFileTime", (SYSCALL)0, 0 },
+#endif
#define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \
LPFILETIME))aSyscall[56].pCurrent)
-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
+#ifdef SQLITE_WIN32_HAS_ANSI
{ "UnlockFile", (SYSCALL)UnlockFile, 0 },
#else
{ "UnlockFile", (SYSCALL)0, 0 },
@@ -41788,7 +41977,7 @@ static struct win_syscall {
#define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \
DWORD,DWORD))aSyscall[62].pCurrent)
-#if !SQLITE_OS_WINRT
+#if SQLITE_OS_WINCE
{ "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 },
#else
{ "WaitForSingleObject", (SYSCALL)0, 0 },
@@ -41902,6 +42091,7 @@ static struct win_syscall {
** 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 0
#if defined(InterlockedCompareExchange)
{ "InterlockedCompareExchange", (SYSCALL)0, 0 },
@@ -41912,6 +42102,15 @@ static struct win_syscall {
#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG \
SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[76].pCurrent)
#endif /* defined(InterlockedCompareExchange) */
+#endif /* 0 */
+
+#if defined(SQLITE_WIN32_HAS_WIDE) && defined(_WIN32)
+ { "GetModuleHandleW", (SYSCALL)GetModuleHandleW, 0 },
+#else
+ { "GetModuleHandleW", (SYSCALL)0, 0 },
+#endif
+
+#define osGetModuleHandleW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[76].pCurrent)
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
{ "UuidCreate", (SYSCALL)UuidCreate, 0 },
@@ -41939,6 +42138,68 @@ static struct win_syscall {
#define osFlushViewOfFile \
((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent)
+#if defined(SQLITE_WIN32_HAS_WIDE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
+ { "SetDllDirectoryW", (SYSCALL)SetDllDirectoryW, 0 },
+#else
+ { "SetDllDirectoryW", (SYSCALL)0, 0 },
+#endif
+
+#define osSetDllDirectoryW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[80].pCurrent)
+
+#if defined(__CYGWIN__)
+ { "getenv", (SYSCALL)getenv, 0 },
+#else
+ { "getenv", (SYSCALL)0, 0 },
+#endif
+
+#define osGetenv ((const char *(*)(const char *))aSyscall[81].pCurrent)
+
+#if defined(__CYGWIN__)
+ { "getcwd", (SYSCALL)getcwd, 0 },
+#else
+ { "getcwd", (SYSCALL)0, 0 },
+#endif
+
+#define getcwd ((char*(*)(char*,size_t))aSyscall[82].pCurrent)
+
+#if defined(__CYGWIN__)
+ { "readlink", (SYSCALL)readlink, 0 },
+#else
+ { "readlink", (SYSCALL)0, 0 },
+#endif
+
+#define readlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[83].pCurrent)
+
+#if defined(__CYGWIN__)
+ { "lstat", (SYSCALL)lstat, 0 },
+#else
+ { "lstat", (SYSCALL)0, 0 },
+#endif
+
+#define lstat ((int(*)(const char*,struct cygwinstat*))aSyscall[84].pCurrent)
+
+#if defined(__CYGWIN__)
+ { "__errno", (SYSCALL)__errno, 0 },
+#else
+ { "__errno", (SYSCALL)0, 0 },
+#endif
+
+#define osErrno (*((int*(*)(void))aSyscall[85].pCurrent)())
+
+#if defined(__CYGWIN__) && defined(SQLITE_WIN32_HAS_WIDE)
+ { "cygwin_conv_path", (SYSCALL)cygwin_conv_path, 0 },
+#else
+ { "cygwin_conv_path", (SYSCALL)0, 0 },
+#endif
+
+#define cygwin_conv_path ((size_t(*)(unsigned int, \
+ const void *, void *, size_t))aSyscall[86].pCurrent)
+
+ { "cygwin_conv_to_full_win32_path", (SYSCALL)0, 0 },
+
+#define cygwin_conv_to_full_win32_path ((void(*)(const char *, \
+ char *))aSyscall[87].pCurrent)
+
}; /* End of the overrideable system calls */
/*
@@ -42052,7 +42313,7 @@ SQLITE_API int sqlite3_win32_compact_hea
(void*)hHeap);
rc = SQLITE_NOMEM_BKPT;
}else{
- sqlite3_log(SQLITE_ERROR, "failed to HeapCompact (%lu), heap=%p",
+ sqlite3_log(SQLITE_ERROR, "failed to HeapCompact (%u), heap=%p",
osGetLastError(), (void*)hHeap);
rc = SQLITE_ERROR;
}
@@ -42112,6 +42373,7 @@ SQLITE_API int sqlite3_win32_reset_heap(
}
#endif /* SQLITE_WIN32_MALLOC */
+#ifdef _WIN32
/*
** This function outputs the specified (ANSI) string to the Win32 debugger
** (if available).
@@ -42154,6 +42416,7 @@ SQLITE_API void sqlite3_win32_write_debu
}
#endif
}
+#endif /* _WIN32 */
/*
** The following routine suspends the current thread for at least ms
@@ -42163,6 +42426,9 @@ SQLITE_API void sqlite3_win32_write_debu
static HANDLE sleepObj = NULL;
#endif
+#if defined(__CYGWIN__) && defined(SQLITE_AMALGAMATION)
+static
+#endif
SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){
#if SQLITE_OS_WINRT
if ( sleepObj==NULL ){
@@ -42176,8 +42442,7 @@ SQLITE_API void sqlite3_win32_sleep(DWOR
#endif
}
-#if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \
- SQLITE_THREADSAFE>0
+#if SQLITE_OS_WIN_THREADS
SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){
DWORD rc;
while( (rc = osWaitForSingleObjectEx(hObject, INFINITE,
@@ -42208,6 +42473,7 @@ SQLITE_PRIVATE DWORD sqlite3Win32Wait(HA
# define osIsNT() ((sqlite3_os_type==2) || sqlite3_win32_is_nt())
#endif
+#if 0
/*
** This function determines if the machine is running a version of Windows
** based on the NT kernel.
@@ -42246,12 +42512,13 @@ SQLITE_API int sqlite3_win32_is_nt(void)
return 1;
#endif
}
+#endif /* 0 */
#ifdef SQLITE_WIN32_MALLOC
/*
** Allocate nBytes of memory.
*/
-static void *winMemMalloc(int nBytes){
+static void *winMemMalloc(size_t nBytes){
HANDLE hHeap;
void *p;
@@ -42262,11 +42529,10 @@ static void *winMemMalloc(int nBytes){
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
#endif
- assert( nBytes>=0 );
p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
if( !p ){
- sqlite3_log(SQLITE_NOMEM, "failed to HeapAlloc %u bytes (%lu), heap=%p",
- nBytes, osGetLastError(), (void*)hHeap);
+ sqlite3_log(SQLITE_NOMEM, "failed to HeapAlloc %llu bytes (%u), heap=%p",
+ (u64)nBytes, osGetLastError(), (void*)hHeap);
}
return p;
}
@@ -42286,7 +42552,7 @@ static void winMemFree(void *pPrior){
#endif
if( !pPrior ) return; /* Passing NULL to HeapFree is undefined. */
if( !osHeapFree(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ){
- sqlite3_log(SQLITE_NOMEM, "failed to HeapFree block %p (%lu), heap=%p",
+ sqlite3_log(SQLITE_NOMEM, "failed to HeapFree block %p (%u), heap=%p",
pPrior, osGetLastError(), (void*)hHeap);
}
}
@@ -42294,7 +42560,7 @@ static void winMemFree(void *pPrior){
/*
** Change the size of an existing memory allocation
*/
-static void *winMemRealloc(void *pPrior, int nBytes){
+static void *winMemRealloc(void *pPrior, size_t nBytes){
HANDLE hHeap;
void *p;
@@ -42305,15 +42571,14 @@ static void *winMemRealloc(void *pPrior,
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) );
#endif
- assert( nBytes>=0 );
if( !pPrior ){
p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
}else{
p = osHeapReAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior, (SIZE_T)nBytes);
}
if( !p ){
- sqlite3_log(SQLITE_NOMEM, "failed to %s %u bytes (%lu), heap=%p",
- pPrior ? "HeapReAlloc" : "HeapAlloc", nBytes, osGetLastError(),
+ sqlite3_log(SQLITE_NOMEM, "failed to %s %llu bytes (%u), heap=%p",
+ pPrior ? "HeapReAlloc" : "HeapAlloc", (u64)nBytes, osGetLastError(),
(void*)hHeap);
}
return p;
@@ -42322,7 +42587,7 @@ static void *winMemRealloc(void *pPrior,
/*
** Return the size of an outstanding allocation, in bytes.
*/
-static int winMemSize(void *p){
+static size_t winMemSize(void *p){
HANDLE hHeap;
SIZE_T n;
@@ -42336,17 +42601,17 @@ static int winMemSize(void *p){
if( !p ) return 0;
n = osHeapSize(hHeap, SQLITE_WIN32_HEAP_FLAGS, p);
if( n==(SIZE_T)-1 ){
- sqlite3_log(SQLITE_NOMEM, "failed to HeapSize block %p (%lu), heap=%p",
+ sqlite3_log(SQLITE_NOMEM, "failed to HeapSize block %p (%u), heap=%p",
p, osGetLastError(), (void*)hHeap);
return 0;
}
- return (int)n;
+ return (size_t)n;
}
/*
** Round up a request size to the next valid allocation size.
*/
-static int winMemRoundup(int n){
+static size_t winMemRoundup(size_t n){
return n;
}
@@ -42373,7 +42638,7 @@ static int winMemInit(void *pAppData){
dwInitialSize, dwMaximumSize);
if( !pWinMemData->hHeap ){
sqlite3_log(SQLITE_NOMEM,
- "failed to HeapCreate (%lu), flags=%u, initSize=%lu, maxSize=%lu",
+ "failed to HeapCreate (%u), flags=%u, initSize=%u, maxSize=%u",
osGetLastError(), SQLITE_WIN32_HEAP_FLAGS, dwInitialSize,
dwMaximumSize);
return SQLITE_NOMEM_BKPT;
@@ -42385,7 +42650,7 @@ static int winMemInit(void *pAppData){
pWinMemData->hHeap = osGetProcessHeap();
if( !pWinMemData->hHeap ){
sqlite3_log(SQLITE_NOMEM,
- "failed to GetProcessHeap (%lu)", osGetLastError());
+ "failed to GetProcessHeap (%u)", osGetLastError());
return SQLITE_NOMEM_BKPT;
}
pWinMemData->bOwned = FALSE;
@@ -42416,7 +42681,7 @@ static void winMemShutdown(void *pAppDat
#endif
if( pWinMemData->bOwned ){
if( !osHeapDestroy(pWinMemData->hHeap) ){
- sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%lu), heap=%p",
+ sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%u), heap=%p",
osGetLastError(), (void*)pWinMemData->hHeap);
}
pWinMemData->bOwned = FALSE;
@@ -42433,8 +42698,8 @@ static void winMemShutdown(void *pAppDat
** This routine is only called by sqlite3_config(), and therefore
** is not required to be threadsafe (it is not).
*/
-SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void){
- static const sqlite3_mem_methods winMemMethods = {
+SQLITE_PRIVATE const sqlite3_mem_methods2 *sqlite3MemGetWin32(void){
+ static const sqlite3_mem_methods2 winMemMethods = {
winMemMalloc,
winMemFree,
winMemRealloc,
@@ -42448,16 +42713,17 @@ SQLITE_PRIVATE const sqlite3_mem_methods
}
SQLITE_PRIVATE void sqlite3MemSetDefault(void){
- sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetWin32());
+ sqlite3_config(SQLITE_CONFIG_MALLOC2, sqlite3MemGetWin32());
}
#endif /* SQLITE_WIN32_MALLOC */
+#ifdef _WIN32
/*
** Convert a UTF-8 string to Microsoft Unicode.
**
** Space to hold the returned string is obtained from sqlite3_malloc().
*/
-static LPWSTR winUtf8ToUnicode(const char *zText){
+static LPWSTR winUtf8ToUnicode(const char *zText, WCHAR *buf){
int nChar;
LPWSTR zWideText;
@@ -42465,9 +42731,13 @@ static LPWSTR winUtf8ToUnicode(const cha
if( nChar==0 ){
return 0;
}
- zWideText = sqlite3MallocZero( nChar*sizeof(WCHAR) );
- if( zWideText==0 ){
- return 0;
+ if( buf && ((size_t)nChar<=MAX_PATH) ){
+ zWideText = buf;
+ }else{
+ zWideText = sqlite3Malloc( nChar*sizeof(WCHAR) );
+ if( zWideText==0 ){
+ return 0;
+ }
}
nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, zWideText,
nChar);
@@ -42477,6 +42747,7 @@ static LPWSTR winUtf8ToUnicode(const cha
}
return zWideText;
}
+#endif /* _WIN32 */
/*
** Convert a Microsoft Unicode string to UTF-8.
@@ -42491,7 +42762,7 @@ static char *winUnicodeToUtf8(LPCWSTR zW
if( nByte == 0 ){
return 0;
}
- zText = sqlite3MallocZero( nByte );
+ zText = sqlite3Malloc( nByte );
if( zText==0 ){
return 0;
}
@@ -42516,11 +42787,11 @@ static LPWSTR winMbcsToUnicode(const cha
int codepage = useAnsi ? CP_ACP : CP_OEMCP;
nByte = osMultiByteToWideChar(codepage, 0, zText, -1, NULL,
- 0)*sizeof(WCHAR);
+ 0);
if( nByte==0 ){
return 0;
}
- zMbcsText = sqlite3MallocZero( nByte*sizeof(WCHAR) );
+ zMbcsText = sqlite3Malloc( nByte*sizeof(WCHAR) );
if( zMbcsText==0 ){
return 0;
}
@@ -42533,6 +42804,7 @@ static LPWSTR winMbcsToUnicode(const cha
return zMbcsText;
}
+#ifdef _WIN32
/*
** Convert a Microsoft Unicode string to a multi-byte character string,
** using the ANSI or OEM code page.
@@ -42548,7 +42820,7 @@ static char *winUnicodeToMbcs(LPCWSTR zW
if( nByte == 0 ){
return 0;
}
- zText = sqlite3MallocZero( nByte );
+ zText = sqlite3Malloc( nByte );
if( zText==0 ){
return 0;
}
@@ -42560,6 +42832,7 @@ static char *winUnicodeToMbcs(LPCWSTR zW
}
return zText;
}
+#endif /* _WIN32 */
/*
** Convert a multi-byte character string to UTF-8.
@@ -42579,6 +42852,7 @@ static char *winMbcsToUtf8(const char *z
return zTextUtf8;
}
+#ifdef _WIN32
/*
** Convert a UTF-8 string to a multi-byte character string.
**
@@ -42587,13 +42861,16 @@ static char *winMbcsToUtf8(const char *z
static char *winUtf8ToMbcs(const char *zText, int useAnsi){
char *zTextMbcs;
LPWSTR zTmpWide;
+ WCHAR buf[MAX_PATH];
- zTmpWide = winUtf8ToUnicode(zText);
+ zTmpWide = winUtf8ToUnicode(zText, buf);
if( zTmpWide==0 ){
return 0;
}
zTextMbcs = winUnicodeToMbcs(zTmpWide, useAnsi);
- sqlite3_free(zTmpWide);
+ if (zTmpWide != buf){
+ sqlite3_free(zTmpWide);
+ }
return zTextMbcs;
}
@@ -42610,7 +42887,7 @@ SQLITE_API LPWSTR sqlite3_win32_utf8_to_
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
- return winUtf8ToUnicode(zText);
+ return winUtf8ToUnicode(zText, 0);
}
/*
@@ -42628,6 +42905,7 @@ SQLITE_API char *sqlite3_win32_unicode_t
#endif
return winUnicodeToUtf8(zWideText);
}
+#endif /* _WIN32 */
/*
** This is a public wrapper for the winMbcsToUtf8() function.
@@ -42645,6 +42923,7 @@ SQLITE_API char *sqlite3_win32_mbcs_to_u
return winMbcsToUtf8(zText, osAreFileApisANSI());
}
+#ifdef _WIN32
/*
** This is a public wrapper for the winMbcsToUtf8() function.
*/
@@ -42715,7 +42994,7 @@ SQLITE_API int sqlite3_win32_set_directo
|| type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE
);
assert( !ppDirectory || sqlite3MemdebugHasType(*ppDirectory, MEMTYPE_HEAP) );
- if( ppDirectory ){
+ if( !osGetenv && ppDirectory ){
char *zCopy = 0;
if( zValue && zValue[0] ){
zCopy = sqlite3_mprintf("%s", zValue);
@@ -42762,6 +43041,7 @@ SQLITE_API int sqlite3_win32_set_directo
){
return sqlite3_win32_set_directory16(type, zValue);
}
+#endif /* _WIN32 */
/*
** The return value of winGetLastErrorMsg
@@ -42833,7 +43113,7 @@ static int winGetLastErrorMsg(DWORD last
}
#endif
if( 0 == dwLen ){
- sqlite3_snprintf(nBuf, zBuf, "OsError 0x%lx (%lu)", lastErrno, lastErrno);
+ sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", lastErrno, lastErrno);
}else{
/* copy a maximum of nBuf chars to output buffer */
sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
@@ -42876,7 +43156,7 @@ static int winLogErrorAtLine(
for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){}
zMsg[i] = 0;
sqlite3_log(errcode,
- "os_win.c:%d: (%lu) %s(%s) - %s",
+ "os_win.c:%d: (%u) %s(%s) - %s",
iLine, lastErrno, zFunc, zPath, zMsg
);
@@ -43031,8 +43311,9 @@ static int winceCreateLock(const char *z
DWORD lastErrno;
BOOL bLogged = FALSE;
BOOL bInit = TRUE;
+ WCHAR buf[MAX_PATH];
- zName = winUtf8ToUnicode(zFilename);
+ zName = winUtf8ToUnicode(zFilename, buf);
if( zName==0 ){
/* out of memory */
return SQLITE_IOERR_NOMEM_BKPT;
@@ -43052,7 +43333,9 @@ static int winceCreateLock(const char *z
pFile->hMutex = osCreateMutexW(NULL, FALSE, zName);
if (!pFile->hMutex){
pFile->lastErrno = osGetLastError();
- sqlite3_free(zName);
+ if( zName!=buf ){
+ sqlite3_free(zName);
+ }
return winLogError(SQLITE_IOERR, pFile->lastErrno,
"winceCreateLock1", zFilename);
}
@@ -43076,7 +43359,9 @@ static int winceCreateLock(const char *z
bInit = FALSE;
}
- sqlite3_free(zName);
+ if( zName!=buf ){
+ sqlite3_free(zName);
+ }
/* If we succeeded in making the shared memory handle, map it. */
if( pFile->hShared ){
@@ -43310,9 +43595,11 @@ static BOOL winLockFile(
ovlp.Offset = offsetLow;
ovlp.OffsetHigh = offsetHigh;
return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp);
+#ifdef SQLITE_WIN32_HAS_ANSI
}else{
return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
numBytesHigh);
+#endif
}
#endif
}
@@ -43341,9 +43628,11 @@ static BOOL winUnlockFile(
ovlp.Offset = offsetLow;
ovlp.OffsetHigh = offsetHigh;
return osUnlockFileEx(*phFile, 0, numBytesLow, numBytesHigh, &ovlp);
+#ifdef SQLITE_WIN32_HAS_ANSI
}else{
return osUnlockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
numBytesHigh);
+#endif
}
#endif
}
@@ -43447,7 +43736,7 @@ static int winClose(sqlite3_file *id){
assert( pFile->pShm==0 );
#endif
assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE );
- OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p\n",
+ OSTRACE(("CLOSE pid=%u, pFile=%p, file=%p\n",
osGetCurrentProcessId(), pFile, pFile->h));
#if SQLITE_MAX_MMAP_SIZE>0
@@ -43482,7 +43771,7 @@ static int winClose(sqlite3_file *id){
pFile->h = NULL;
}
OpenCounter(-1);
- OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p, rc=%s\n",
+ OSTRACE(("CLOSE pid=%u, pFile=%p, file=%p, rc=%s\n",
osGetCurrentProcessId(), pFile, pFile->h, rc ? "ok" : "failed"));
return rc ? SQLITE_OK
: winLogError(SQLITE_IOERR_CLOSE, osGetLastError(),
@@ -43511,7 +43800,7 @@ static int winRead(
assert( amt>0 );
assert( offset>=0 );
SimulateIOError(return SQLITE_IOERR_READ);
- OSTRACE(("READ pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, "
+ OSTRACE(("READ pid=%u, pFile=%p, file=%p, buffer=%p, amount=%d, "
"offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile,
pFile->h, pBuf, amt, offset, pFile->locktype));
@@ -43521,7 +43810,7 @@ static int winRead(
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt);
- OSTRACE(("READ-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ OSTRACE(("READ-MMAP pid=%u, pFile=%p, file=%p, rc=SQLITE_OK\n",
osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}else{
@@ -43536,7 +43825,7 @@ static int winRead(
#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
if( winSeekFile(pFile, offset) ){
- OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n",
+ OSTRACE(("READ pid=%u, pFile=%p, file=%p, rc=SQLITE_FULL\n",
osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_FULL;
}
@@ -43551,7 +43840,7 @@ static int winRead(
DWORD lastErrno;
if( winRetryIoerr(&nRetry, &lastErrno) ) continue;
pFile->lastErrno = lastErrno;
- OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_READ\n",
+ OSTRACE(("READ pid=%u, pFile=%p, file=%p, rc=SQLITE_IOERR_READ\n",
osGetCurrentProcessId(), pFile, pFile->h));
return winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
"winRead", pFile->zPath);
@@ -43560,12 +43849,12 @@ static int winRead(
if( nRead<(DWORD)amt ){
/* Unread parts of the buffer must be zero-filled */
memset(&((char*)pBuf)[nRead], 0, amt-nRead);
- OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_SHORT_READ\n",
+ OSTRACE(("READ pid=%u, pFile=%p, file=%p, rc=SQLITE_IOERR_SHORT_READ\n",
osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_IOERR_SHORT_READ;
}
- OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ OSTRACE(("READ pid=%u, pFile=%p, file=%p, rc=SQLITE_OK\n",
osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}
@@ -43589,7 +43878,7 @@ static int winWrite(
SimulateIOError(return SQLITE_IOERR_WRITE);
SimulateDiskfullError(return SQLITE_FULL);
- OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, "
+ OSTRACE(("WRITE pid=%u, pFile=%p, file=%p, buffer=%p, amount=%d, "
"offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile,
pFile->h, pBuf, amt, offset, pFile->locktype));
@@ -43599,7 +43888,7 @@ static int winWrite(
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt);
- OSTRACE(("WRITE-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ OSTRACE(("WRITE-MMAP pid=%u, pFile=%p, file=%p, rc=SQLITE_OK\n",
osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}else{
@@ -43663,19 +43952,19 @@ static int winWrite(
if( rc ){
if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL )
|| ( pFile->lastErrno==ERROR_DISK_FULL )){
- OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n",
+ OSTRACE(("WRITE pid=%u, pFile=%p, file=%p, rc=SQLITE_FULL\n",
osGetCurrentProcessId(), pFile, pFile->h));
return winLogError(SQLITE_FULL, pFile->lastErrno,
"winWrite1", pFile->zPath);
}
- OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_WRITE\n",
+ OSTRACE(("WRITE pid=%u, pFile=%p, file=%p, rc=SQLITE_IOERR_WRITE\n",
osGetCurrentProcessId(), pFile, pFile->h));
return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno,
"winWrite2", pFile->zPath);
}else{
winLogIoerr(nRetry, __LINE__);
}
- OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ OSTRACE(("WRITE pid=%u, pFile=%p, file=%p, rc=SQLITE_OK\n",
osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}
@@ -43713,7 +44002,7 @@ static int winTruncate(sqlite3_file *id,
assert( pFile );
SimulateIOError(return SQLITE_IOERR_TRUNCATE);
- OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, size=%lld, lock=%d\n",
+ OSTRACE(("TRUNCATE pid=%u, pFile=%p, file=%p, size=%lld, lock=%d\n",
osGetCurrentProcessId(), pFile, pFile->h, nByte, pFile->locktype));
/* If the user has configured a chunk-size for this file, truncate the
@@ -43755,7 +44044,7 @@ static int winTruncate(sqlite3_file *id,
}
#endif
- OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, rc=%s\n",
+ OSTRACE(("TRUNCATE pid=%u, pFile=%p, file=%p, rc=%s\n",
osGetCurrentProcessId(), pFile, pFile->h, sqlite3ErrName(rc)));
return rc;
}
@@ -43801,7 +44090,7 @@ static int winSync(sqlite3_file *id, int
*/
SimulateDiskfullError( return SQLITE_FULL );
- OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, flags=%x, lock=%d\n",
+ OSTRACE(("SYNC pid=%u, pFile=%p, file=%p, flags=%x, lock=%d\n",
osGetCurrentProcessId(), pFile, pFile->h, flags,
pFile->locktype));
@@ -43818,19 +44107,19 @@ static int winSync(sqlite3_file *id, int
** no-op
*/
#ifdef SQLITE_NO_SYNC
- OSTRACE(("SYNC-NOP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ OSTRACE(("SYNC-NOP pid=%u, pFile=%p, file=%p, rc=SQLITE_OK\n",
osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
#else
#if SQLITE_MAX_MMAP_SIZE>0
if( pFile->pMapRegion ){
if( osFlushViewOfFile(pFile->pMapRegion, 0) ){
- OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, "
+ OSTRACE(("SYNC-MMAP pid=%u, pFile=%p, pMapRegion=%p, "
"rc=SQLITE_OK\n", osGetCurrentProcessId(),
pFile, pFile->pMapRegion));
}else{
pFile->lastErrno = osGetLastError();
- OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, "
+ OSTRACE(("SYNC-MMAP pid=%u, pFile=%p, pMapRegion=%p, "
"rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(),
pFile, pFile->pMapRegion));
return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
@@ -43841,12 +44130,12 @@ static int winSync(sqlite3_file *id, int
rc = osFlushFileBuffers(pFile->h);
SimulateIOError( rc=FALSE );
if( rc ){
- OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ OSTRACE(("SYNC pid=%u, pFile=%p, file=%p, rc=SQLITE_OK\n",
osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}else{
pFile->lastErrno = osGetLastError();
- OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_FSYNC\n",
+ OSTRACE(("SYNC pid=%u, pFile=%p, file=%p, rc=SQLITE_IOERR_FSYNC\n",
osGetCurrentProcessId(), pFile, pFile->h));
return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno,
"winSync2", pFile->zPath);
@@ -44597,7 +44886,7 @@ static int winShmSystemLock(
rc = SQLITE_BUSY;
}
- OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n",
+ OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%u, rc=%s\n",
pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" :
"winLockFile", pFile->lastErrno, sqlite3ErrName(rc)));
@@ -44618,7 +44907,7 @@ static void winShmPurge(sqlite3_vfs *pVf
winShmNode **pp;
winShmNode *p;
assert( winShmMutexHeld() );
- OSTRACE(("SHM-PURGE pid=%lu, deleteFlag=%d\n",
+ OSTRACE(("SHM-PURGE pid=%u, deleteFlag=%d\n",
osGetCurrentProcessId(), deleteFlag));
pp = &winShmNodeList;
while( (p = *pp)!=0 ){
@@ -44627,11 +44916,11 @@ static void winShmPurge(sqlite3_vfs *pVf
if( p->mutex ){ sqlite3_mutex_free(p->mutex); }
for(i=0; i<p->nRegion; i++){
BOOL bRc = osUnmapViewOfFile(p->aRegion[i].pMap);
- OSTRACE(("SHM-PURGE-UNMAP pid=%lu, region=%d, rc=%s\n",
+ OSTRACE(("SHM-PURGE-UNMAP pid=%u, region=%d, rc=%s\n",
osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
UNUSED_VARIABLE_VALUE(bRc);
bRc = osCloseHandle(p->aRegion[i].hMap);
- OSTRACE(("SHM-PURGE-CLOSE pid=%lu, region=%d, rc=%s\n",
+ OSTRACE(("SHM-PURGE-CLOSE pid=%u, region=%d, rc=%s\n",
osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
UNUSED_VARIABLE_VALUE(bRc);
}
@@ -44941,7 +45230,7 @@ static int winShmLock(
}
}
sqlite3_mutex_leave(pShmNode->mutex);
- OSTRACE(("SHM-LOCK pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x, rc=%s\n",
+ OSTRACE(("SHM-LOCK pid=%u, id=%d, sharedMask=%03x, exclMask=%03x, rc=%s\n",
osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask,
sqlite3ErrName(rc)));
return rc;
@@ -45077,7 +45366,7 @@ static int winShmMap(
NULL, protect, 0, nByte, NULL
);
#endif
- OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n",
+ OSTRACE(("SHM-MAP-CREATE pid=%u, region=%d, size=%d, rc=%s\n",
osGetCurrentProcessId(), pShmNode->nRegion, nByte,
hMap ? "ok" : "failed"));
if( hMap ){
@@ -45092,7 +45381,7 @@ static int winShmMap(
0, iOffset - iOffsetShift, szRegion + iOffsetShift
);
#endif
- OSTRACE(("SHM-MAP-MAP pid=%lu, region=%d, offset=%d, size=%d, rc=%s\n",
+ OSTRACE(("SHM-MAP-MAP pid=%u, region=%d, offset=%d, size=%d, rc=%s\n",
osGetCurrentProcessId(), pShmNode->nRegion, iOffset,
szRegion, pMap ? "ok" : "failed"));
}
@@ -45137,14 +45426,14 @@ shmpage_out:
#if SQLITE_MAX_MMAP_SIZE>0
static int winUnmapfile(winFile *pFile){
assert( pFile!=0 );
- OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, pMapRegion=%p, "
+ OSTRACE(("UNMAP-FILE pid=%u, pFile=%p, hMap=%p, pMapRegion=%p, "
"mmapSize=%lld, mmapSizeMax=%lld\n",
osGetCurrentProcessId(), pFile, pFile->hMap, pFile->pMapRegion,
pFile->mmapSize, pFile->mmapSizeMax));
if( pFile->pMapRegion ){
if( !osUnmapViewOfFile(pFile->pMapRegion) ){
pFile->lastErrno = osGetLastError();
- OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, pMapRegion=%p, "
+ OSTRACE(("UNMAP-FILE pid=%u, pFile=%p, pMapRegion=%p, "
"rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(), pFile,
pFile->pMapRegion));
return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
@@ -45156,14 +45445,14 @@ static int winUnmapfile(winFile *pFile){
if( pFile->hMap!=NULL ){
if( !osCloseHandle(pFile->hMap) ){
pFile->lastErrno = osGetLastError();
- OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, rc=SQLITE_IOERR_MMAP\n",
+ OSTRACE(("UNMAP-FILE pid=%u, pFile=%p, hMap=%p, rc=SQLITE_IOERR_MMAP\n",
osGetCurrentProcessId(), pFile, pFile->hMap));
return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
"winUnmapfile2", pFile->zPath);
}
pFile->hMap = NULL;
}
- OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
+ OSTRACE(("UNMAP-FILE pid=%u, pFile=%p, rc=SQLITE_OK\n",
osGetCurrentProcessId(), pFile));
return SQLITE_OK;
}
@@ -45189,7 +45478,7 @@ static int winMapfile(winFile *pFd, sqli
int rc;
assert( nMap>=0 || pFd->nFetchOut==0 );
- OSTRACE(("MAP-FILE pid=%lu, pFile=%p, size=%lld\n",
+ OSTRACE(("MAP-FILE pid=%u, pFile=%p, size=%lld\n",
osGetCurrentProcessId(), pFd, nByte));
if( pFd->nFetchOut>0 ) return SQLITE_OK;
@@ -45197,7 +45486,7 @@ static int winMapfile(winFile *pFd, sqli
if( nMap<0 ){
rc = winFileSize((sqlite3_file*)pFd, &nMap);
if( rc ){
- OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_IOERR_FSTAT\n",
+ OSTRACE(("MAP-FILE pid=%u, pFile=%p, rc=SQLITE_IOERR_FSTAT\n",
osGetCurrentProcessId(), pFd));
return SQLITE_IOERR_FSTAT;
}
@@ -45238,7 +45527,7 @@ static int winMapfile(winFile *pFd, sqli
rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno,
"winMapfile1", pFd->zPath);
/* Log the error, but continue normal operation using xRead/xWrite */
- OSTRACE(("MAP-FILE-CREATE pid=%lu, pFile=%p, rc=%s\n",
+ OSTRACE(("MAP-FILE-CREATE pid=%u, pFile=%p, rc=%s\n",
osGetCurrentProcessId(), pFd, sqlite3ErrName(rc)));
return SQLITE_OK;
}
@@ -45256,7 +45545,7 @@ static int winMapfile(winFile *pFd, sqli
rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno,
"winMapfile2", pFd->zPath);
/* Log the error, but continue normal operation using xRead/xWrite */
- OSTRACE(("MAP-FILE-MAP pid=%lu, pFile=%p, rc=%s\n",
+ OSTRACE(("MAP-FILE-MAP pid=%u, pFile=%p, rc=%s\n",
osGetCurrentProcessId(), pFd, sqlite3ErrName(rc)));
return SQLITE_OK;
}
@@ -45264,7 +45553,7 @@ static int winMapfile(winFile *pFd, sqli
pFd->mmapSize = nMap;
}
- OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
+ OSTRACE(("MAP-FILE pid=%u, pFile=%p, rc=SQLITE_OK\n",
osGetCurrentProcessId(), pFd));
return SQLITE_OK;
}
@@ -45288,7 +45577,7 @@ static int winFetch(sqlite3_file *fd, i6
#endif
*pp = 0;
- OSTRACE(("FETCH pid=%lu, pFile=%p, offset=%lld, amount=%d, pp=%p\n",
+ OSTRACE(("FETCH pid=%u, pFile=%p, offset=%lld, amount=%d, pp=%p\n",
osGetCurrentProcessId(), fd, iOff, nAmt, pp));
#if SQLITE_MAX_MMAP_SIZE>0
@@ -45296,7 +45585,7 @@ static int winFetch(sqlite3_file *fd, i6
if( pFd->pMapRegion==0 ){
int rc = winMapfile(pFd, -1);
if( rc!=SQLITE_OK ){
- OSTRACE(("FETCH pid=%lu, pFile=%p, rc=%s\n",
+ OSTRACE(("FETCH pid=%u, pFile=%p, rc=%s\n",
osGetCurrentProcessId(), pFd, sqlite3ErrName(rc)));
return rc;
}
@@ -45309,7 +45598,7 @@ static int winFetch(sqlite3_file *fd, i6
}
#endif
- OSTRACE(("FETCH pid=%lu, pFile=%p, pp=%p, *pp=%p, rc=SQLITE_OK\n",
+ OSTRACE(("FETCH pid=%u, pFile=%p, pp=%p, *pp=%p, rc=SQLITE_OK\n",
osGetCurrentProcessId(), fd, pp, *pp));
return SQLITE_OK;
}
@@ -45336,7 +45625,7 @@ static int winUnfetch(sqlite3_file *fd,
/* If p!=0, it must match the iOff value. */
assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] );
- OSTRACE(("UNFETCH pid=%lu, pFile=%p, offset=%lld, p=%p\n",
+ OSTRACE(("UNFETCH pid=%u, pFile=%p, offset=%lld, p=%p\n",
osGetCurrentProcessId(), pFd, iOff, p));
if( p ){
@@ -45352,7 +45641,8 @@ static int winUnfetch(sqlite3_file *fd,
assert( pFd->nFetchOut>=0 );
#endif
- OSTRACE(("UNFETCH pid=%lu, pFile=%p, rc=SQLITE_OK\n",
+ UNUSED_PARAMETER(iOff);
+ OSTRACE(("UNFETCH pid=%u, pFile=%p, rc=SQLITE_OK\n",
osGetCurrentProcessId(), fd));
return SQLITE_OK;
}
@@ -45434,7 +45724,7 @@ static winVfsAppData winNolockAppData =
** sqlite3_vfs object.
*/
-#if defined(__CYGWIN__)
+#if 0
/*
** Convert a filename from whatever the underlying operating system
** supports for filenames into UTF-8. Space to hold the result is
@@ -45459,12 +45749,106 @@ static char *winConvertToUtf8Filename(co
** Convert a UTF-8 filename into whatever form the underlying
** operating system wants filenames in. Space to hold the result
** is obtained from malloc and must be freed by the calling
-** function.
+** function, unless buf is not NULL and the needed size is less
+** than MAX_PATH bytes.
+**
+** On Cygwin 1.7 and higher, 3 possible input forms are accepted:
+** - If the filename starts with "<drive>:/" or "<drive>:\",
+** it is converted to UTF-16 as-is.
+** - If the filename contains '/', it is assumed to be a
+** Cygwin absolute path, it is converted to a win32
+** absolute path in UTF-16.
+** - Otherwise it must be a filename only, the win32 filename
+** is returned in UTF-16.
+** Note: The function cygwin_conv_path does not exist in
+** Cygwin 1.5. Cygwin 1.7 does not run in Windows 95/98/ME.
+** Therefore the !osIsNT() case does not need special handling.
+** Note 2: If the function cygwin_conv_path() fails, only
+** UTF-8 -> UTF-16 conversion will be done. This can only
+** happen when the file path >32k, in which case winUtf8ToUnicode()
+** will fail too.
*/
-static void *winConvertFromUtf8Filename(const char *zFilename){
+static void *winConvertFromUtf8Filename(const char *zFilename, WCHAR *buf){
void *zConverted = 0;
if( osIsNT() ){
- zConverted = winUtf8ToUnicode(zFilename);
+ int nChar;
+ LPWSTR zWideFilename;
+
+ if( cygwin_conv_path && !(winIsDriveLetterAndColon(zFilename)
+ && winIsDirSep(zFilename[2])) ){
+ int nByte;
+ int convertflag = CCP_POSIX_TO_WIN_W;
+ if( !strchr(zFilename, '/') ) convertflag |= CCP_RELATIVE;
+ nByte = (int) cygwin_conv_path(convertflag,
+ zFilename, 0, 0);
+ if( nByte>0 ){
+ if( buf && (nByte<(MAX_PATH-12)) ){
+ zConverted = buf;
+ }else{
+ zConverted = sqlite3Malloc(nByte+12);
+ if ( zConverted==0 ){
+ return zConverted;
+ }
+ }
+ zWideFilename = zConverted;
+ /* Filenames should be prefixed, except when converted
+ * full path already starts with "\\?\". */
+ if( cygwin_conv_path(convertflag, zFilename,
+ zWideFilename+4, nByte)==0 ){
+ if( (convertflag&CCP_RELATIVE) ){
+ memmove(zWideFilename, zWideFilename+4, nByte);
+ }else if( memcmp(zWideFilename+4, L"\\\\", 4) ){
+ memcpy(zWideFilename, L"\\\\?\\", 8);
+ }else if( zWideFilename[6]!='?' ){
+ memmove(zWideFilename+6, zWideFilename+4, nByte);
+ memcpy(zWideFilename, L"\\\\?\\UNC", 14);
+ }else{
+ memmove(zWideFilename, zWideFilename+4, nByte);
+ }
+ return zConverted;
+ }
+ if( zConverted!=buf ){
+ sqlite3_free(zConverted);
+ }
+ }
+#ifdef _WIN32
+ }else if( (cygwin_conv_to_full_win32_path!=NULL) &&
+ !(winIsDriveLetterAndColon(zFilename) && winIsDirSep(zFilename[2]))){
+ char buf1[MAX_PATH];
+ cygwin_conv_to_full_win32_path(zFilename, buf1);
+ return winMbcsToUnicode(buf1, osAreFileApisANSI());
+#endif
+ }
+ nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
+ if( nChar==0 ){
+ return 0;
+ }
+ if( buf && ((size_t)nChar<=MAX_PATH) ){
+ zWideFilename = buf;
+ }else{
+ zWideFilename = sqlite3Malloc( nChar*sizeof(WCHAR)+12 );
+ if( zWideFilename==0 ){
+ return 0;
+ }
+ }
+ nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1,
+ zWideFilename, nChar);
+ if( nChar==0 ){
+ sqlite3_free(zWideFilename);
+ zWideFilename = 0;
+ }else if( nChar>MAX_PATH
+ && winIsDriveLetterAndColon(zFilename)
+ && winIsDirSep(zFilename[2]) ){
+ memmove(zWideFilename+4, zWideFilename, nChar*sizeof(WCHAR));
+ zWideFilename[2] = '\\';
+ memcpy(zWideFilename, L"\\\\?\\", 8);
+ }else if( nChar>MAX_PATH
+ && winIsDirSep(zFilename[0]) && winIsDirSep(zFilename[1])
+ && zFilename[2] != '?' ){
+ memmove(zWideFilename+6, zWideFilename, nChar*sizeof(WCHAR));
+ memcpy(zWideFilename, L"\\\\?\\UNC", 14);
+ }
+ zConverted = zWideFilename;
}
#ifdef SQLITE_WIN32_HAS_ANSI
else{
@@ -45487,7 +45871,14 @@ static int winMakeEndInDirSep(int nBuf,
if( winIsDirSep(zBuf[nLen-1]) ){
return 1;
}else if( nLen+1<nBuf ){
- zBuf[nLen] = winGetDirSep();
+ if( !osGetenv ){
+ zBuf[nLen] = '\\';
+ }else if( winIsDriveLetterAndColon(zBuf) && winIsDirSep(zBuf[2]) ){
+ zBuf[nLen] = '\\';
+ zBuf[2]='\\';
+ }else{
+ zBuf[nLen] = '/';
+ }
zBuf[nLen+1] = '\0';
return 1;
}
@@ -45501,7 +45892,7 @@ static int winMakeEndInDirSep(int nBuf,
** The pointer returned in pzBuf must be freed via sqlite3_free().
*/
static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
- static char zChars[] =
+ static const char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
@@ -45546,8 +45937,8 @@ static int winGetTempname(sqlite3_vfs *p
sqlite3_snprintf(nMax, zBuf, "%s", sqlite3_temp_directory);
}
}
-#if defined(__CYGWIN__)
- else{
+#if SQLITE_OS_WINNT
+ else if( osGetenv!=NULL ){
static const char *azDirs[] = {
0, /* getenv("SQLITE_TMPDIR") */
0, /* getenv("TMPDIR") */
@@ -45563,21 +45954,22 @@ static int winGetTempname(sqlite3_vfs *p
unsigned int i;
const char *zDir = 0;
- if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR");
- if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
- if( !azDirs[2] ) azDirs[2] = getenv("TMP");
- if( !azDirs[3] ) azDirs[3] = getenv("TEMP");
- if( !azDirs[4] ) azDirs[4] = getenv("USERPROFILE");
+ if( !azDirs[0] ) azDirs[0] = osGetenv("SQLITE_TMPDIR");
+ if( !azDirs[1] ) azDirs[1] = osGetenv("TMPDIR");
+ if( !azDirs[2] ) azDirs[2] = osGetenv("TMP");
+ if( !azDirs[3] ) azDirs[3] = osGetenv("TEMP");
+ if( !azDirs[4] ) azDirs[4] = osGetenv("USERPROFILE");
for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
void *zConverted;
+ WCHAR buf[MAX_PATH];
if( zDir==0 ) continue;
/* If the path starts with a drive letter followed by the colon
** character, assume it is already a native Win32 path; otherwise,
** it must be converted to a native Win32 path via the Cygwin API
** prior to using it.
*/
- if( winIsDriveLetterAndColon(zDir) ){
- zConverted = winConvertFromUtf8Filename(zDir);
+ {
+ zConverted = winConvertFromUtf8Filename(zDir, buf);
if( !zConverted ){
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
@@ -45585,10 +45977,15 @@ static int winGetTempname(sqlite3_vfs *p
}
if( winIsDir(zConverted) ){
sqlite3_snprintf(nMax, zBuf, "%s", zDir);
- sqlite3_free(zConverted);
+ if( zConverted!=buf ){
+ sqlite3_free(zConverted);
+ }
break;
}
- sqlite3_free(zConverted);
+ if( zConverted!=buf ){
+ sqlite3_free(zConverted);
+ }
+#if 0 /* No longer necessary */
}else{
zConverted = sqlite3MallocZero( nMax+1 );
if( !zConverted ){
@@ -45623,13 +46020,16 @@ static int winGetTempname(sqlite3_vfs *p
break;
}
sqlite3_free(zConverted);
+#endif /* No longer necessary */
}
}
}
-#elif !SQLITE_OS_WINRT && !defined(__CYGWIN__)
+#endif
+
+#if !SQLITE_OS_WINRT && !defined(__CYGWIN__)
else if( osIsNT() ){
char *zMulti;
- LPWSTR zWidePath = sqlite3MallocZero( nMax*sizeof(WCHAR) );
+ LPWSTR zWidePath = sqlite3Malloc( nMax*sizeof(WCHAR) );
if( !zWidePath ){
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
@@ -45779,9 +46179,7 @@ static int winOpen(
DWORD dwShareMode;
DWORD dwCreationDisposition;
DWORD dwFlagsAndAttributes = 0;
-#if SQLITE_OS_WINCE
- int isTemp = 0;
-#endif
+ WCHAR buf[MAX_PATH];
winVfsAppData *pAppData;
winFile *pFile = (winFile*)id;
void *zConverted; /* Filename in OS encoding */
@@ -45873,7 +46271,11 @@ static int winOpen(
zUtf8Name[sqlite3Strlen30(zUtf8Name)+1]==0 );
/* Convert the filename to the system encoding. */
- zConverted = winConvertFromUtf8Filename(zUtf8Name);
+#if SQLITE_OS_WINCE
+ zConverted = winConvertFromUtf8Filename(zUtf8Name, isDelete ? 0 : buf );
+#else
+ zConverted = winConvertFromUtf8Filename(zUtf8Name, buf );
+#endif
if( zConverted==0 ){
sqlite3_free(zTmpname);
OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name));
@@ -45881,7 +46283,9 @@ static int winOpen(
}
if( winIsDir(zConverted) ){
- sqlite3_free(zConverted);
+ if( zConverted!=buf ){
+ sqlite3_free(zConverted);
+ }
sqlite3_free(zTmpname);
OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8Name));
return SQLITE_CANTOPEN_ISDIR;
@@ -45914,7 +46318,6 @@ static int winOpen(
if( isDelete ){
#if SQLITE_OS_WINCE
dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN;
- isTemp = 1;
#else
dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY
| FILE_ATTRIBUTE_HIDDEN
@@ -45999,7 +46402,9 @@ static int winOpen(
dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
if( h==INVALID_HANDLE_VALUE ){
- sqlite3_free(zConverted);
+ if( zConverted!=buf ){
+ sqlite3_free(zConverted);
+ }
sqlite3_free(zTmpname);
if( isReadWrite && !isExclusive ){
return winOpen(pVfs, zName, id,
@@ -46034,18 +46439,22 @@ static int winOpen(
&& (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
){
osCloseHandle(h);
- sqlite3_free(zConverted);
+ if( zConverted!=buf ){
+ sqlite3_free(zConverted);
+ }
sqlite3_free(zTmpname);
OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc)));
return rc;
}
}
- if( isTemp ){
+ if( isDelete ){
pFile->zDeleteOnClose = zConverted;
}else
#endif
{
- sqlite3_free(zConverted);
+ if( zConverted!=buf ){
+ sqlite3_free(zConverted);
+ }
}
sqlite3_free(zTmpname);
@@ -46093,13 +46502,14 @@ static int winDelete(
DWORD attr;
DWORD lastErrno = 0;
void *zConverted;
+ WCHAR buf[MAX_PATH];
UNUSED_PARAMETER(pVfs);
UNUSED_PARAMETER(syncDir);
SimulateIOError(return SQLITE_IOERR_DELETE);
OSTRACE(("DELETE name=%s, syncDir=%d\n", zFilename, syncDir));
- zConverted = winConvertFromUtf8Filename(zFilename);
+ zConverted = winConvertFromUtf8Filename(zFilename, buf);
if( zConverted==0 ){
OSTRACE(("DELETE name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
return SQLITE_IOERR_NOMEM_BKPT;
@@ -46183,7 +46593,9 @@ static int winDelete(
}else{
winLogIoerr(cnt, __LINE__);
}
- sqlite3_free(zConverted);
+ if( zConverted != buf ){
+ sqlite3_free(zConverted);
+ }
OSTRACE(("DELETE name=%s, rc=%s\n", zFilename, sqlite3ErrName(rc)));
return rc;
}
@@ -46201,13 +46613,14 @@ static int winAccess(
int rc = 0;
DWORD lastErrno = 0;
void *zConverted;
+ WCHAR buf[MAX_PATH];
UNUSED_PARAMETER(pVfs);
SimulateIOError( return SQLITE_IOERR_ACCESS; );
OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n",
zFilename, flags, pResOut));
- zConverted = winConvertFromUtf8Filename(zFilename);
+ zConverted = winConvertFromUtf8Filename(zFilename, buf);
if( zConverted==0 ){
OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
return SQLITE_IOERR_NOMEM_BKPT;
@@ -46233,7 +46646,9 @@ static int winAccess(
}else{
winLogIoerr(cnt, __LINE__);
if( lastErrno!=ERROR_FILE_NOT_FOUND && lastErrno!=ERROR_PATH_NOT_FOUND ){
- sqlite3_free(zConverted);
+ if( zConverted!=buf ){
+ sqlite3_free(zConverted);
+ }
return winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess",
zFilename);
}else{
@@ -46246,7 +46661,9 @@ static int winAccess(
attr = osGetFileAttributesA((char*)zConverted);
}
#endif
- sqlite3_free(zConverted);
+ if( zConverted!=buf ){
+ sqlite3_free(zConverted);
+ }
switch( flags ){
case SQLITE_ACCESS_READ:
case SQLITE_ACCESS_EXISTS:
@@ -46275,6 +46692,7 @@ static BOOL winIsDriveLetterAndColon(
return ( sqlite3Isalpha(zPathname[0]) && zPathname[1]==':' );
}
+#ifdef _WIN32
/*
** Returns non-zero if the specified path name should be used verbatim. If
** non-zero is returned from this function, the calling function must simply
@@ -46311,6 +46729,71 @@ static BOOL winIsVerbatimPathname(
*/
return FALSE;
}
+#endif /* _WIN32 */
+
+/*
+** Simplify a filename into its canonical form
+** by making the following changes:
+**
+** * convert any '/' to '\' (win32) or reverse (Cygwin)
+** * removing any trailing and duplicate / (except for UNC paths)
+** * convert /./ into just /
+**
+** Changes are made in-place. Return the new name length.
+**
+** The original filename is in z[0..]. If the path is shortened,
+** no-longer used bytes will be written by '\0'.
+*/
+static void winSimplifyName(char *z){
+ int i, j;
+ for(i=j=0; z[i]; ++i){
+ if( winIsDirSep(z[i]) ){
+#if !defined(SQLITE_TEST)
+ /* Some test-cases assume that "./foo" and "foo" are different */
+ if( z[i+1]=='.' && winIsDirSep(z[i+2]) ){
+ ++i;
+ continue;
+ }
+#endif
+ if( !z[i+1] || (winIsDirSep(z[i+1]) && (i!=0)) ){
+ continue;
+ }
+ z[j++] = osGetenv?'/':'\\';
+ }else{
+ z[j++] = z[i];
+ }
+ }
+ while(j<i) z[j++] = '\0';
+}
+
+#if !SQLITE_OS_UNIX
+
+#define SQLITE_MAX_SYMLINKS 100
+
+static int mkFullPathname(
+ const char *zPath, /* Input path */
+ char *zOut, /* Output buffer */
+ int nOut /* Allocated size of buffer zOut */
+){
+ int nPath = sqlite3Strlen30(zPath);
+ int iOff = 0;
+ if( zPath[0]!='/' ){
+ if( getcwd(zOut, nOut-2)==0 ){
+ return winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)osErrno, "getcwd", zPath);
+ }
+ iOff = sqlite3Strlen30(zOut);
+ zOut[iOff++] = '/';
+ }
+ if( (iOff+nPath+1)>nOut ){
+ /* SQLite assumes that xFullPathname() nul-terminates the output buffer
+ ** even if it returns an error. */
+ zOut[iOff] = '\0';
+ return SQLITE_CANTOPEN_BKPT;
+ }
+ sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath);
+ return SQLITE_OK;
+}
+#endif
/*
** Turn a relative pathname into a full pathname. Write the full
@@ -46323,8 +46806,9 @@ static int winFullPathname(
int nFull, /* Size of output buffer in bytes */
char *zFull /* Output buffer */
){
-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
- DWORD nByte;
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
+ WCHAR buf[MAX_PATH];
+ int nByte;
void *zConverted;
char *zOut;
#endif
@@ -46336,7 +46820,85 @@ static int winFullPathname(
zRelative++;
}
-#if defined(__CYGWIN__)
+ SimulateIOError( return SQLITE_ERROR );
+
+ if( getcwd ){
+ zFull[nFull-1] = '\0';
+ if( !winIsDriveLetterAndColon(zRelative) || !winIsDirSep(zRelative[2]) ){
+ int rc = SQLITE_OK;
+ int nByte;
+ int nLink = 1; /* Number of symbolic links followed so far */
+ const char *zIn = zRelative; /* Input path for each iteration of loop */
+ char *zDel = 0;
+ struct cygwinstat buf;
+
+#ifdef __CYGWIN__ /* Make sure that "struct cygwinstat" corresponds with real struct */
+ assert( sizeof(buf)==sizeof(struct stat));
+#endif
+ UNUSED_PARAMETER(pVfs);
+
+ do {
+ /* Call lstat() on path zIn. Set bLink to true if the path is a symbolic
+ ** link, or false otherwise. */
+ int bLink = 0;
+ if( lstat && readlink ) {
+ if( lstat(zIn, &buf)!=0 ){
+ int myErrno = osErrno;
+ if( myErrno!=ENOENT ){
+ rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)myErrno, "lstat", zIn);
+ }
+ }else{
+ bLink = ((buf.st_mode & 0170000) == 0120000);
+ }
+
+ if( bLink ){
+ if( zDel==0 ){
+ zDel = sqlite3Malloc(nFull);
+ if( zDel==0 ) rc = SQLITE_NOMEM;
+ }else if( ++nLink>SQLITE_MAX_SYMLINKS ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ }
+
+ if( rc==SQLITE_OK ){
+ nByte = readlink(zIn, zDel, nFull-1);
+ if( nByte<0 ){
+ rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)osErrno, "readlink", zIn);
+ }else{
+ if( zDel[0]!='/' ){
+ int n;
+ for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--);
+ if( nByte+n+1>nFull ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ }else{
+ memmove(&zDel[n], zDel, nByte+1);
+ memcpy(zDel, zIn, n);
+ nByte += n;
+ }
+ }
+ zDel[nByte] = '\0';
+ }
+ }
+
+ zIn = zDel;
+ }
+ }
+
+ assert( rc!=SQLITE_OK || zIn!=zFull || zIn[0]=='/' );
+ if( rc==SQLITE_OK && zIn!=zFull ){
+ rc = mkFullPathname(zIn, zFull, nFull);
+ }
+ if( bLink==0 ) break;
+ zIn = zFull;
+ }while( rc==SQLITE_OK );
+
+ sqlite3_free(zDel);
+ winSimplifyName(zFull);
+ return rc;
+ }
+ }
+#if 0 /* This doesn't work correctly at all! See:
+ <http://sqlite.1065341.n5.nabble.com/Wrong-filename-handling-in-sqlite3-load-extension-for-Cygwin-td74049.html>
+*/
SimulateIOError( return SQLITE_ERROR );
UNUSED_PARAMETER(nFull);
assert( nFull>=pVfs->mxPathname );
@@ -46347,7 +46909,7 @@ static int winFullPathname(
** for converting the relative path name to an absolute
** one by prepending the data directory and a slash.
*/
- char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
+ char *zOut = sqlite3Malloc( pVfs->mxPathname+1 );
if( !zOut ){
return SQLITE_IOERR_NOMEM_BKPT;
}
@@ -46369,7 +46931,7 @@ static int winFullPathname(
sqlite3_free(zOut);
}
}else{
- char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
+ char *zOut = sqlite3Malloc( pVfs->mxPathname+1 );
if( !zOut ){
return SQLITE_IOERR_NOMEM_BKPT;
}
@@ -46394,7 +46956,6 @@ static int winFullPathname(
#endif
#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__)
- SimulateIOError( return SQLITE_ERROR );
/* WinCE has no concept of a relative pathname, or so I am told. */
/* WinRT has no way to convert a relative path to an absolute one. */
if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){
@@ -46412,13 +46973,8 @@ static int winFullPathname(
return SQLITE_OK;
#endif
-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
- /* 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. This function could fail if, for example, the
- ** current working directory has been unlinked.
- */
- SimulateIOError( return SQLITE_ERROR );
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
+#if defined(_WIN32)
if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){
/*
** NOTE: We are dealing with a relative path name and the data
@@ -46430,7 +46986,8 @@ static int winFullPathname(
sqlite3_data_directory, winGetDirSep(), zRelative);
return SQLITE_OK;
}
- zConverted = winConvertFromUtf8Filename(zRelative);
+#endif
+ zConverted = winConvertFromUtf8Filename(zRelative, buf);
if( zConverted==0 ){
return SQLITE_IOERR_NOMEM_BKPT;
}
@@ -46438,24 +46995,32 @@ static int winFullPathname(
LPWSTR zTemp;
nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0);
if( nByte==0 ){
- sqlite3_free(zConverted);
+ if( zConverted != buf ){
+ sqlite3_free(zConverted);
+ }
return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(),
"winFullPathname1", zRelative);
}
nByte += 3;
- zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
+ zTemp = sqlite3Malloc( nByte*sizeof(zTemp[0]) );
if( zTemp==0 ){
- sqlite3_free(zConverted);
+ if( zConverted != buf ){
+ sqlite3_free(zConverted);
+ }
return SQLITE_IOERR_NOMEM_BKPT;
}
nByte = osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0);
if( nByte==0 ){
- sqlite3_free(zConverted);
+ if( zConverted != buf ){
+ sqlite3_free(zConverted);
+ }
sqlite3_free(zTemp);
return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(),
"winFullPathname2", zRelative);
}
- sqlite3_free(zConverted);
+ if( zConverted != buf ){
+ sqlite3_free(zConverted);
+ }
zOut = winUnicodeToUtf8(zTemp);
sqlite3_free(zTemp);
}
@@ -46487,7 +47052,22 @@ static int winFullPathname(
}
#endif
if( zOut ){
- sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut);
+ if( memcmp(zOut, "\\\\?\\", 4) ){
+ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut);
+ }else if( memcmp(zOut+4, "UNC\\", 4) ){
+ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut+4);
+ }else{
+ char *p = zOut+6;
+ *p = '\\';
+ if( getcwd ){
+ /* On Cygwin, UNC paths use forward slashes */
+ while( *p ){
+ if( *p=='\\' ) *p = '/';
+ ++p;
+ }
+ }
+ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut+6);
+ }
sqlite3_free(zOut);
return SQLITE_OK;
}else{
@@ -46503,9 +47083,11 @@ static int winFullPathname(
*/
static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
HANDLE h;
-#if defined(__CYGWIN__)
+#if 0 /* This doesn't work correctly at all! See:
+ <http://sqlite.1065341.n5.nabble.com/Wrong-filename-handling-in-sqlite3-load-extension-for-Cygwin-td74049.html>
+*/
int nFull = pVfs->mxPathname+1;
- char *zFull = sqlite3MallocZero( nFull );
+ char *zFull = sqlite3Malloc( nFull );
void *zConverted = 0;
if( zFull==0 ){
OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
@@ -46519,7 +47101,8 @@ static void *winDlOpen(sqlite3_vfs *pVfs
zConverted = winConvertFromUtf8Filename(zFull);
sqlite3_free(zFull);
#else
- void *zConverted = winConvertFromUtf8Filename(zFilename);
+ WCHAR buf[MAX_PATH];
+ void *zConverted = winConvertFromUtf8Filename(zFilename, buf);
UNUSED_PARAMETER(pVfs);
#endif
if( zConverted==0 ){
@@ -46539,7 +47122,9 @@ static void *winDlOpen(sqlite3_vfs *pVfs
}
#endif
OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)h));
- sqlite3_free(zConverted);
+ if( zConverted!=buf ){
+ sqlite3_free(zConverted);
+ }
return (void*)h;
}
static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
@@ -46629,15 +47214,31 @@ static int winRandomness(sqlite3_vfs *pV
osQueryPerformanceCounter(&i);
xorMemory(&e, (unsigned char*)&i, sizeof(LARGE_INTEGER));
}
-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
{
UUID id;
- memset(&id, 0, sizeof(UUID));
- osUuidCreate(&id);
- xorMemory(&e, (unsigned char*)&id, sizeof(UUID));
- memset(&id, 0, sizeof(UUID));
- osUuidCreateSequential(&id);
- xorMemory(&e, (unsigned char*)&id, sizeof(UUID));
+#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_WIN32_USE_UUID)
+ static HMODULE module = 0;
+ if( !module && module != (HMODULE)-1 ){
+ module = osLoadLibraryW(L"RPCRT4.DLL");
+ if( !module ){
+ module = (HMODULE)-1;
+ }else{
+ aSyscall[77].pCurrent = (SYSCALL) osGetProcAddressA(module, "UuidCreate");
+ aSyscall[78].pCurrent = (SYSCALL) osGetProcAddressA(module, "UuidCreateSequential");
+ }
+ }
+#endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) */
+ if( osUuidCreate ){
+ memset(&id, 0, sizeof(UUID));
+ osUuidCreate(&id);
+ xorMemory(&e, (unsigned char*)&id, sizeof(UUID));
+ }
+ if( osUuidCreateSequential ){
+ memset(&id, 0, sizeof(UUID));
+ osUuidCreateSequential(&id);
+ xorMemory(&e, (unsigned char*)&id, sizeof(UUID));
+ }
}
#endif /* !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID */
return e.nXor>nBuf ? nBuf : e.nXor;
@@ -46763,6 +47364,10 @@ static int winGetLastError(sqlite3_vfs *
return e;
}
+#if SQLITE_OS_UNIX && !defined(SQLITE_AMALGAMATION)
+SQLITE_API int sqlite3_os_unix_init(void);
+#endif
+
/*
** Initialize and deinitialize the operating system interface.
*/
@@ -46841,6 +47446,30 @@ SQLITE_API int sqlite3_os_init(void){
winGetSystemCall, /* xGetSystemCall */
winNextSystemCall, /* xNextSystemCall */
};
+ static sqlite3_vfs winNolockVfs1 = {
+ 3, /* iVersion */
+ sizeof(winFile), /* szOsFile */
+ SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */
+ 0, /* pNext */
+ "none", /* zName */
+ &winNolockAppData, /* pAppData */
+ winOpen, /* xOpen */
+ winDelete, /* xDelete */
+ winAccess, /* xAccess */
+ winFullPathname, /* xFullPathname */
+ winDlOpen, /* xDlOpen */
+ winDlError, /* xDlError */
+ winDlSym, /* xDlSym */
+ winDlClose, /* xDlClose */
+ winRandomness, /* xRandomness */
+ winSleep, /* xSleep */
+ winCurrentTime, /* xCurrentTime */
+ winGetLastError, /* xGetLastError */
+ winCurrentTimeInt64, /* xCurrentTimeInt64 */
+ winSetSystemCall, /* xSetSystemCall */
+ winGetSystemCall, /* xGetSystemCall */
+ winNextSystemCall, /* xNextSystemCall */
+ };
#if defined(SQLITE_WIN32_HAS_WIDE)
static sqlite3_vfs winLongPathNolockVfs = {
3, /* iVersion */
@@ -46866,11 +47495,15 @@ SQLITE_API int sqlite3_os_init(void){
winGetSystemCall, /* xGetSystemCall */
winNextSystemCall, /* xNextSystemCall */
};
+#ifdef _WIN32
+ int i;
+ HMODULE module;
+#endif
#endif
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
- assert( ArraySize(aSyscall)==80 );
+ assert( ArraySize(aSyscall)==88 );
/* get memory map allocation granularity */
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
@@ -46882,13 +47515,52 @@ SQLITE_API int sqlite3_os_init(void){
assert( winSysInfo.dwAllocationGranularity>0 );
assert( winSysInfo.dwPageSize>0 );
+#ifdef _WIN32
+ module = osGetModuleHandleW(L"CYGWIN1.DLL");
+ if( !module ){
+ module = osGetModuleHandleW(L"MSYS-2.0.DLL");
+ }
+ if( !module ){
+ module = osGetModuleHandleW(L"MSYS-1.0.DLL");
+ }
+ if( module ){
+ for( i=81; i<ArraySize(aSyscall); ++i ){
+ aSyscall[i].pCurrent = (SYSCALL) osGetProcAddressA(module,
+ aSyscall[i].zName);
+ }
+ }
+#endif
+
+#if SQLITE_OS_UNIX
+ sqlite3_os_unix_init();
+#endif
+
sqlite3_vfs_register(&winVfs, 1);
+#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
+ if( cygwin_conv_path ){
+ WCHAR buf[MAX_PATH];
+ cygwin_conv_path(CCP_POSIX_TO_WIN_W, "/usr/bin",
+ buf, MAX_PATH*sizeof(WCHAR));
+ osSetDllDirectoryW(buf);
+#ifdef _WIN32
+ }else if( cygwin_conv_to_full_win32_path ){
+ WCHAR buf[MAX_PATH];
+ char *buf1 = (char *)buf;
+ int i = MAX_PATH;
+ cygwin_conv_to_full_win32_path("/usr/bin", buf1);
+ while(--i>=0) buf[i] = buf1[i];
+ osSetDllDirectoryW(buf);
+#endif
+ }
+#endif
+
#if defined(SQLITE_WIN32_HAS_WIDE)
sqlite3_vfs_register(&winLongPathVfs, 0);
#endif
sqlite3_vfs_register(&winNolockVfs, 0);
+ sqlite3_vfs_register(&winNolockVfs1, 0);
#if defined(SQLITE_WIN32_HAS_WIDE)
sqlite3_vfs_register(&winLongPathNolockVfs, 0);
@@ -46902,6 +47574,19 @@ SQLITE_API int sqlite3_os_init(void){
}
SQLITE_API int sqlite3_os_end(void){
+#ifdef _WIN32
+ int i;
+#endif
+#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
+ if( cygwin_conv_path || cygwin_conv_to_full_win32_path){
+ osSetDllDirectoryW(0);
+ }
+#endif
+#ifdef _WIN32
+ for( i=81; i<ArraySize(aSyscall); ++i ){
+ aSyscall[i].pCurrent = 0;
+ }
+#endif
#if SQLITE_OS_WINRT
if( sleepObj!=NULL ){
osCloseHandle(sleepObj);
@@ -47893,7 +48578,7 @@ SQLITE_PRIVATE int sqlite3BitvecBuiltinT
** bits to act as the reference */
pBitvec = sqlite3BitvecCreate( sz );
pV = sqlite3MallocZero( (sz+7)/8 + 1 );
- pTmpSpace = sqlite3_malloc64(BITVEC_SZ);
+ pTmpSpace = sqlite3Malloc(BITVEC_SZ);
if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end;
/* NULL pBitvec tests */
@@ -49017,8 +49702,8 @@ struct PCache1 {
*/
PGroup *pGroup; /* PGroup this cache belongs to */
unsigned int *pnPurgeable; /* Pointer to pGroup->nPurgeable */
- int szPage; /* Size of database content section */
- int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */
+ size_t szPage; /* Size of database content section */
+ size_t szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */
int szAlloc; /* Total size of one pcache line */
int bPurgeable; /* True if cache is purgeable */
unsigned int nMin; /* Minimum number of pages reserved */
@@ -49060,7 +49745,7 @@ static SQLITE_WSD struct PCacheGlobal {
int isInit; /* True if initialized */
int separateCache; /* Use a new PGroup for each PCache */
int nInitPage; /* Initial bulk allocation size */
- int szSlot; /* Size of each free slot */
+ size_t szSlot; /* Size of each free slot */
int nSlot; /* The number of pcache slots */
int nReserve; /* Try to keep nFreeSlot above this */
void *pStart, *pEnd; /* Bounds of global page cache memory */
@@ -49108,7 +49793,7 @@ static SQLITE_WSD struct PCacheGlobal {
** This routine is called from sqlite3_initialize() and so it is guaranteed
** to be serialized already. There is no need for further mutexing.
*/
-SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
+SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, size_t sz, int n){
if( pcache1.isInit ){
PgFreeslot *p;
if( pBuf==0 ) sz = n = 0;
@@ -49177,7 +49862,7 @@ static int pcache1InitBulk(PCache1 *pCac
** Multiple threads can run this routine at the same time. Global variables
** in pcache1 need to be protected via mutex.
*/
-static void *pcache1Alloc(int nByte){
+static void *pcache1Alloc(size_t nByte){
void *p = 0;
assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
if( nByte<=pcache1.szSlot ){
@@ -49200,7 +49885,7 @@ static void *pcache1Alloc(int nByte){
p = sqlite3Malloc(nByte);
#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
if( p ){
- int sz = sqlite3MallocSize(p);
+ size_t sz = sqlite3MallocSize(p);
sqlite3_mutex_enter(pcache1.mutex);
sqlite3StatusHighwater(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
@@ -49248,11 +49933,11 @@ static void pcache1Free(void *p){
/*
** Return the size of a pcache allocation
*/
-static int pcache1MemSize(void *p){
+static size_t pcache1MemSize(void *p){
if( p>=pcache1.pStart && p<pcache1.pEnd ){
return pcache1.szSlot;
}else{
- int iSize;
+ size_t iSize;
assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
iSize = sqlite3MallocSize(p);
@@ -49336,7 +50021,7 @@ static void pcache1FreePage(PgHdr1 *p){
** using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no such buffer
** exists, this function falls back to sqlite3Malloc().
*/
-SQLITE_PRIVATE void *sqlite3PageMalloc(int sz){
+SQLITE_PRIVATE void *sqlite3PageMalloc(size_t sz){
assert( sz<=65536+8 ); /* These allocations are never very large */
return pcache1Alloc(sz);
}
@@ -50072,14 +50757,14 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3Pca
** been released, the function returns. The return value is the total number
** of bytes of memory released.
*/
-SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
- int nFree = 0;
+SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(size_t nReq){
+ size_t nFree = 0;
assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
assert( sqlite3_mutex_notheld(pcache1.mutex) );
if( sqlite3GlobalConfig.pPage==0 ){
PgHdr1 *p;
pcache1EnterMutex(&pcache1.grp);
- while( (nReq<0 || nFree<nReq)
+ while( (nFree<nReq)
&& (p=pcache1.grp.lru.pLruPrev)!=0
&& p->isAnchor==0
){
@@ -59095,9 +59780,9 @@ static SQLITE_NOINLINE int walIndexPageR
/* Enlarge the pWal->apWiData[] array if required */
if( pWal->nWiData<=iPage ){
- sqlite3_int64 nByte = sizeof(u32*)*(iPage+1);
+ size_t nByte = sizeof(u32*)*(iPage+1);
volatile u32 **apNew;
- apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte);
+ apNew = (volatile u32 **)sqlite3Realloc((void *)pWal->apWiData, nByte);
if( !apNew ){
*ppPage = 0;
return SQLITE_NOMEM_BKPT;
@@ -59748,7 +60433,7 @@ static int walIndexRecover(Wal *pWal){
/* Malloc a buffer to read frames into. */
szFrame = szPage + WAL_FRAME_HDRSIZE;
- aFrame = (u8 *)sqlite3_malloc64(szFrame);
+ aFrame = (u8 *)sqlite3Malloc(szFrame);
if( !aFrame ){
rc = SQLITE_NOMEM_BKPT;
goto recovery_error;
@@ -60153,7 +60838,7 @@ static int walIteratorInit(Wal *pWal, u3
nByte = sizeof(WalIterator)
+ (nSegment-1)*sizeof(struct WalSegment)
+ iLast*sizeof(ht_slot);
- p = (WalIterator *)sqlite3_malloc64(nByte);
+ p = (WalIterator *)sqlite3Malloc(nByte);
if( !p ){
return SQLITE_NOMEM_BKPT;
}
@@ -60163,7 +60848,7 @@ static int walIteratorInit(Wal *pWal, u3
/* Allocate temporary space used by the merge-sort routine. This block
** of memory will be freed before this function returns.
*/
- aTmp = (ht_slot *)sqlite3_malloc64(
+ aTmp = (ht_slot *)sqlite3Malloc(
sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
);
if( !aTmp ){
@@ -61786,7 +62471,7 @@ static int walRewriteChecksums(Wal *pWal
u32 iRead; /* Next frame to read from wal file */
i64 iCksumOff;
- aBuf = sqlite3_malloc(szPage + WAL_FRAME_HDRSIZE);
+ aBuf = sqlite3Malloc(szPage + WAL_FRAME_HDRSIZE);
if( aBuf==0 ) return SQLITE_NOMEM_BKPT;
/* Find the checksum values to use as input for the recalculating the
@@ -62274,7 +62959,7 @@ SQLITE_PRIVATE int sqlite3WalSnapshotGet
*ppSnapshot = 0;
return SQLITE_ERROR;
}
- pRet = (WalIndexHdr*)sqlite3_malloc(sizeof(WalIndexHdr));
+ pRet = (WalIndexHdr*)sqlite3Malloc(sizeof(WalIndexHdr));
if( pRet==0 ){
rc = SQLITE_NOMEM_BKPT;
}else{
@@ -68193,7 +68878,7 @@ static int accessPayload(
if( (pCur->curFlags & BTCF_ValidOvfl)==0 ){
int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
if( pCur->aOverflow==0
- || nOvfl*(int)sizeof(Pgno) > sqlite3MallocSize(pCur->aOverflow)
+ || nOvfl*sizeof(Pgno) > sqlite3MallocSize(pCur->aOverflow)
){
Pgno *aNew = (Pgno*)sqlite3Realloc(
pCur->aOverflow, nOvfl*2*sizeof(Pgno)
@@ -72567,7 +73252,7 @@ static int clearDatabasePage(
BtShared *pBt, /* The BTree that contains the table */
Pgno pgno, /* Page number to clear */
int freePageFlag, /* Deallocate page if true */
- int *pnChange /* Add number of Cells freed to this counter */
+ u64 *pnChange /* Add number of Cells freed to this counter */
){
MemPage *pPage;
int rc;
@@ -72630,7 +73315,7 @@ cleardatabasepage_out:
** integer value pointed to by pnChange is incremented by the number of
** entries in the table.
*/
-SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
+SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, u64 *pnChange){
int rc;
BtShared *pBt = p->pBt;
sqlite3BtreeEnter(p);
@@ -74879,7 +75564,7 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEnco
** blob if bPreserve is true. If bPreserve is false, any prior content
** in pMem->z is discarded.
*/
-SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
+SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, size_t n, int bPreserve){
assert( sqlite3VdbeCheckMemInvariants(pMem) );
assert( !sqlite3VdbeMemIsRowSet(pMem) );
testcase( pMem->db==0 );
@@ -74940,7 +75625,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlit
** Return SQLITE_OK on success or an error code (probably SQLITE_NOMEM)
** if unable to complete the resizing.
*/
-SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
+SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, size_t szNew){
assert( CORRUPT_DB || szNew>0 );
assert( (pMem->flags & MEM_Dyn)==0 || pMem->szMalloc==0 );
if( pMem->szMalloc<szNew ){
@@ -75369,7 +76054,7 @@ SQLITE_PRIVATE int sqlite3RealSameAsInt(
double r2 = (double)i;
return r1==0.0
|| (memcmp(&r1, &r2, sizeof(r1))==0
- && i >= -2251799813685248LL && i < 2251799813685248LL);
+ && (i < 0 ? -i : i) >> 53 == 0);
}
/*
@@ -75489,11 +76174,11 @@ SQLITE_PRIVATE void sqlite3ValueSetNull(
** Delete any previous value and set the value to be a BLOB of length
** n containing all zeros.
*/
-SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){
+SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem *pMem, size_t n){
sqlite3VdbeMemRelease(pMem);
pMem->flags = MEM_Blob|MEM_Zero;
pMem->n = 0;
- if( n<0 ) n = 0;
+ if( (int)n<0 ) n = 0;
pMem->u.nZero = n;
pMem->enc = SQLITE_UTF8;
pMem->z = 0;
@@ -75722,7 +76407,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemMove(M
SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
Mem *pMem, /* Memory cell to set to string value */
const char *z, /* String pointer */
- int n, /* Bytes in string, or negative */
+ size_t n, /* Bytes in string, or negative */
u8 enc, /* Encoding of z. 0 for BLOBs */
void (*xDel)(void*) /* Destructor function */
){
@@ -76528,10 +77213,10 @@ SQLITE_PRIVATE void sqlite3ValueFree(sql
** sqlite3_value object assuming that it uses the encoding "enc".
** The valueBytes() routine is a helper function.
*/
-static SQLITE_NOINLINE int valueBytes(sqlite3_value *pVal, u8 enc){
+static SQLITE_NOINLINE size_t valueBytes(sqlite3_value *pVal, u8 enc){
return valueToText(pVal, enc)!=0 ? pVal->n : 0;
}
-SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
+SQLITE_PRIVATE size_t sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
Mem *p = (Mem*)pVal;
assert( (p->flags & MEM_Null)==0 || (p->flags & (MEM_Str|MEM_Blob))==0 );
if( (p->flags & MEM_Str)!=0 && pVal->enc==enc ){
@@ -76721,7 +77406,7 @@ static int growOpArray(Vdbe *v, int nOp)
return SQLITE_NOMEM;
}
- assert( nOp<=(1024/sizeof(Op)) );
+ assert( (unsigned)nOp<=(1024/sizeof(Op)) );
assert( nNew>=(v->nOpAlloc+nOp) );
pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op));
if( pNew ){
@@ -76784,7 +77469,7 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdb
pOp->p3 = p3;
pOp->p4.p = 0;
pOp->p4type = P4_NOTUSED;
-#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+#if 1
pOp->zComment = 0;
#endif
#ifdef SQLITE_DEBUG
@@ -77192,7 +77877,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayA
int opcode = pOp->opcode;
if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
|| opcode==OP_VDestroy
- || (opcode==OP_Function0 && pOp->p4.pFunc->funcFlags&SQLITE_FUNC_INTERNAL)
+ || (opcode==OP_ParseSchema && pOp->p4.z==0)
|| ((opcode==OP_Halt || opcode==OP_HaltIfNull)
&& ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort))
){
@@ -77479,7 +78164,7 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpL
pOut->p4type = P4_NOTUSED;
pOut->p4.p = 0;
pOut->p5 = 0;
-#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+#if 1
pOut->zComment = 0;
#endif
#ifdef SQLITE_VDBE_COVERAGE
@@ -77632,7 +78317,7 @@ static void vdbeFreeOpArray(sqlite3 *db,
Op *pOp;
for(pOp=&aOp[nOp-1]; pOp>=aOp; pOp--){
if( pOp->p4type <= P4_FREE_IF_LE ) freeP4(db, pOp->p4type, pOp->p4.p);
-#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+#if 1
sqlite3DbFree(db, pOp->zComment);
#endif
}
@@ -77785,7 +78470,7 @@ SQLITE_PRIVATE void sqlite3VdbeSetP4KeyI
if( pKeyInfo ) sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO);
}
-#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+#if 1
/*
** Change the comment on the most recently coded instruction. Or
** insert a No-op and add the comment to that new instruction. This
@@ -77858,7 +78543,7 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(
}
}
-#if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS)
+#if 1
/*
** Return an integer value for one of the parameters to the opcode pOp
** determined by character c.
@@ -78036,8 +78721,8 @@ static void displayP4Expr(StrAccum *p, E
** Compute a string that describes the P4 parameter for an opcode.
** Use zTemp for any required temporary buffer space.
*/
-static char *displayP4(Op *pOp, char *zTemp, int nTemp){
- char *zP4 = zTemp;
+static const char *displayP4(Op *pOp, char *zTemp, int nTemp){
+ const char *zP4 = zTemp;
StrAccum x;
assert( nTemp>=20 );
sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0);
@@ -78241,14 +78926,18 @@ SQLITE_PRIVATE void sqlite3VdbeLeave(Vdb
** Print a single opcode. This routine is used for debugging only.
*/
SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, VdbeOp *pOp){
- char *zP4;
+ const char *zP4;
char zPtr[50];
char zCom[100];
static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-13s %.2X %s\n";
if( pOut==0 ) pOut = stdout;
zP4 = displayP4(pOp, zPtr, sizeof(zPtr));
-#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
- displayComment(pOp, zP4, zCom, sizeof(zCom));
+#if 1
+ if( sqlite3GlobalConfig.bVdbeComments ){
+ displayComment(pOp, zP4, zCom, sizeof(zCom));
+ }else{
+ zCom[0] = 0;
+ }
#else
zCom[0] = 0;
#endif
@@ -78505,7 +79194,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
rc = SQLITE_ERROR;
sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
}else{
- char *zP4;
+ const char *zP4;
if( p->explain==1 ){
pMem->flags = MEM_Int;
pMem->u.i = i; /* Program counter */
@@ -78558,7 +79247,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
pMem->enc = SQLITE_UTF8;
pMem++;
-#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+ if( sqlite3GlobalConfig.bVdbeComments ){
if( sqlite3VdbeMemClearAndResize(pMem, 500) ){
assert( p->db->mallocFailed );
return SQLITE_ERROR;
@@ -78566,9 +79255,9 @@ SQLITE_PRIVATE int sqlite3VdbeList(
pMem->flags = MEM_Str|MEM_Term;
pMem->n = displayComment(pOp, zP4, pMem->z, 500);
pMem->enc = SQLITE_UTF8;
-#else
+ } else {
pMem->flags = MEM_Null; /* Comment */
-#endif
+ }
}
p->nResColumn = 8 - 4*(p->explain-1);
@@ -80050,7 +80739,6 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType
return 7;
}
assert( pMem->db->mallocFailed || flags&(MEM_Str|MEM_Blob) );
- assert( pMem->n>=0 );
n = (u32)pMem->n;
if( flags & MEM_Zero ){
n += pMem->u.nZero;
@@ -80083,7 +80771,7 @@ static const u8 sqlite3SmallTypeSizes[]
/*
** Return the length of the data corresponding to the supplied serial-type.
*/
-SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32 serial_type){
+SQLITE_PRIVATE size_t sqlite3VdbeSerialTypeLen(u32 serial_type){
if( serial_type>=128 ){
return (serial_type-12)/2;
}else{
@@ -80189,7 +80877,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(
/* String or blob */
if( serial_type>=12 ){
assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.nZero:0)
- == (int)sqlite3VdbeSerialTypeLen(serial_type) );
+ == sqlite3VdbeSerialTypeLen(serial_type) );
len = pMem->n;
if( len>0 ) memcpy(buf, pMem->z, len);
return len;
@@ -80544,7 +81232,7 @@ debugCompareEnd:
** incorrectly.
*/
static void vdbeAssertFieldCountWithinLimits(
- int nKey, const void *pKey, /* The record to verify */
+ size_t nKey, const void *pKey,/* The record to verify */
const KeyInfo *pKeyInfo /* Compare size with this KeyInfo */
){
int nField = 0;
@@ -80555,8 +81243,7 @@ static void vdbeAssertFieldCountWithinLi
if( CORRUPT_DB ) return;
idx = getVarint32(aKey, szHdr);
- assert( nKey>=0 );
- assert( szHdr<=(u32)nKey );
+ assert( szHdr<=nKey );
while( idx<szHdr ){
idx += getVarint32(aKey+idx, notUsed);
nField++;
@@ -80841,7 +81528,7 @@ static i64 vdbeRecordDecodeInt(u32 seria
** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db).
*/
SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
- int nKey1, const void *pKey1, /* Left key */
+ size_t nKey1, const void *pKey1,/* Left key */
UnpackedRecord *pPKey2, /* Right key */
int bSkip /* If true, skip the first field */
){
@@ -80974,7 +81661,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordComp
if( serial_type<12 || (serial_type & 0x01) ){
rc = -1;
}else{
- int nStr = (serial_type - 12) / 2;
+ size_t nStr = (serial_type - 12) / 2;
testcase( (d1+nStr)==(unsigned)nKey1 );
testcase( (d1+nStr+1)==(unsigned)nKey1 );
if( (d1+nStr) > (unsigned)nKey1 ){
@@ -81038,7 +81725,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordComp
return pPKey2->default_rc;
}
SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
- int nKey1, const void *pKey1, /* Left key */
+ size_t nKey1, const void *pKey1,/* Left key */
UnpackedRecord *pPKey2 /* Right key */
){
return sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 0);
@@ -81055,7 +81742,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordComp
** on schemas where the maximum valid header size is 63 bytes or less.
*/
static int vdbeRecordCompareInt(
- int nKey1, const void *pKey1, /* Left key */
+ size_t nKey1, const void *pKey1, /* Left key */
UnpackedRecord *pPKey2 /* Right key */
){
const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F];
@@ -81149,7 +81836,7 @@ static int vdbeRecordCompareInt(
** at the start of (pKey1/nKey1) fits in a single byte.
*/
static int vdbeRecordCompareString(
- int nKey1, const void *pKey1, /* Left key */
+ size_t nKey1, const void *pKey1, /* Left key */
UnpackedRecord *pPKey2 /* Right key */
){
const u8 *aKey1 = (const u8*)pKey1;
@@ -81164,8 +81851,8 @@ static int vdbeRecordCompareString(
}else if( !(serial_type & 0x01) ){
res = pPKey2->r2; /* (pKey1/nKey1) is a blob */
}else{
- int nCmp;
- int nStr;
+ size_t nCmp;
+ size_t nStr;
int szHdr = aKey1[0];
nStr = (serial_type-12) / 2;
@@ -81290,7 +81977,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(s
testcase( szHdr==m.n );
testcase( szHdr>0x7fffffff );
assert( m.n>=0 );
- if( unlikely(szHdr<3 || szHdr>(unsigned)m.n) ){
+ if( unlikely(szHdr<3 || szHdr>m.n) ){
goto idx_rowid_corruption;
}
@@ -81354,12 +82041,13 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyComp
pCur = pC->uc.pCursor;
assert( sqlite3BtreeCursorIsValid(pCur) );
nCellKey = sqlite3BtreePayloadSize(pCur);
- /* nCellKey will always be between 0 and 0xffffffff because of the way
+ /* nCellKey will always be between 0 and 0x7fffffff because of the way
** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */
- if( nCellKey<=0 || nCellKey>0x7fffffff ){
+ if( (nCellKey & ~(i64)0x7fffffff)!=0 ){
*res = 0;
return SQLITE_CORRUPT_BKPT;
}
+ assert( nCellKey>=0 && nCellKey<=0x7fffffff );
sqlite3VdbeMemInit(&m, db, 0);
rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m);
if( rc ){
@@ -81374,7 +82062,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyComp
** This routine sets the value to be returned by subsequent calls to
** sqlite3_changes() on the database handle 'db'.
*/
-SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *db, int nChange){
+SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *db, u64 nChange){
assert( sqlite3_mutex_held(db->mutex) );
db->nChange = nChange;
db->nTotalChange += nChange;
@@ -81781,10 +82469,10 @@ SQLITE_API const void *sqlite3_value_blo
return sqlite3_value_text(pVal);
}
}
-SQLITE_API int sqlite3_value_bytes(sqlite3_value *pVal){
+SQLITE_API unsigned int sqlite3_value_bytes(sqlite3_value *pVal){
return sqlite3ValueBytes(pVal, SQLITE_UTF8);
}
-SQLITE_API int sqlite3_value_bytes16(sqlite3_value *pVal){
+SQLITE_API unsigned int sqlite3_value_bytes16(sqlite3_value *pVal){
return sqlite3ValueBytes(pVal, SQLITE_UTF16NATIVE);
}
SQLITE_API double sqlite3_value_double(sqlite3_value *pVal){
@@ -81931,7 +82619,7 @@ SQLITE_API int sqlite3_value_frombind(sq
SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){
sqlite3_value *pNew;
if( pOrig==0 ) return 0;
- pNew = sqlite3_malloc( sizeof(*pNew) );
+ pNew = sqlite3Malloc( sizeof(*pNew) );
if( pNew==0 ) return 0;
memset(pNew, 0, sizeof(*pNew));
memcpy(pNew, pOrig, MEMCELLSIZE);
@@ -81970,7 +82658,7 @@ SQLITE_API void sqlite3_value_free(sqlit
static void setResultStrOrError(
sqlite3_context *pCtx, /* Function context */
const char *z, /* String pointer */
- int n, /* Bytes in string, or negative */
+ size_t n, /* Bytes in string, or negative */
u8 enc, /* Encoding of z. 0 for BLOBs */
void (*xDel)(void*) /* Destructor function */
){
@@ -81994,15 +82682,15 @@ static int invokeValueDestructor(
if( pCtx ) sqlite3_result_error_toobig(pCtx);
return SQLITE_TOOBIG;
}
+#undef sqlite3_result_blob
SQLITE_API void sqlite3_result_blob(
sqlite3_context *pCtx,
const void *z,
- int n,
+ unsigned int n,
void (*xDel)(void *)
){
- assert( n>=0 );
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
- setResultStrOrError(pCtx, z, n, 0, xDel);
+ setResultStrOrError(pCtx, z, (size_t)n, 0, xDel);
}
SQLITE_API void sqlite3_result_blob64(
sqlite3_context *pCtx,
@@ -82012,11 +82700,12 @@ SQLITE_API void sqlite3_result_blob64(
){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
assert( xDel!=SQLITE_DYNAMIC );
- if( n>0x7fffffff ){
- (void)invokeValueDestructor(z, xDel, pCtx);
- }else{
- setResultStrOrError(pCtx, z, (int)n, 0, xDel);
+
+ if( n>SQLITE_MAX_LENGTH ){
+ (void)invokeValueDestructor(z, xDel, 0);
+ return;
}
+ setResultStrOrError(pCtx, z, (size_t)n, 0, xDel);
}
SQLITE_API void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
@@ -82064,6 +82753,7 @@ SQLITE_API void sqlite3_result_subtype(s
pOut->eSubtype = eSubtype & 0xff;
pOut->flags |= MEM_Subtype;
}
+#undef sqlite3_result_text
SQLITE_API void sqlite3_result_text(
sqlite3_context *pCtx,
const char *z,
@@ -82071,7 +82761,7 @@ SQLITE_API void sqlite3_result_text(
void (*xDel)(void *)
){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
- setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel);
+ setResultStrOrError(pCtx, z, (size_t)n, SQLITE_UTF8, xDel);
}
SQLITE_API void sqlite3_result_text64(
sqlite3_context *pCtx,
@@ -82082,14 +82772,20 @@ SQLITE_API void sqlite3_result_text64(
){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
assert( xDel!=SQLITE_DYNAMIC );
- if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
if( n>0x7fffffff ){
- (void)invokeValueDestructor(z, xDel, pCtx);
- }else{
- setResultStrOrError(pCtx, z, (int)n, enc, xDel);
+ if( (sqlite3_int64)n >= 0 ){
+ (void)invokeValueDestructor(z, xDel, pCtx);
+ return;
+ }
+ n = (sqlite3_uint64)-1;
}
+ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
+ setResultStrOrError(pCtx, z, (size_t)n, enc, xDel);
}
#ifndef SQLITE_OMIT_UTF16
+#undef sqlite3_result_text16
+#undef sqlite3_result_text16be
+#undef sqlite3_result_text16le
SQLITE_API void sqlite3_result_text16(
sqlite3_context *pCtx,
const void *z,
@@ -82097,7 +82793,7 @@ SQLITE_API void sqlite3_result_text16(
void (*xDel)(void *)
){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
- setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel);
+ setResultStrOrError(pCtx, z, (size_t)n, SQLITE_UTF16NATIVE, xDel);
}
SQLITE_API void sqlite3_result_text16be(
sqlite3_context *pCtx,
@@ -82106,7 +82802,7 @@ SQLITE_API void sqlite3_result_text16be(
void (*xDel)(void *)
){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
- setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel);
+ setResultStrOrError(pCtx, z, (size_t)n, SQLITE_UTF16BE, xDel);
}
SQLITE_API void sqlite3_result_text16le(
sqlite3_context *pCtx,
@@ -82115,16 +82811,17 @@ SQLITE_API void sqlite3_result_text16le(
void (*xDel)(void *)
){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
- setResultStrOrError(pCtx, z, n, SQLITE_UTF16LE, xDel);
+ setResultStrOrError(pCtx, z, (size_t)n, SQLITE_UTF16LE, xDel);
}
#endif /* SQLITE_OMIT_UTF16 */
SQLITE_API void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemCopy(pCtx->pOut, pValue);
}
+#undef sqlite3_result_zeroblob
SQLITE_API void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
- sqlite3VdbeMemSetZeroBlob(pCtx->pOut, n);
+ sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (size_t)n);
}
SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){
Mem *pOut = pCtx->pOut;
@@ -82132,7 +82829,7 @@ SQLITE_API int sqlite3_result_zeroblob64
if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){
return SQLITE_TOOBIG;
}
- sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n);
+ sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (size_t)n);
return SQLITE_OK;
}
SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
@@ -82717,13 +83414,13 @@ SQLITE_API const void *sqlite3_column_bl
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
- int val = sqlite3_value_bytes( columnMem(pStmt,i) );
+SQLITE_API unsigned int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
+ unsigned int val = sqlite3ValueBytes( columnMem(pStmt,i), SQLITE_UTF8 );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
- int val = sqlite3_value_bytes16( columnMem(pStmt,i) );
+SQLITE_API unsigned int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
+ unsigned int val = sqlite3ValueBytes( columnMem(pStmt,i), SQLITE_UTF16NATIVE );
columnMallocFailure(pStmt);
return val;
}
@@ -82974,7 +83671,7 @@ static int bindText(
sqlite3_stmt *pStmt, /* The statement to bind against */
int i, /* Index of the parameter to bind */
const void *zData, /* Pointer to the data to be bound */
- int nData, /* Number of bytes of data to be bound */
+ size_t nData, /* Number of bytes of data to be bound */
void (*xDel)(void*), /* Destructor for the data */
u8 encoding /* Encoding for the data */
){
@@ -83006,11 +83703,12 @@ static int bindText(
/*
** Bind a blob value to an SQL statement variable.
*/
+#undef sqlite3_bind_blob
SQLITE_API int sqlite3_bind_blob(
sqlite3_stmt *pStmt,
int i,
const void *zData,
- int nData,
+ unsigned int nData,
void (*xDel)(void*)
){
#ifdef SQLITE_ENABLE_API_ARMOR
@@ -83026,11 +83724,11 @@ SQLITE_API int sqlite3_bind_blob64(
void (*xDel)(void*)
){
assert( xDel!=SQLITE_DYNAMIC );
- if( nData>0x7fffffff ){
+
+ if( nData>SQLITE_MAX_LENGTH ){
return invokeValueDestructor(zData, xDel, 0);
- }else{
- return bindText(pStmt, i, zData, (int)nData, xDel, 0);
}
+ return bindText(pStmt, i, zData, (size_t)nData, xDel, 0);
}
SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
int rc;
@@ -83082,6 +83780,7 @@ SQLITE_API int sqlite3_bind_pointer(
}
return rc;
}
+#undef sqlite3_bind_text
SQLITE_API int sqlite3_bind_text(
sqlite3_stmt *pStmt,
int i,
@@ -83101,13 +83800,16 @@ SQLITE_API int sqlite3_bind_text64(
){
assert( xDel!=SQLITE_DYNAMIC );
if( nData>0x7fffffff ){
- return invokeValueDestructor(zData, xDel, 0);
- }else{
- if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
- return bindText(pStmt, i, zData, (int)nData, xDel, enc);
+ if( (sqlite3_int64)nData >= 0 ){
+ return invokeValueDestructor(zData, xDel, 0);
+ }
+ nData = (sqlite3_uint64)-1;
}
+ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
+ return bindText(pStmt, i, zData, nData, xDel, enc);
}
#ifndef SQLITE_OMIT_UTF16
+#undef sqlite3_bind_text16
SQLITE_API int sqlite3_bind_text16(
sqlite3_stmt *pStmt,
int i,
@@ -83149,12 +83851,13 @@ SQLITE_API int sqlite3_bind_value(sqlite
}
return rc;
}
+#undef sqlite3_bind_zeroblob
SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
int rc;
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, i);
if( rc==SQLITE_OK ){
- sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
+ sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], (size_t)n);
sqlite3_mutex_leave(p->db->mutex);
}
return rc;
@@ -83166,7 +83869,7 @@ SQLITE_API int sqlite3_bind_zeroblob64(s
if( n>(u64)p->db->aLimit[SQLITE_LIMIT_LENGTH] ){
rc = SQLITE_TOOBIG;
}else{
- assert( (n & 0x7FFFFFFF)==n );
+ assert( n<=SQLITE_MAX_LENGTH );
rc = sqlite3_bind_zeroblob(pStmt, i, n);
}
rc = sqlite3ApiExit(p->db, rc);
@@ -83319,7 +84022,7 @@ SQLITE_API sqlite3_stmt *sqlite3_next_st
*/
SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
Vdbe *pVdbe = (Vdbe*)pStmt;
- u32 v;
+ size_t v;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !pStmt
|| (op!=SQLITE_STMTSTATUS_MEMUSED && (op<0||op>=ArraySize(pVdbe->aCounter)))
@@ -83332,7 +84035,7 @@ SQLITE_API int sqlite3_stmt_status(sqlit
sqlite3 *db = pVdbe->db;
sqlite3_mutex_enter(db->mutex);
v = 0;
- db->pnBytesFreed = (int*)&v;
+ db->pnBytesFreed = &v;
sqlite3VdbeClearObject(db, pVdbe);
sqlite3DbFree(db, pVdbe);
db->pnBytesFreed = 0;
@@ -84335,21 +85038,21 @@ SQLITE_PRIVATE void sqlite3VdbeMemPretty
}
*(zCsr++) = c;
*(zCsr++) = 'x';
- sqlite3_snprintf(100, zCsr, "%d[", pMem->n);
+ sqlite3_snprintf(100, zCsr, "%lld[", (u64)pMem->n);
zCsr += sqlite3Strlen30(zCsr);
- for(i=0; i<25 && i<pMem->n; i++){
+ for(i=0; i<25 && i<(int)pMem->n; i++){
sqlite3_snprintf(100, zCsr, "%02X", ((int)pMem->z[i] & 0xFF));
zCsr += sqlite3Strlen30(zCsr);
}
*zCsr++ = '|';
- for(i=0; i<25 && i<pMem->n; i++){
+ for(i=0; i<25 && (int)i<pMem->n; i++){
char z = pMem->z[i];
if( z<32 || z>126 ) *zCsr++ = '.';
else *zCsr++ = z;
}
*(zCsr++) = ']';
if( f & MEM_Zero ){
- sqlite3_snprintf(100, zCsr,"+%dz",pMem->u.nZero);
+ sqlite3_snprintf(100, zCsr,"+%lldz",(u64)pMem->u.nZero);
zCsr += sqlite3Strlen30(zCsr);
}
*zCsr = '\0';
@@ -84369,10 +85072,10 @@ SQLITE_PRIVATE void sqlite3VdbeMemPretty
zBuf[1] = 's';
}
k = 2;
- sqlite3_snprintf(100, &zBuf[k], "%d", pMem->n);
+ sqlite3_snprintf(100, &zBuf[k], "%lld", (u64)pMem->n);
k += sqlite3Strlen30(&zBuf[k]);
zBuf[k++] = '[';
- for(j=0; j<25 && j<pMem->n; j++){
+ for(j=0; j<25 && j<(int)pMem->n; j++){
u8 c = pMem->z[j];
if( c>=0x20 && c<0x7f ){
zBuf[k++] = c;
@@ -84398,11 +85101,19 @@ static void memTracePrint(Mem *p){
}else if( p->flags & MEM_Null ){
printf(p->flags & MEM_Zero ? " NULL-nochng" : " NULL");
}else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
+#ifdef _WIN32
+ printf(" si:%I64d", p->u.i);
+ }else if( (p->flags & (MEM_Int|MEM_IntReal))==(MEM_Int|MEM_IntReal) ){
+ printf(" ir:%I64d", p->u.i);
+ }else if( p->flags & MEM_Int ){
+ printf(" i:%I64d", p->u.i);
+#else
printf(" si:%lld", p->u.i);
}else if( (p->flags & (MEM_IntReal))!=0 ){
printf(" ir:%lld", p->u.i);
}else if( p->flags & MEM_Int ){
printf(" i:%lld", p->u.i);
+#endif
#ifndef SQLITE_OMIT_FLOATING_POINT
}else if( p->flags & MEM_Real ){
printf(" r:%.17g", p->u.r);
@@ -86478,7 +87189,7 @@ case OP_Column: {
VdbeCursor *pC; /* The VDBE cursor */
BtCursor *pCrsr; /* The BTree cursor */
u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
- int len; /* The length of the serialized data for the column */
+ size_t len; /* The length of the serialized data for the column */
int i; /* Loop counter */
Mem *pDest; /* Where to write the extracted value */
Mem sMem; /* For storing the record being decoded */
@@ -88478,23 +89189,27 @@ case OP_SeekRowid: { /* jump, in3
pIn3 = &aMem[pOp->p3];
testcase( pIn3->flags & MEM_Int );
testcase( pIn3->flags & MEM_IntReal );
+ testcase( pIn3->flags & MEM_Real );
+ testcase( (pIn3->flags & (MEM_Str|MEM_Int))==MEM_Str );
if( (pIn3->flags & (MEM_Int|MEM_IntReal))==0 ){
- /* Make sure pIn3->u.i contains a valid integer representation of
- ** the key value, but do not change the datatype of the register, as
- ** other parts of the perpared statement might be depending on the
- ** current datatype. */
- u16 origFlags = pIn3->flags;
- int isNotInt;
- applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding);
- isNotInt = (pIn3->flags & MEM_Int)==0;
- pIn3->flags = origFlags;
- if( isNotInt ) goto jump_to_p2;
+ /* If pIn3->u.i does not contain an integer, compute iKey as the
+ ** integer value of pIn3. Jump to P2 if pIn3 cannot be converted
+ ** into an integer without loss of information. Take care to avoid
+ ** changing the datatype of pIn3, however, as it is used by other
+ ** parts of the prepared statement. */
+ Mem x = pIn3[0];
+ applyAffinity(&x, SQLITE_AFF_NUMERIC, encoding);
+ if( (x.flags & MEM_Int)==0 ) goto jump_to_p2;
+ iKey = x.u.i;
+ goto notExistsWithKey;
}
/* Fall through into OP_NotExists */
case OP_NotExists: /* jump, in3 */
pIn3 = &aMem[pOp->p3];
assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ iKey = pIn3->u.i;
+notExistsWithKey:
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
#ifdef SQLITE_DEBUG
@@ -88505,7 +89220,6 @@ case OP_NotExists: /* jump, in3
pCrsr = pC->uc.pCursor;
assert( pCrsr!=0 );
res = 0;
- iKey = pIn3->u.i;
rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
assert( rc==SQLITE_OK || res==0 );
pC->movetoTarget = iKey; /* Used by OP_Delete */
@@ -89779,7 +90493,7 @@ case OP_Destroy: { /* out2 */
** See also: Destroy
*/
case OP_Clear: {
- int nChange;
+ u64 nChange;
sqlite3VdbeIncrWriteCounter(p, 0);
nChange = 0;
@@ -91946,7 +92660,7 @@ SQLITE_API int sqlite3_blob_open(
goto blob_open_out;
}
pBlob->pTab = pTab;
- pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName;
+ pBlob->zDb = (char *) db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName;
/* Now search pTab for the exact column. */
for(iCol=0; iCol<pTab->nCol; iCol++) {
@@ -92888,7 +93602,7 @@ static int vdbeSorterMapFile(SortSubtask
int rc = SQLITE_OK;
if( pFile->iEof<=(i64)(pTask->pSorter->db->nMaxSorterMmap) ){
sqlite3_file *pFd = pFile->pFd;
- if( pFd->pMethods->iVersion>=3 ){
+ if( pFd->pMethods->iVersion>=3 && pFd->pMethods->xFetch ){
rc = sqlite3OsFetch(pFd, 0, (int)pFile->iEof, (void**)pp);
testcase( rc!=SQLITE_OK );
}
@@ -93080,10 +93794,10 @@ static int vdbeSorterCompareText(
const void *pKey1, int nKey1, /* Left side of comparison */
const void *pKey2, int nKey2 /* Right side of comparison */
){
- const u8 * const p1 = (const u8 * const)pKey1;
- const u8 * const p2 = (const u8 * const)pKey2;
- const u8 * const v1 = &p1[ p1[0] ]; /* Pointer to value 1 */
- const u8 * const v2 = &p2[ p2[0] ]; /* Pointer to value 2 */
+ const u8 *p1 = (const u8 *)pKey1;
+ const u8 *p2 = (const u8 *)pKey2;
+ const u8 *v1 = &p1[ p1[0] ]; /* Pointer to value 1 */
+ const u8 *v2 = &p2[ p2[0] ]; /* Pointer to value 2 */
int n1;
int n2;
@@ -93670,20 +94384,16 @@ static SorterCompare vdbeSorterGetCompar
*/
static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
int i;
- SorterRecord **aSlot;
SorterRecord *p;
int rc;
+ SorterRecord *aSlot[64];
rc = vdbeSortAllocUnpacked(pTask);
if( rc!=SQLITE_OK ) return rc;
p = pList->pList;
pTask->xCompare = vdbeSorterGetCompare(pTask->pSorter);
-
- aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *));
- if( !aSlot ){
- return SQLITE_NOMEM_BKPT;
- }
+ memset(aSlot, 0, sizeof(aSlot));
while( p ){
SorterRecord *pNext;
@@ -93691,7 +94401,7 @@ static int vdbeSorterSort(SortSubtask *p
if( (u8*)p==pList->aMemory ){
pNext = 0;
}else{
- assert( p->u.iNext<sqlite3MallocSize(pList->aMemory) );
+ assert( (unsigned)p->u.iNext<sqlite3MallocSize(pList->aMemory) );
pNext = (SorterRecord*)&pList->aMemory[p->u.iNext];
}
}else{
@@ -93708,13 +94418,12 @@ static int vdbeSorterSort(SortSubtask *p
}
p = 0;
- for(i=0; i<64; i++){
+ for(i=0; i<ArraySize(aSlot); i++){
if( aSlot[i]==0 ) continue;
p = p ? vdbeSorterMerge(pTask, p, aSlot[i]) : aSlot[i];
}
pList->pList = p;
- sqlite3_free(aSlot);
assert( pTask->pUnpacked->errCode==SQLITE_OK
|| pTask->pUnpacked->errCode==SQLITE_NOMEM
);
@@ -95270,7 +95979,7 @@ static int memjrnlWrite(
if( iChunkOffset==0 ){
/* New chunk is required to extend the file. */
- FileChunk *pNew = sqlite3_malloc(fileChunkSize(p->nChunkSize));
+ FileChunk *pNew = sqlite3Malloc(fileChunkSize(p->nChunkSize));
if( !pNew ){
return SQLITE_IOERR_NOMEM_BKPT;
}
@@ -96561,8 +97270,8 @@ static int resolveExprStep(Walker *pWalk
}
#endif
else if( no_such_func && pParse->db->init.busy==0
-#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
- && pParse->explain==0
+#if 1
+ && (pParse->explain==0 || !sqlite3GlobalConfig.bEnableUnknownSqlFunction)
#endif
){
sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
@@ -101318,8 +102027,8 @@ expr_code_doover:
assert( !ExprHasProperty(pExpr, EP_IntValue) );
zId = pExpr->u.zToken;
pDef = sqlite3FindFunction(db, zId, nFarg, enc, 0);
-#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
- if( pDef==0 && pParse->explain ){
+#if 1
+ if( pDef==0 && pParse->explain && sqlite3GlobalConfig.bEnableUnknownSqlFunction){
pDef = sqlite3FindFunction(db, "unknown", nFarg, enc, 0);
}
#endif
@@ -101359,7 +102068,7 @@ expr_code_doover:
** the SQLite type logic.
*/
if( pDef->funcFlags & SQLITE_FUNC_AFFINITY ){
- const char *azAff[] = { "blob", "text", "numeric", "integer", "real" };
+ const char *const azAff[] = { "blob", "text", "numeric", "integer", "real" };
char aff;
assert( nFarg==1 );
aff = sqlite3ExprAffinity(pFarg->a[0].pExpr);
@@ -103268,7 +103977,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTa
Token *pName /* The new table name. */
){
int iDb; /* Database that contains the table */
- char *zDb; /* Name of database iDb */
+ const char *zDb; /* Name of database iDb */
Table *pTab; /* Table being renamed */
char *zName = 0; /* NULL-terminated version of pName */
sqlite3 *db = pParse->db; /* Database connection */
@@ -103607,6 +104316,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAdd
goto exit_begin_add_column;
}
+ sqlite3MayAbort(pParse);
assert( pTab->addColOffset>0 );
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -105110,7 +105820,7 @@ struct Stat4Sample {
i64 iRowid; /* Rowid in main table of the key */
u8 *aRowid; /* Key for WITHOUT ROWID tables */
} u;
- u32 nRowid; /* Sizeof aRowid[] */
+ size_t nRowid; /* Sizeof aRowid[] */
u8 isPSample; /* True if a periodic sample */
int iCol; /* If !isPSample, the reason for inclusion */
u32 iHash; /* Tiebreaker hash */
@@ -105148,7 +105858,7 @@ static void sampleClear(sqlite3 *db, Sta
/* Initialize the BLOB value of a ROWID
*/
#ifdef SQLITE_ENABLE_STAT4
-static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
+static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, size_t n, const u8 *pData){
assert( db!=0 );
if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
p->u.aRowid = sqlite3DbMallocRawNN(db, n);
@@ -106189,7 +106899,8 @@ SQLITE_PRIVATE void sqlite3Analyze(Parse
sqlite3 *db = pParse->db;
int iDb;
int i;
- char *z, *zDb;
+ char *z;
+ const char *zDb;
Table *pTab;
Index *pIdx;
Token *pTableName;
@@ -106519,14 +107230,14 @@ static int loadStatTbl(
char *zIndex; /* Index name */
Index *pIdx; /* Pointer to the index object */
- int nSample; /* Number of samples */
+ size_t nSample; /* Number of samples */
int nByte; /* Bytes of space required */
int i; /* Bytes of space required */
tRowcnt *pSpace;
zIndex = (char *)sqlite3_column_text(pStmt, 0);
if( zIndex==0 ) continue;
- nSample = sqlite3_column_int(pStmt, 1);
+ nSample = sqlite3_column_int64(pStmt, 1);
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
assert( pIdx==0 || pIdx->nSample==0 );
if( pIdx==0 ) continue;
@@ -106838,7 +107549,7 @@ static void attachFunc(
goto attach_error;
}
for(i=0; i<db->nDb; i++){
- char *z = db->aDb[i].zDbSName;
+ const char *z = db->aDb[i].zDbSName;
assert( z && zName );
if( sqlite3StrICmp(z, zName)==0 ){
zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName);
@@ -107477,7 +108188,7 @@ SQLITE_PRIVATE int sqlite3AuthReadCol(
int iDb /* Index of containing database. */
){
sqlite3 *db = pParse->db; /* Database handle */
- char *zDb = db->aDb[iDb].zDbSName; /* Schema name of attached database */
+ const char *zDb = db->aDb[iDb].zDbSName; /* Schema name of attached database */
int rc; /* Auth callback return code */
if( db->init.busy ) return SQLITE_OK;
@@ -107754,9 +108465,9 @@ static void codeTableLocks(Parse *pParse
/*
** 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.
+** macros when SQLITE_MAX_ATTACHED is greater than 62.
*/
-#if SQLITE_MAX_ATTACHED>30
+#if SQLITE_MAX_ATTACHED>62
SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask m){
int i;
for(i=0; i<sizeof(yDbMask); i++) if( m[i] ) return 0;
@@ -108151,7 +108862,7 @@ SQLITE_PRIVATE void sqlite3CollapseDatab
for(i=j=2; i<db->nDb; i++){
struct Db *pDb = &db->aDb[i];
if( pDb->pBt==0 ){
- sqlite3DbFree(db, pDb->zDbSName);
+ sqlite3DbFree(db, (char *)pDb->zDbSName);
pDb->zDbSName = 0;
continue;
}
@@ -108602,7 +109313,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
SQLITE_CREATE_VIEW,
SQLITE_CREATE_TEMP_VIEW
};
- char *zDb = db->aDb[iDb].zDbSName;
+ const char *zDb = db->aDb[iDb].zDbSName;
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
goto begin_table_error;
}
@@ -108621,7 +109332,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
** collisions.
*/
if( !IN_SPECIAL_PARSE ){
- char *zDb = db->aDb[iDb].zDbSName;
+ const char *zDb = db->aDb[iDb].zDbSName;
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
goto begin_table_error;
}
@@ -109287,7 +109998,7 @@ static void identPut(char *z, int *pIdx,
static char *createTableStmt(sqlite3 *db, Table *p){
int i, k, n;
char *zStmt;
- char *zSep, *zSep2, *zEnd;
+ const char *zSep, *zSep2, *zEnd;
Column *pCol;
n = 0;
for(pCol = p->aCol, i=0; i<p->nCol; i++, pCol++){
@@ -109775,8 +110486,8 @@ SQLITE_PRIVATE void sqlite3EndTable(
if( !db->init.busy ){
int n;
Vdbe *v;
- char *zType; /* "view" or "table" */
- char *zType2; /* "VIEW" or "TABLE" */
+ const char *zType; /* "view" or "table" */
+ const char *zType2; /* "VIEW" or "TABLE" */
char *zStmt; /* Text of the CREATE TABLE or CREATE VIEW statement */
v = sqlite3GetVdbe(pParse);
@@ -113109,7 +113820,7 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
Expr *pWhere, /* The WHERE clause. May be null */
ExprList *pOrderBy, /* The ORDER BY clause. May be null */
Expr *pLimit, /* The LIMIT clause. May be null */
- char *zStmtType /* Either DELETE or UPDATE. For err msgs. */
+ const char *zStmtType /* Either DELETE or UPDATE. For err msgs. */
){
sqlite3 *db = pParse->db;
Expr *pLhs = NULL; /* LHS of IN(SELECT...) operator */
@@ -113279,6 +113990,11 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
pOrderBy = 0;
pLimit = 0;
}
+#else
+ if( pOrderBy || pLimit ){
+ sqlite3ErrorMsg(pParse, "%s on DELETE not supported", pOrderBy?"ORDER BY":"LIMIT");
+ goto delete_from_cleanup;
+ }
#endif
/* If pTab is really a view, make sure it has been initialized.
@@ -113583,10 +114299,8 @@ delete_from_cleanup:
sqlite3AuthContextPop(&sContext);
sqlite3SrcListDelete(db, pTabList);
sqlite3ExprDelete(db, pWhere);
-#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
sqlite3ExprListDelete(db, pOrderBy);
sqlite3ExprDelete(db, pLimit);
-#endif
sqlite3DbFree(db, aToOpen);
return;
}
@@ -114007,7 +114721,7 @@ static void typeofFunc(
int NotUsed,
sqlite3_value **argv
){
- static const char *azType[] = { "integer", "real", "text", "blob", "null" };
+ static const char *const azType[] = { "integer", "real", "text", "blob", "null" };
int i = sqlite3_value_type(argv[0]) - 1;
UNUSED_PARAMETER(NotUsed);
assert( i>=0 && i<ArraySize(azType) );
@@ -114229,7 +114943,7 @@ static void substrFunc(
){
const unsigned char *z;
const unsigned char *z2;
- int len;
+ size_t len;
int p0type;
i64 p1, p2;
int negP2 = 0;
@@ -114305,7 +115019,7 @@ static void substrFunc(
sqlite3_result_text64(context, (char*)z, z2-z, SQLITE_TRANSIENT,
SQLITE_UTF8);
}else{
- if( p1+p2>len ){
+ if( p1+p2>(i64)len ){
p2 = len-p1;
if( p2<0 ) p2 = 0;
}
@@ -114508,7 +115222,7 @@ static void changes(
){
sqlite3 *db = sqlite3_context_db_handle(context);
UNUSED_PARAMETER2(NotUsed, NotUsed2);
- sqlite3_result_int(context, sqlite3_changes(db));
+ sqlite3_result_int64(context, sqlite3_changes(db));
}
/*
@@ -114524,7 +115238,7 @@ static void total_changes(
UNUSED_PARAMETER2(NotUsed, NotUsed2);
/* IMP: R-52756-41993 This function is a wrapper around the
** sqlite3_total_changes() C/C++ interface. */
- sqlite3_result_int(context, sqlite3_total_changes(db));
+ sqlite3_result_int64(context, sqlite3_total_changes(db));
}
/*
@@ -115049,7 +115763,7 @@ static void charFunc(
){
unsigned char *z, *zOut;
int i;
- zOut = z = sqlite3_malloc64( argc*4+1 );
+ zOut = z = sqlite3Malloc( argc*4+1 );
if( z==0 ){
sqlite3_result_error_nomem(context);
return;
@@ -115143,10 +115857,10 @@ static void replaceFunc(
const unsigned char *zPattern; /* The pattern string B */
const unsigned char *zRep; /* The replacement string C */
unsigned char *zOut; /* The output */
- int nStr; /* Size of zStr */
+ size_t nStr; /* Size of zStr */
int nPattern; /* Size of zPattern */
- int nRep; /* Size of zRep */
- i64 nOut; /* Maximum size of zOut */
+ size_t nRep; /* Size of zRep */
+ int nOut; /* Maximum size of zOut */
int loopLimit; /* Last zStr[] that might match zPattern[] */
int i, j; /* Loop counters */
unsigned cntExpand; /* Number zOut expansions */
@@ -115202,7 +115916,7 @@ static void replaceFunc(
** whose index is a power of two: 1, 2, 4, 8, 16, 32, ... */
u8 *zOld;
zOld = zOut;
- zOut = sqlite3_realloc64(zOut, (int)nOut + (nOut - nStr - 1));
+ zOut = sqlite3Realloc(zOut, (int)nOut + (nOut - nStr - 1));
if( zOut==0 ){
sqlite3_result_error_nomem(context);
sqlite3_free(zOld);
@@ -115215,7 +115929,7 @@ static void replaceFunc(
i += nPattern-1;
}
}
- assert( j+nStr-i+1<=nOut );
+ assert( j+nStr-i+1<=(unsigned)nOut );
memcpy(&zOut[j], &zStr[i], nStr-i);
j += nStr - i;
assert( j<=nOut );
@@ -115308,7 +116022,7 @@ static void trimFunc(
}
-#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+#if 1 /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/
/*
** The "unknown" function is automatically substituted in place of
** any unrecognized function name when doing an EXPLAIN or EXPLAIN QUERY PLAN
@@ -115922,7 +116636,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuilt
LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE),
LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE),
#endif
-#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+#if 1 /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/
FUNCTION(unknown, -1, 0, 0, unknownFunc ),
#endif
FUNCTION(coalesce, 1, 0, 0, 0 ),
@@ -120052,7 +120766,7 @@ exec_out:
struct sqlite3_api_routines {
void * (*aggregate_context)(sqlite3_context*,int nBytes);
int (*aggregate_count)(sqlite3_context*);
- int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
+ int (*bind_blob)(sqlite3_stmt*,int,const void*,unsigned int,void(*)(void*));
int (*bind_double)(sqlite3_stmt*,int,double);
int (*bind_int)(sqlite3_stmt*,int,int);
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
@@ -120060,20 +120774,20 @@ struct sqlite3_api_routines {
int (*bind_parameter_count)(sqlite3_stmt*);
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
- int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
+ int (*bind_text)(sqlite3_stmt*,int,const char*,int,void(*)(void*));
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
int (*busy_timeout)(sqlite3*,int ms);
- int (*changes)(sqlite3*);
+ sqlite_uint64 (*changes)(sqlite3*);
int (*close)(sqlite3*);
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
int eTextRep,const char*));
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
int eTextRep,const void*));
const void * (*column_blob)(sqlite3_stmt*,int iCol);
- int (*column_bytes)(sqlite3_stmt*,int iCol);
- int (*column_bytes16)(sqlite3_stmt*,int iCol);
+ unsigned int (*column_bytes)(sqlite3_stmt*,int iCol);
+ unsigned int (*column_bytes16)(sqlite3_stmt*,int iCol);
int (*column_count)(sqlite3_stmt*pStmt);
const char * (*column_database_name)(sqlite3_stmt*,int);
const void * (*column_database_name16)(sqlite3_stmt*,int);
@@ -120138,7 +120852,7 @@ struct sqlite3_api_routines {
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
void *(*realloc)(void*,int);
int (*reset)(sqlite3_stmt*pStmt);
- void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
+ void (*result_blob)(sqlite3_context*,const void*,unsigned int,void(*)(void*));
void (*result_double)(sqlite3_context*,double);
void (*result_error)(sqlite3_context*,const char*,int);
void (*result_error16)(sqlite3_context*,const void*,int);
@@ -120159,15 +120873,15 @@ struct sqlite3_api_routines {
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
char const**,char const**,int*,int*,int*);
void (*thread_cleanup)(void);
- int (*total_changes)(sqlite3*);
+ sqlite_uint64 (*total_changes)(sqlite3*);
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
sqlite_int64),void*);
void * (*user_data)(sqlite3_context*);
const void * (*value_blob)(sqlite3_value*);
- int (*value_bytes)(sqlite3_value*);
- int (*value_bytes16)(sqlite3_value*);
+ unsigned int (*value_bytes)(sqlite3_value*);
+ unsigned int (*value_bytes16)(sqlite3_value*);
double (*value_double)(sqlite3_value*);
int (*value_int)(sqlite3_value*);
sqlite_int64 (*value_int64)(sqlite3_value*);
@@ -120369,10 +121083,9 @@ typedef int (*sqlite3_loadext_entry)(
*/
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
-#ifndef SQLITE_OMIT_DEPRECATED
-#define sqlite3_aggregate_count sqlite3_api->aggregate_count
-#endif
+#ifndef sqlite3_bind_blob
#define sqlite3_bind_blob sqlite3_api->bind_blob
+#endif
#define sqlite3_bind_double sqlite3_api->bind_double
#define sqlite3_bind_int sqlite3_api->bind_int
#define sqlite3_bind_int64 sqlite3_api->bind_int64
@@ -120380,12 +121093,19 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
+#ifndef sqlite3_bind_text
#define sqlite3_bind_text sqlite3_api->bind_text
+#endif
+#ifndef sqlite3_bind_text16
#define sqlite3_bind_text16 sqlite3_api->bind_text16
+#endif
#define sqlite3_bind_value sqlite3_api->bind_value
#define sqlite3_busy_handler sqlite3_api->busy_handler
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
-#define sqlite3_changes sqlite3_api->changes
+#undef sqlite3_changes
+#define sqlite3_changes (int)sqlite3_api->changes
+#undef sqlite3_changes64
+#define sqlite3_changes64 sqlite3_api->changes
#define sqlite3_close sqlite3_api->close
#define sqlite3_collation_needed sqlite3_api->collation_needed
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
@@ -120413,11 +121133,14 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_commit_hook sqlite3_api->commit_hook
#define sqlite3_complete sqlite3_api->complete
#define sqlite3_complete16 sqlite3_api->complete16
-#define sqlite3_create_collation sqlite3_api->create_collation
+#undef sqlite3_create_collation
+#define sqlite3_create_collation(a,b,c,d,e) sqlite3_create_collation_v2(a,b,c,d,e,0)
#define sqlite3_create_collation16 sqlite3_api->create_collation16
-#define sqlite3_create_function sqlite3_api->create_function
+#undef sqlite3_create_function
+#define sqlite3_create_function(a,b,c,d,e,f,g,h) sqlite3_create_function_v2(a,b,c,d,e,f,g,h,0)
#define sqlite3_create_function16 sqlite3_api->create_function16
-#define sqlite3_create_module sqlite3_api->create_module
+#undef sqlite3_create_module
+#define sqlite3_create_module(a,b,c,d) sqlite3_create_module_v2(a,b,c,d,0)
#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
#define sqlite3_data_count sqlite3_api->data_count
#define sqlite3_db_handle sqlite3_api->db_handle
@@ -120427,23 +121150,19 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_errmsg sqlite3_api->errmsg
#define sqlite3_errmsg16 sqlite3_api->errmsg16
#define sqlite3_exec sqlite3_api->exec
-#ifndef SQLITE_OMIT_DEPRECATED
-#define sqlite3_expired sqlite3_api->expired
-#endif
#define sqlite3_finalize sqlite3_api->finalize
#define sqlite3_free sqlite3_api->free
#define sqlite3_free_table sqlite3_api->free_table
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
#define sqlite3_get_table sqlite3_api->get_table
-#ifndef SQLITE_OMIT_DEPRECATED
-#define sqlite3_global_recover sqlite3_api->global_recover
-#endif
#define sqlite3_interrupt sqlite3_api->interruptx
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
#define sqlite3_libversion sqlite3_api->libversion
#define sqlite3_libversion_number sqlite3_api->libversion_number
+#ifndef sqlite3_malloc
#define sqlite3_malloc sqlite3_api->malloc
+#endif
#define sqlite3_mprintf sqlite3_api->mprintf
#define sqlite3_open sqlite3_api->open
#define sqlite3_open16 sqlite3_api->open16
@@ -120453,19 +121172,31 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
#define sqlite3_profile sqlite3_api->profile
#define sqlite3_progress_handler sqlite3_api->progress_handler
+#ifndef sqlite3_realloc
#define sqlite3_realloc sqlite3_api->realloc
+#endif
#define sqlite3_reset sqlite3_api->reset
+#ifndef sqlite3_result_blob
#define sqlite3_result_blob sqlite3_api->result_blob
+#endif
#define sqlite3_result_double sqlite3_api->result_double
#define sqlite3_result_error sqlite3_api->result_error
#define sqlite3_result_error16 sqlite3_api->result_error16
#define sqlite3_result_int sqlite3_api->result_int
#define sqlite3_result_int64 sqlite3_api->result_int64
#define sqlite3_result_null sqlite3_api->result_null
+#ifndef sqlite3_result_text
#define sqlite3_result_text sqlite3_api->result_text
+#endif
+#ifndef sqlite3_result_text16
#define sqlite3_result_text16 sqlite3_api->result_text16
+#endif
+#ifndef sqlite3_result_text16be
#define sqlite3_result_text16be sqlite3_api->result_text16be
+#endif
+#ifndef sqlite3_result_text16le
#define sqlite3_result_text16le sqlite3_api->result_text16le
+#endif
#define sqlite3_result_value sqlite3_api->result_value
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
@@ -120473,12 +121204,11 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_snprintf sqlite3_api->xsnprintf
#define sqlite3_step sqlite3_api->step
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
-#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
-#define sqlite3_total_changes sqlite3_api->total_changes
+#undef sqlite3_total_changes
+#define sqlite3_total_changes (int)sqlite3_api->total_changes
+#undef sqlite3_total_changes64
+#define sqlite3_total_changes64 sqlite3_api->total_changes
#define sqlite3_trace sqlite3_api->trace
-#ifndef SQLITE_OMIT_DEPRECATED
-#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
-#endif
#define sqlite3_update_hook sqlite3_api->update_hook
#define sqlite3_user_data sqlite3_api->user_data
#define sqlite3_value_blob sqlite3_api->value_blob
@@ -120519,12 +121249,13 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
#define sqlite3_sleep sqlite3_api->sleep
-#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
#define sqlite3_vfs_find sqlite3_api->vfs_find
#define sqlite3_vfs_register sqlite3_api->vfs_register
#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
#define sqlite3_threadsafe sqlite3_api->xthreadsafe
+#ifndef sqlite3_result_zeroblob
#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
+#endif
#define sqlite3_result_error_code sqlite3_api->result_error_code
#define sqlite3_test_control sqlite3_api->test_control
#define sqlite3_randomness sqlite3_api->randomness
@@ -120553,7 +121284,8 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_strnicmp sqlite3_api->strnicmp
#define sqlite3_unlock_notify sqlite3_api->unlock_notify
#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
-#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
+#undef sqlite3_wal_checkpoint
+#define sqlite3_wal_checkpoint(a,b) sqlite3_wal_checkpoint_v2(a,b,SQLITE_CHECKPOINT_PASSIVE,0,0)
#define sqlite3_wal_hook sqlite3_api->wal_hook
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
#define sqlite3_vtab_config sqlite3_api->vtab_config
@@ -120753,6 +121485,11 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_blob_reopen 0
#endif
+#ifdef SQLITE_OMIT_DEPRECATED
+# undef sqlite3_soft_heap_limit
+# define sqlite3_soft_heap_limit 0
+#endif
+
#if defined(SQLITE_OMIT_TRACE)
# define sqlite3_trace_v2 0
#endif
@@ -120772,7 +121509,8 @@ typedef int (*sqlite3_loadext_entry)(
** also check to make sure that the pointer to the function is
** not NULL before calling it.
*/
-static const sqlite3_api_routines sqlite3Apis = {
+#define sqlite3Apis apis_.a
+static const struct {sqlite3_api_routines a;void *b[10];} apis_ = {{
sqlite3_aggregate_context,
#ifndef SQLITE_OMIT_DEPRECATED
sqlite3_aggregate_count,
@@ -120849,7 +121587,11 @@ static const sqlite3_api_routines sqlite
sqlite3_last_insert_rowid,
sqlite3_libversion,
sqlite3_libversion_number,
+#if !defined(SQLITE_OMIT_DEPRECATED) || SQLITE_PTRSIZE<8
sqlite3_malloc,
+#else
+ 0,
+#endif
sqlite3_mprintf,
sqlite3_open,
sqlite3_open16,
@@ -120857,7 +121599,11 @@ static const sqlite3_api_routines sqlite
sqlite3_prepare16,
sqlite3_profile,
sqlite3_progress_handler,
+#if !defined(SQLITE_OMIT_DEPRECATED) || SQLITE_PTRSIZE<8
sqlite3_realloc,
+#else
+ 0,
+#endif
sqlite3_reset,
sqlite3_result_blob,
sqlite3_result_double,
@@ -121110,6 +121856,7 @@ static const sqlite3_api_routines sqlite
#else
0,
#endif
+},{0,0,0,0,0,0,0,0,0,0}
};
/*
@@ -121138,19 +121885,18 @@ static int sqlite3LoadExtension(
char *zAltEntry = 0;
void **aHandle;
u64 nMsg = 300 + sqlite3Strlen30(zFile);
- int ii;
int rc;
/* Shared library endings to try if zFile cannot be loaded as written */
- static const char *azEndings[] = {
-#if SQLITE_OS_WIN
+ static const char azEnding[] =
+#if SQLITE_OS_WIN || defined(__CYGWIN__)
"dll"
#elif defined(__APPLE__)
"dylib"
#else
"so"
#endif
- };
+ ;
if( pzErrMsg ) *pzErrMsg = 0;
@@ -121172,17 +121918,27 @@ static int sqlite3LoadExtension(
zEntry = zProc ? zProc : "sqlite3_extension_init";
handle = sqlite3OsDlOpen(pVfs, zFile);
-#if SQLITE_OS_UNIX || SQLITE_OS_WIN
- for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
- char *zAltFile = sqlite3_mprintf("%s.%s", zFile, azEndings[ii]);
+ if( handle==0 ){
+ char *zAltFile = sqlite3_mprintf("%s.%s", zFile, azEnding);
if( zAltFile==0 ) return SQLITE_NOMEM_BKPT;
handle = sqlite3OsDlOpen(pVfs, zAltFile);
sqlite3_free(zAltFile);
- }
+#if defined(_WIN32) || defined(__CYGWIN__)
+ if( handle==0 ){
+# if defined(__CYGWIN__)
+ zAltFile = sqlite3_mprintf("cygsqlite3%s-0.%s", zFile, azEnding);
+# else /* how about Msys/Msys-2 ??? */
+ zAltFile = sqlite3_mprintf("sqlite3%s.%s", zFile, azEnding);
+# endif
+ if( zAltFile==0 ) return SQLITE_NOMEM;
+ handle = sqlite3OsDlOpen(pVfs, zAltFile);
+ sqlite3_free(zAltFile);
+ }
#endif
+ }
if( handle==0 ){
if( pzErrMsg ){
- *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
+ *pzErrMsg = zErrmsg = sqlite3Malloc(nMsg);
if( zErrmsg ){
sqlite3_snprintf(nMsg, zErrmsg,
"unable to open shared library [%s]", zFile);
@@ -121207,7 +121963,7 @@ static int sqlite3LoadExtension(
if( xInit==0 && zProc==0 ){
int iFile, iEntry, c;
int ncFile = sqlite3Strlen30(zFile);
- zAltEntry = sqlite3_malloc64(ncFile+30);
+ zAltEntry = sqlite3Malloc(ncFile+30);
if( zAltEntry==0 ){
sqlite3OsDlClose(pVfs, handle);
return SQLITE_NOMEM_BKPT;
@@ -121228,7 +121984,7 @@ static int sqlite3LoadExtension(
if( xInit==0 ){
if( pzErrMsg ){
nMsg += sqlite3Strlen30(zEntry);
- *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
+ *pzErrMsg = zErrmsg = sqlite3Malloc(nMsg);
if( zErrmsg ){
sqlite3_snprintf(nMsg, zErrmsg,
"no entry point [%s] in shared library [%s]", zEntry, zFile);
@@ -121363,9 +122119,9 @@ SQLITE_API int sqlite3_auto_extension(
if( wsdAutoext.aExt[i]==xInit ) break;
}
if( i==wsdAutoext.nExt ){
- u64 nByte = (wsdAutoext.nExt+1)*sizeof(wsdAutoext.aExt[0]);
+ size_t nByte = (wsdAutoext.nExt+1)*sizeof(wsdAutoext.aExt[0]);
void (**aNew)(void);
- aNew = sqlite3_realloc64(wsdAutoext.aExt, nByte);
+ aNew = sqlite3Realloc(wsdAutoext.aExt, nByte);
if( aNew==0 ){
rc = SQLITE_NOMEM_BKPT;
}else{
@@ -121728,7 +122484,7 @@ static const PragmaName aPragmaName[] =
/* ColNames: */ 0, 0,
/* iArg: */ SQLITE_CountRows },
#endif
-#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN
+#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && defined(_WIN32)
{/* zName: */ "data_store_directory",
/* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY,
/* ePragFlg: */ PragFlg_NoColumns1,
@@ -122179,7 +122935,7 @@ static const PragmaName aPragmaName[] =
/* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError },
#endif
};
-/* Number of pragmas: 65 on by default, 81 total. */
+/* Number of pragmas: 64 on by default, 81 total. */
/************** End of pragma.h **********************************************/
/************** Continuing where we left off in pragma.c *********************/
@@ -122411,7 +123167,7 @@ static const char *actionName(u8 action)
** journal-mode name.
*/
SQLITE_PRIVATE const char *sqlite3JournalModename(int eMode){
- static char * const azModeName[] = {
+ static const char * const azModeName[] = {
"delete", "persist", "off", "truncate", "memory"
#ifndef SQLITE_OMIT_WAL
, "wal"
@@ -123086,7 +123842,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
break;
}
-#if SQLITE_OS_WIN
+#if defined(_WIN32)
/*
** PRAGMA data_store_directory
** PRAGMA data_store_directory = ""|"directory_name"
@@ -123139,7 +123895,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
Pager *pPager = sqlite3BtreePager(pDb->pBt);
char *proxy_file_path = NULL;
sqlite3_file *pFile = sqlite3PagerFile(pPager);
- sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE,
+ sqlite3OsFileControlHint(pFile, SQLITE_FCNTL_GET_LOCKPROXYFILE,
&proxy_file_path);
returnSingleText(v, proxy_file_path);
}else{
@@ -123147,10 +123903,10 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3_file *pFile = sqlite3PagerFile(pPager);
int res;
if( zRight[0] ){
- res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE,
+ res=sqlite3OsFileControl(pFile, SQLITE_FCNTL_SET_LOCKPROXYFILE,
zRight);
} else {
- res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE,
+ res=sqlite3OsFileControl(pFile, SQLITE_FCNTL_SET_LOCKPROXYFILE,
NULL);
}
if( res!=SQLITE_OK ){
@@ -123362,7 +124118,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
pParse->nMem = 5;
sqlite3CodeVerifySchema(pParse, iTabDb);
for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){
- const char *azOrigin[] = { "c", "u", "pk" };
+ const char azOrigin[][4] = { "c", "u", "pk" };
sqlite3VdbeMultiLoad(v, 1, "isisi",
i,
pIdx->zName,
@@ -123857,7 +124613,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( aOp ){
aOp[0].p2 = 1-mxErr;
aOp[2].p4type = P4_STATIC;
- aOp[2].p4.z = "ok";
+ aOp[2].p4.z = (char *)"ok";
aOp[5].p4type = P4_STATIC;
aOp[5].p4.z = (char*)sqlite3ErrStr(SQLITE_CORRUPT);
}
@@ -123892,7 +124648,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
*/
case PragTyp_ENCODING: {
static const struct EncName {
- char *zName;
+ const char *zName;
u8 enc;
} encnames[] = {
{ "UTF8", SQLITE_UTF8 },
@@ -124727,6 +125483,18 @@ SQLITE_PRIVATE int sqlite3IndexHasDuplic
return 0;
}
+/* forward declaration */
+static int sqlite3Prepare(
+ sqlite3 *db, /* Database handle. */
+ const char *zSql, /* UTF-8 encoded SQL statement. */
+ int nBytes, /* Length of zSql in bytes. */
+ u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */
+ Vdbe *pReprepare, /* VM being reprepared */
+ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
+ const char **pzTail /* OUT: End of parsed string */
+);
+
+
/*
** This is the callback routine for the code that initializes the
** database. See sqlite3Init() below for additional information.
@@ -124776,7 +125544,8 @@ SQLITE_PRIVATE int sqlite3InitCallback(v
db->init.newTnum = sqlite3Atoi(argv[3]);
db->init.orphanTrigger = 0;
db->init.azInit = argv;
- TESTONLY(rcp = ) sqlite3_prepare(db, argv[4], -1, &pStmt, 0);
+ pStmt = 0;
+ TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0);
rc = db->errCode;
assert( (rc&0xFF)==(rcp&0xFF) );
db->init.iDb = saved_iDb;
@@ -126972,7 +127741,7 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoFr
** Name of the connection operator, used for error messages.
*/
static const char *selectOpName(int id){
- char *z;
+ const char *z;
switch( id ){
case TK_ALL: z = "UNION ALL"; break;
case TK_INTERSECT: z = "INTERSECT"; break;
@@ -127486,7 +128255,7 @@ static void generateColumnNames(
char *zName = pEList->a[i].zName;
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT);
}else if( srcName && p->op==TK_COLUMN ){
- char *zCol;
+ const char *zCol;
int iCol = p->iColumn;
pTab = p->y.pTab;
assert( pTab!=0 );
@@ -127581,7 +128350,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExp
Table *pTab = pColExpr->y.pTab;
assert( pTab!=0 );
if( iCol<0 ) iCol = pTab->iPKey;
- zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid";
+ zName = iCol>=0 ? pTab->aCol[iCol].zName : (char *)"rowid";
}else if( pColExpr->op==TK_ID ){
assert( !ExprHasProperty(pColExpr, EP_IntValue) );
zName = pColExpr->u.zToken;
@@ -132377,7 +133146,7 @@ static int sqlite3_get_table_cb(void *pA
if( p->nData + need > p->nAlloc ){
char **azNew;
p->nAlloc = p->nAlloc*2 + need;
- azNew = sqlite3_realloc64( p->azResult, sizeof(char*)*p->nAlloc );
+ azNew = sqlite3Realloc( p->azResult, sizeof(char*)*p->nAlloc );
if( azNew==0 ) goto malloc_failed;
p->azResult = azNew;
}
@@ -132409,7 +133178,7 @@ static int sqlite3_get_table_cb(void *pA
z = 0;
}else{
int n = sqlite3Strlen30(argv[i])+1;
- z = sqlite3_malloc64( n );
+ z = sqlite3Malloc( n );
if( z==0 ) goto malloc_failed;
memcpy(z, argv[i], n);
}
@@ -132458,7 +133227,7 @@ SQLITE_API int sqlite3_get_table(
res.nData = 1;
res.nAlloc = 20;
res.rc = SQLITE_OK;
- res.azResult = sqlite3_malloc64(sizeof(char*)*res.nAlloc );
+ res.azResult = sqlite3Malloc(sizeof(char*)*res.nAlloc );
if( res.azResult==0 ){
db->errCode = SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
@@ -132486,7 +133255,7 @@ SQLITE_API int sqlite3_get_table(
}
if( res.nAlloc>res.nData ){
char **azNew;
- azNew = sqlite3_realloc64( res.azResult, sizeof(char*)*res.nData );
+ azNew = sqlite3Realloc( res.azResult, sizeof(char*)*res.nData );
if( azNew==0 ){
sqlite3_free_table(&res.azResult[1]);
db->errCode = SQLITE_NOMEM;
@@ -133361,7 +134130,7 @@ static int codeTriggerProgram(
return 0;
}
-#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+#if 1
/*
** This function is used to add VdbeComment() annotations to a VDBE
** program. It is not used in production code, only for debugging.
@@ -133958,6 +134727,11 @@ SQLITE_PRIVATE void sqlite3Update(
pOrderBy = 0;
pLimit = 0;
}
+#else
+ if( pOrderBy || pLimit ){
+ sqlite3ErrorMsg(pParse, "%s on UPDATE not supported", pOrderBy?"ORDER BY":"LIMIT");
+ goto update_cleanup;
+ }
#endif
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
@@ -134556,10 +135330,8 @@ update_cleanup:
sqlite3SrcListDelete(db, pTabList);
sqlite3ExprListDelete(db, pChanges);
sqlite3ExprDelete(db, pWhere);
-#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
sqlite3ExprListDelete(db, pOrderBy);
sqlite3ExprDelete(db, pLimit);
-#endif
return;
}
/* Make sure "isView" and other macros defined above are undefined. Otherwise
@@ -135132,8 +135904,8 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlit
Btree *pTemp; /* The temporary database we vacuum into */
u32 saved_mDbFlags; /* Saved value of db->mDbFlags */
u64 saved_flags; /* Saved value of db->flags */
- int saved_nChange; /* Saved value of db->nChange */
- int saved_nTotalChange; /* Saved value of db->nTotalChange */
+ u64 saved_nChange; /* Saved value of db->nChange */
+ u64 saved_nTotalChange; /* Saved value of db->nTotalChange */
u32 saved_openFlags; /* Saved value of db->openFlags */
u8 saved_mTrace; /* Saved trace settings */
Db *pDb = 0; /* Database to detach at end of vacuum */
@@ -135504,6 +136276,7 @@ static int createModule(
/*
** External API function used to create a new virtual-table module.
*/
+#undef sqlite3_create_module
SQLITE_API int sqlite3_create_module(
sqlite3 *db, /* Database in which module is registered */
const char *zName, /* Name assigned to this module */
@@ -135986,7 +136759,7 @@ static int vtabCallConstructor(
pVTable->pMod = pMod;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
- pTab->azModuleArg[1] = db->aDb[iDb].zDbSName;
+ pTab->azModuleArg[1] = (char *)db->aDb[iDb].zDbSName;
/* Invoke the virtual table constructor */
assert( &db->pVtabCtx );
@@ -136033,7 +136806,7 @@ static int vtabCallConstructor(
pTab->pVTable = pVTable;
for(iCol=0; iCol<pTab->nCol; iCol++){
- char *zType = sqlite3ColumnType(&pTab->aCol[iCol], "");
+ char *zType = (char *) sqlite3ColumnType(&pTab->aCol[iCol], 0);
int nType;
int i = 0;
nType = sqlite3Strlen30(zType);
@@ -136572,7 +137345,7 @@ SQLITE_PRIVATE void sqlite3VtabMakeWrita
if( pTab==pToplevel->apVtabLock[i] ) return;
}
n = (pToplevel->nVtabLock+1)*sizeof(pToplevel->apVtabLock[0]);
- apVtabLock = sqlite3_realloc64(pToplevel->apVtabLock, n);
+ apVtabLock = sqlite3Realloc(pToplevel->apVtabLock, n);
if( apVtabLock ){
pToplevel->apVtabLock = apVtabLock;
pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab;
@@ -136866,7 +137639,7 @@ struct WhereLoop {
u8 needFree; /* True if sqlite3_free(idxStr) is needed */
i8 isOrdered; /* True if satisfies ORDER BY */
u16 omitMask; /* Terms that may be omitted */
- char *idxStr; /* Index identifier string */
+ const char *idxStr; /* Index identifier string */
} vtab;
} u;
u32 wsFlags; /* WHERE_* flags describing the plan */
@@ -142056,7 +142829,7 @@ static void constructAutomaticIndex(
pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+1, 0, &zNotUsed);
if( pIdx==0 ) goto end_auto_index_create;
pLoop->u.btree.pIndex = pIdx;
- pIdx->zName = "auto-index";
+ pIdx->zName = (char *)"auto-index";
pIdx->pTable = pTable;
n = 0;
idxCols = 0;
@@ -143075,7 +143848,7 @@ static void whereLoopPrint(WhereLoop *p,
const char *zName;
if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){
if( strncmp(zName, "sqlite_autoindex_", 17)==0 ){
- int i = sqlite3Strlen30(zName) - 1;
+ size_t i = sqlite3Strlen30(zName) - 1;
while( zName[i]!='_' ) i--;
zName += i;
}
@@ -143126,7 +143899,7 @@ static void whereLoopInit(WhereLoop *p){
static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){
if( p->wsFlags & (WHERE_VIRTUALTABLE|WHERE_AUTO_INDEX) ){
if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 && p->u.vtab.needFree ){
- sqlite3_free(p->u.vtab.idxStr);
+ sqlite3_free((char *)p->u.vtab.idxStr);
p->u.vtab.needFree = 0;
p->u.vtab.idxStr = 0;
}else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){
@@ -144509,7 +145282,7 @@ static int whereLoopAddVirtualOne(
}
rc = whereLoopInsert(pBuilder, pNew);
if( pNew->u.vtab.needFree ){
- sqlite3_free(pNew->u.vtab.idxStr);
+ sqlite3_free((char *)pNew->u.vtab.idxStr);
pNew->u.vtab.needFree = 0;
}
WHERETRACE(0xffff, (" bIn=%d prereqIn=%04llx prereqOut=%04llx\n",
@@ -144678,7 +145451,7 @@ static int whereLoopAddVirtual(
}
}
- if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr);
+ if( p->needToFreeIdxStr ) sqlite3_free((char *)p->idxStr);
sqlite3DbFreeNN(pParse->db, p);
WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pTab->zName, rc));
return rc;
@@ -149707,7 +150480,7 @@ SQLITE_PRIVATE void sqlite3WindowCodeSte
** Alternative datatype for the argument to the malloc() routine passed
** into sqlite3ParserAlloc(). The default is size_t.
*/
-#define YYMALLOCARGTYPE u64
+#define YYMALLOCARGTYPE size_t
/*
** An instance of the following structure describes the event of a
@@ -149929,17 +150702,17 @@ typedef union {
#define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse;
#define sqlite3ParserCTX_STORE yypParser->pParse=pParse;
#define YYFALLBACK 1
-#define YYNSTATE 543
+#define YYNSTATE 547
#define YYNRULE 381
#define YYNTOKEN 179
-#define YY_MAX_SHIFT 542
-#define YY_MIN_SHIFTREDUCE 790
-#define YY_MAX_SHIFTREDUCE 1170
-#define YY_ERROR_ACTION 1171
-#define YY_ACCEPT_ACTION 1172
-#define YY_NO_ACTION 1173
-#define YY_MIN_REDUCE 1174
-#define YY_MAX_REDUCE 1554
+#define YY_MAX_SHIFT 546
+#define YY_MIN_SHIFTREDUCE 794
+#define YY_MAX_SHIFTREDUCE 1174
+#define YY_ERROR_ACTION 1175
+#define YY_ACCEPT_ACTION 1176
+#define YY_NO_ACTION 1177
+#define YY_MIN_REDUCE 1178
+#define YY_MAX_REDUCE 1558
/************* End control #defines *******************************************/
#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))
@@ -150006,200 +150779,200 @@ typedef union {
** yy_default[] Default action for each state.
**
*********** Begin parsing tables **********************************************/
-#define YY_ACTTAB_COUNT (1913)
+#define YY_ACTTAB_COUNT (1918)
static const YYACTIONTYPE yy_action[] = {
- /* 0 */ 537, 339, 537, 1241, 1220, 537, 12, 537, 112, 109,
- /* 10 */ 209, 537, 1241, 537, 1205, 462, 112, 109, 209, 386,
- /* 20 */ 338, 462, 42, 42, 42, 42, 445, 42, 42, 70,
- /* 30 */ 70, 922, 1208, 70, 70, 70, 70, 1443, 403, 923,
- /* 40 */ 531, 531, 531, 119, 120, 110, 1148, 1148, 991, 994,
- /* 50 */ 984, 984, 117, 117, 118, 118, 118, 118, 425, 386,
- /* 60 */ 1498, 542, 2, 1176, 1442, 519, 141, 1518, 289, 519,
- /* 70 */ 134, 519, 95, 259, 495, 1215, 189, 1254, 518, 494,
- /* 80 */ 484, 437, 296, 119, 120, 110, 1148, 1148, 991, 994,
- /* 90 */ 984, 984, 117, 117, 118, 118, 118, 118, 270, 116,
- /* 100 */ 116, 116, 116, 115, 115, 114, 114, 114, 113, 418,
- /* 110 */ 264, 264, 264, 264, 423, 1479, 352, 1481, 123, 351,
- /* 120 */ 1479, 508, 1094, 534, 1034, 534, 1099, 386, 1099, 239,
- /* 130 */ 206, 112, 109, 209, 96, 1094, 376, 219, 1094, 116,
- /* 140 */ 116, 116, 116, 115, 115, 114, 114, 114, 113, 418,
- /* 150 */ 480, 119, 120, 110, 1148, 1148, 991, 994, 984, 984,
- /* 160 */ 117, 117, 118, 118, 118, 118, 353, 422, 1407, 264,
- /* 170 */ 264, 114, 114, 114, 113, 418, 883, 121, 416, 416,
- /* 180 */ 416, 882, 534, 116, 116, 116, 116, 115, 115, 114,
- /* 190 */ 114, 114, 113, 418, 212, 415, 414, 386, 443, 383,
- /* 200 */ 382, 118, 118, 118, 118, 111, 177, 116, 116, 116,
- /* 210 */ 116, 115, 115, 114, 114, 114, 113, 418, 112, 109,
- /* 220 */ 209, 119, 120, 110, 1148, 1148, 991, 994, 984, 984,
- /* 230 */ 117, 117, 118, 118, 118, 118, 386, 438, 312, 1163,
- /* 240 */ 1155, 80, 1155, 1127, 514, 79, 116, 116, 116, 116,
- /* 250 */ 115, 115, 114, 114, 114, 113, 418, 514, 428, 418,
- /* 260 */ 119, 120, 110, 1148, 1148, 991, 994, 984, 984, 117,
- /* 270 */ 117, 118, 118, 118, 118, 428, 427, 116, 116, 116,
- /* 280 */ 116, 115, 115, 114, 114, 114, 113, 418, 115, 115,
- /* 290 */ 114, 114, 114, 113, 418, 1127, 1127, 1128, 1129, 1094,
- /* 300 */ 258, 258, 192, 386, 408, 371, 1168, 326, 118, 118,
- /* 310 */ 118, 118, 1094, 534, 374, 1094, 116, 116, 116, 116,
- /* 320 */ 115, 115, 114, 114, 114, 113, 418, 119, 120, 110,
- /* 330 */ 1148, 1148, 991, 994, 984, 984, 117, 117, 118, 118,
- /* 340 */ 118, 118, 386, 354, 445, 428, 829, 238, 1127, 1128,
- /* 350 */ 1129, 515, 1466, 116, 116, 116, 116, 115, 115, 114,
- /* 360 */ 114, 114, 113, 418, 1127, 1467, 119, 120, 110, 1148,
- /* 370 */ 1148, 991, 994, 984, 984, 117, 117, 118, 118, 118,
- /* 380 */ 118, 1169, 82, 116, 116, 116, 116, 115, 115, 114,
- /* 390 */ 114, 114, 113, 418, 405, 112, 109, 209, 161, 445,
- /* 400 */ 250, 267, 336, 478, 331, 477, 236, 951, 1127, 386,
- /* 410 */ 888, 1521, 329, 822, 852, 162, 274, 1127, 1128, 1129,
- /* 420 */ 338, 169, 116, 116, 116, 116, 115, 115, 114, 114,
- /* 430 */ 114, 113, 418, 119, 120, 110, 1148, 1148, 991, 994,
- /* 440 */ 984, 984, 117, 117, 118, 118, 118, 118, 386, 438,
- /* 450 */ 312, 1502, 1112, 1176, 161, 288, 528, 311, 289, 883,
- /* 460 */ 134, 1127, 1128, 1129, 882, 537, 143, 1254, 288, 528,
- /* 470 */ 297, 275, 119, 120, 110, 1148, 1148, 991, 994, 984,
- /* 480 */ 984, 117, 117, 118, 118, 118, 118, 70, 70, 116,
- /* 490 */ 116, 116, 116, 115, 115, 114, 114, 114, 113, 418,
- /* 500 */ 264, 264, 12, 264, 264, 395, 1127, 483, 1473, 1094,
- /* 510 */ 204, 482, 6, 534, 1258, 386, 534, 1474, 825, 972,
- /* 520 */ 504, 6, 1094, 500, 95, 1094, 534, 219, 116, 116,
- /* 530 */ 116, 116, 115, 115, 114, 114, 114, 113, 418, 119,
- /* 540 */ 120, 110, 1148, 1148, 991, 994, 984, 984, 117, 117,
- /* 550 */ 118, 118, 118, 118, 386, 1339, 971, 422, 956, 1127,
- /* 560 */ 1128, 1129, 231, 512, 1473, 475, 472, 471, 6, 113,
- /* 570 */ 418, 825, 962, 298, 503, 470, 961, 452, 119, 120,
- /* 580 */ 110, 1148, 1148, 991, 994, 984, 984, 117, 117, 118,
- /* 590 */ 118, 118, 118, 395, 537, 116, 116, 116, 116, 115,
- /* 600 */ 115, 114, 114, 114, 113, 418, 202, 961, 961, 963,
- /* 610 */ 231, 971, 1127, 475, 472, 471, 13, 13, 951, 1127,
- /* 620 */ 834, 386, 1207, 470, 399, 183, 447, 962, 462, 162,
- /* 630 */ 397, 961, 1246, 1246, 116, 116, 116, 116, 115, 115,
- /* 640 */ 114, 114, 114, 113, 418, 119, 120, 110, 1148, 1148,
- /* 650 */ 991, 994, 984, 984, 117, 117, 118, 118, 118, 118,
- /* 660 */ 386, 271, 961, 961, 963, 1127, 1128, 1129, 311, 433,
- /* 670 */ 299, 1406, 1127, 1128, 1129, 178, 1471, 138, 162, 32,
- /* 680 */ 6, 1127, 288, 528, 119, 120, 110, 1148, 1148, 991,
- /* 690 */ 994, 984, 984, 117, 117, 118, 118, 118, 118, 909,
- /* 700 */ 390, 116, 116, 116, 116, 115, 115, 114, 114, 114,
- /* 710 */ 113, 418, 1127, 429, 817, 537, 1127, 265, 265, 981,
- /* 720 */ 981, 992, 995, 324, 1055, 93, 520, 5, 338, 537,
- /* 730 */ 534, 288, 528, 1522, 1127, 1128, 1129, 70, 70, 1056,
+ /* 0 */ 541, 343, 541, 1245, 1224, 541, 12, 541, 112, 109,
+ /* 10 */ 209, 541, 1245, 541, 1209, 466, 112, 109, 209, 390,
+ /* 20 */ 342, 466, 42, 42, 42, 42, 449, 42, 42, 70,
+ /* 30 */ 70, 926, 1212, 70, 70, 70, 70, 1447, 407, 927,
+ /* 40 */ 535, 535, 535, 119, 120, 110, 1152, 1152, 995, 998,
+ /* 50 */ 988, 988, 117, 117, 118, 118, 118, 118, 429, 390,
+ /* 60 */ 1502, 546, 2, 1180, 1446, 523, 141, 1522, 289, 523,
+ /* 70 */ 134, 523, 95, 259, 499, 1219, 189, 1258, 522, 498,
+ /* 80 */ 488, 441, 296, 119, 120, 110, 1152, 1152, 995, 998,
+ /* 90 */ 988, 988, 117, 117, 118, 118, 118, 118, 270, 116,
+ /* 100 */ 116, 116, 116, 115, 115, 114, 114, 114, 113, 422,
+ /* 110 */ 264, 264, 264, 264, 427, 1483, 356, 1485, 123, 355,
+ /* 120 */ 1483, 512, 1098, 538, 1038, 538, 1103, 390, 1103, 239,
+ /* 130 */ 206, 112, 109, 209, 96, 1098, 380, 219, 1098, 116,
+ /* 140 */ 116, 116, 116, 115, 115, 114, 114, 114, 113, 422,
+ /* 150 */ 484, 119, 120, 110, 1152, 1152, 995, 998, 988, 988,
+ /* 160 */ 117, 117, 118, 118, 118, 118, 357, 426, 1411, 264,
+ /* 170 */ 264, 114, 114, 114, 113, 422, 887, 121, 420, 420,
+ /* 180 */ 420, 886, 538, 116, 116, 116, 116, 115, 115, 114,
+ /* 190 */ 114, 114, 113, 422, 212, 419, 418, 390, 447, 387,
+ /* 200 */ 386, 118, 118, 118, 118, 111, 177, 116, 116, 116,
+ /* 210 */ 116, 115, 115, 114, 114, 114, 113, 422, 112, 109,
+ /* 220 */ 209, 119, 120, 110, 1152, 1152, 995, 998, 988, 988,
+ /* 230 */ 117, 117, 118, 118, 118, 118, 390, 442, 316, 1167,
+ /* 240 */ 1159, 80, 1159, 1131, 518, 79, 116, 116, 116, 116,
+ /* 250 */ 115, 115, 114, 114, 114, 113, 422, 518, 432, 422,
+ /* 260 */ 119, 120, 110, 1152, 1152, 995, 998, 988, 988, 117,
+ /* 270 */ 117, 118, 118, 118, 118, 432, 431, 116, 116, 116,
+ /* 280 */ 116, 115, 115, 114, 114, 114, 113, 422, 115, 115,
+ /* 290 */ 114, 114, 114, 113, 422, 1131, 1131, 1132, 1133, 1098,
+ /* 300 */ 258, 258, 192, 390, 412, 375, 1172, 330, 118, 118,
+ /* 310 */ 118, 118, 1098, 538, 378, 1098, 116, 116, 116, 116,
+ /* 320 */ 115, 115, 114, 114, 114, 113, 422, 119, 120, 110,
+ /* 330 */ 1152, 1152, 995, 998, 988, 988, 117, 117, 118, 118,
+ /* 340 */ 118, 118, 390, 358, 449, 432, 833, 238, 1131, 1132,
+ /* 350 */ 1133, 519, 1470, 116, 116, 116, 116, 115, 115, 114,
+ /* 360 */ 114, 114, 113, 422, 1131, 1471, 119, 120, 110, 1152,
+ /* 370 */ 1152, 995, 998, 988, 988, 117, 117, 118, 118, 118,
+ /* 380 */ 118, 1173, 82, 116, 116, 116, 116, 115, 115, 114,
+ /* 390 */ 114, 114, 113, 422, 409, 112, 109, 209, 161, 449,
+ /* 400 */ 250, 267, 340, 482, 335, 481, 236, 955, 1131, 390,
+ /* 410 */ 892, 1525, 333, 826, 856, 162, 274, 1131, 1132, 1133,
+ /* 420 */ 342, 169, 116, 116, 116, 116, 115, 115, 114, 114,
+ /* 430 */ 114, 113, 422, 119, 120, 110, 1152, 1152, 995, 998,
+ /* 440 */ 988, 988, 117, 117, 118, 118, 118, 118, 390, 442,
+ /* 450 */ 316, 1506, 1116, 1180, 161, 288, 532, 315, 289, 887,
+ /* 460 */ 134, 1131, 1132, 1133, 886, 541, 143, 1258, 288, 532,
+ /* 470 */ 297, 275, 119, 120, 110, 1152, 1152, 995, 998, 988,
+ /* 480 */ 988, 117, 117, 118, 118, 118, 118, 70, 70, 116,
+ /* 490 */ 116, 116, 116, 115, 115, 114, 114, 114, 113, 422,
+ /* 500 */ 264, 264, 12, 264, 264, 399, 1131, 487, 1477, 1098,
+ /* 510 */ 204, 486, 6, 538, 1262, 390, 538, 1478, 829, 976,
+ /* 520 */ 508, 6, 1098, 504, 95, 1098, 538, 219, 116, 116,
+ /* 530 */ 116, 116, 115, 115, 114, 114, 114, 113, 422, 119,
+ /* 540 */ 120, 110, 1152, 1152, 995, 998, 988, 988, 117, 117,
+ /* 550 */ 118, 118, 118, 118, 390, 1343, 975, 426, 960, 1131,
+ /* 560 */ 1132, 1133, 231, 516, 1477, 479, 476, 475, 6, 113,
+ /* 570 */ 422, 829, 966, 298, 507, 474, 965, 456, 119, 120,
+ /* 580 */ 110, 1152, 1152, 995, 998, 988, 988, 117, 117, 118,
+ /* 590 */ 118, 118, 118, 399, 541, 116, 116, 116, 116, 115,
+ /* 600 */ 115, 114, 114, 114, 113, 422, 202, 965, 965, 967,
+ /* 610 */ 231, 975, 1131, 479, 476, 475, 13, 13, 955, 1131,
+ /* 620 */ 838, 390, 1211, 474, 403, 183, 451, 966, 466, 162,
+ /* 630 */ 401, 965, 1250, 1250, 116, 116, 116, 116, 115, 115,
+ /* 640 */ 114, 114, 114, 113, 422, 119, 120, 110, 1152, 1152,
+ /* 650 */ 995, 998, 988, 988, 117, 117, 118, 118, 118, 118,
+ /* 660 */ 390, 271, 965, 965, 967, 1131, 1132, 1133, 315, 437,
+ /* 670 */ 301, 1410, 1131, 1132, 1133, 178, 1475, 138, 162, 32,
+ /* 680 */ 6, 1131, 288, 532, 119, 120, 110, 1152, 1152, 995,
+ /* 690 */ 998, 988, 988, 117, 117, 118, 118, 118, 118, 913,
+ /* 700 */ 394, 116, 116, 116, 116, 115, 115, 114, 114, 114,
+ /* 710 */ 113, 422, 1131, 433, 821, 541, 1131, 265, 265, 985,
+ /* 720 */ 985, 996, 999, 328, 1059, 93, 524, 5, 342, 541,
+ /* 730 */ 538, 288, 532, 1526, 1131, 1132, 1133, 70, 70, 1060,
/* 740 */ 116, 116, 116, 116, 115, 115, 114, 114, 114, 113,
- /* 750 */ 418, 70, 70, 1495, 1057, 537, 98, 1244, 1244, 264,
- /* 760 */ 264, 908, 371, 1076, 1127, 1127, 1128, 1129, 817, 1127,
- /* 770 */ 1128, 1129, 534, 519, 140, 863, 386, 13, 13, 456,
- /* 780 */ 192, 193, 521, 453, 319, 864, 322, 284, 365, 430,
- /* 790 */ 985, 402, 379, 1077, 1548, 101, 386, 1548, 3, 395,
- /* 800 */ 119, 120, 110, 1148, 1148, 991, 994, 984, 984, 117,
- /* 810 */ 117, 118, 118, 118, 118, 386, 451, 1127, 1128, 1129,
- /* 820 */ 119, 120, 110, 1148, 1148, 991, 994, 984, 984, 117,
- /* 830 */ 117, 118, 118, 118, 118, 1127, 1354, 1412, 1169, 119,
- /* 840 */ 108, 110, 1148, 1148, 991, 994, 984, 984, 117, 117,
- /* 850 */ 118, 118, 118, 118, 1412, 1414, 116, 116, 116, 116,
- /* 860 */ 115, 115, 114, 114, 114, 113, 418, 272, 535, 1075,
- /* 870 */ 877, 877, 337, 1492, 309, 462, 116, 116, 116, 116,
- /* 880 */ 115, 115, 114, 114, 114, 113, 418, 537, 1127, 1128,
- /* 890 */ 1129, 537, 360, 537, 356, 116, 116, 116, 116, 115,
- /* 900 */ 115, 114, 114, 114, 113, 418, 386, 264, 264, 13,
- /* 910 */ 13, 273, 1127, 13, 13, 13, 13, 304, 1253, 386,
- /* 920 */ 534, 1077, 1549, 404, 1412, 1549, 496, 277, 451, 186,
- /* 930 */ 1252, 120, 110, 1148, 1148, 991, 994, 984, 984, 117,
- /* 940 */ 117, 118, 118, 118, 118, 110, 1148, 1148, 991, 994,
- /* 950 */ 984, 984, 117, 117, 118, 118, 118, 118, 105, 529,
- /* 960 */ 537, 4, 1339, 264, 264, 1127, 1128, 1129, 1039, 1039,
- /* 970 */ 459, 795, 796, 797, 536, 532, 534, 242, 301, 807,
- /* 980 */ 303, 462, 69, 69, 451, 1353, 116, 116, 116, 116,
- /* 990 */ 115, 115, 114, 114, 114, 113, 418, 1075, 419, 116,
- /* 1000 */ 116, 116, 116, 115, 115, 114, 114, 114, 113, 418,
- /* 1010 */ 526, 537, 1146, 192, 350, 105, 529, 537, 4, 497,
- /* 1020 */ 162, 337, 1492, 310, 1249, 385, 1550, 372, 9, 462,
- /* 1030 */ 242, 400, 532, 13, 13, 499, 971, 843, 436, 70,
- /* 1040 */ 70, 359, 103, 103, 8, 339, 278, 187, 278, 104,
- /* 1050 */ 1127, 419, 539, 538, 1339, 419, 961, 302, 1339, 1172,
- /* 1060 */ 1, 1, 542, 2, 1176, 1146, 1146, 526, 476, 289,
- /* 1070 */ 30, 134, 317, 288, 528, 285, 844, 1014, 1254, 276,
- /* 1080 */ 1472, 506, 410, 1194, 6, 207, 505, 961, 961, 963,
- /* 1090 */ 964, 27, 449, 971, 415, 414, 234, 233, 232, 103,
- /* 1100 */ 103, 31, 1152, 1127, 1128, 1129, 104, 1154, 419, 539,
- /* 1110 */ 538, 264, 264, 961, 1399, 1153, 264, 264, 1470, 1146,
- /* 1120 */ 537, 216, 6, 401, 534, 1197, 392, 458, 406, 534,
- /* 1130 */ 537, 485, 358, 537, 261, 537, 1339, 907, 219, 1155,
- /* 1140 */ 467, 1155, 50, 50, 961, 961, 963, 964, 27, 1497,
- /* 1150 */ 1116, 421, 70, 70, 268, 70, 70, 13, 13, 369,
- /* 1160 */ 369, 368, 253, 366, 264, 264, 804, 235, 422, 105,
- /* 1170 */ 529, 516, 4, 287, 487, 510, 493, 534, 486, 213,
- /* 1180 */ 1055, 294, 490, 384, 1127, 450, 532, 338, 413, 293,
- /* 1190 */ 522, 417, 335, 1036, 509, 1056, 107, 1036, 16, 16,
- /* 1200 */ 1469, 1094, 334, 1105, 6, 411, 1145, 264, 264, 419,
- /* 1210 */ 1057, 102, 511, 100, 1094, 264, 264, 1094, 922, 215,
- /* 1220 */ 534, 526, 907, 264, 264, 208, 923, 154, 534, 457,
- /* 1230 */ 156, 525, 391, 142, 218, 506, 534, 1127, 1128, 1129,
- /* 1240 */ 507, 139, 1131, 38, 214, 530, 392, 971, 329, 1454,
- /* 1250 */ 907, 1105, 537, 103, 103, 105, 529, 537, 4, 537,
- /* 1260 */ 104, 424, 419, 539, 538, 537, 502, 961, 517, 537,
- /* 1270 */ 1072, 537, 532, 373, 54, 54, 288, 528, 387, 55,
- /* 1280 */ 55, 15, 15, 288, 528, 17, 136, 44, 44, 1451,
- /* 1290 */ 537, 56, 56, 57, 57, 419, 1131, 291, 961, 961,
- /* 1300 */ 963, 964, 27, 393, 163, 537, 426, 526, 263, 206,
- /* 1310 */ 208, 517, 58, 58, 235, 440, 842, 841, 197, 105,
- /* 1320 */ 529, 506, 4, 1033, 439, 1033, 505, 59, 59, 308,
- /* 1330 */ 849, 850, 95, 971, 537, 907, 532, 948, 832, 103,
- /* 1340 */ 103, 105, 529, 537, 4, 1021, 104, 537, 419, 539,
- /* 1350 */ 538, 1116, 421, 961, 537, 268, 60, 60, 532, 419,
- /* 1360 */ 369, 369, 368, 253, 366, 61, 61, 804, 965, 45,
- /* 1370 */ 45, 526, 537, 1032, 1277, 1032, 46, 46, 537, 391,
- /* 1380 */ 213, 419, 294, 266, 961, 961, 963, 964, 27, 292,
- /* 1390 */ 293, 295, 832, 526, 48, 48, 1290, 971, 1289, 1021,
- /* 1400 */ 49, 49, 432, 103, 103, 887, 953, 537, 1457, 241,
- /* 1410 */ 104, 305, 419, 539, 538, 925, 926, 961, 444, 971,
- /* 1420 */ 215, 241, 965, 1224, 537, 103, 103, 1431, 154, 62,
- /* 1430 */ 62, 156, 104, 1430, 419, 539, 538, 97, 529, 961,
- /* 1440 */ 4, 537, 454, 537, 314, 214, 63, 63, 961, 961,
- /* 1450 */ 963, 964, 27, 537, 532, 446, 1286, 318, 241, 537,
- /* 1460 */ 321, 323, 325, 64, 64, 14, 14, 1237, 537, 1223,
- /* 1470 */ 961, 961, 963, 964, 27, 65, 65, 419, 537, 387,
- /* 1480 */ 537, 125, 125, 537, 288, 528, 537, 1486, 537, 526,
- /* 1490 */ 66, 66, 313, 524, 537, 95, 468, 1221, 1511, 237,
- /* 1500 */ 51, 51, 67, 67, 330, 68, 68, 426, 52, 52,
- /* 1510 */ 149, 149, 1222, 340, 341, 971, 150, 150, 1298, 463,
- /* 1520 */ 327, 103, 103, 95, 537, 1338, 1273, 537, 104, 537,
- /* 1530 */ 419, 539, 538, 1284, 537, 961, 268, 283, 523, 1344,
- /* 1540 */ 1204, 369, 369, 368, 253, 366, 75, 75, 804, 53,
- /* 1550 */ 53, 71, 71, 537, 1196, 537, 126, 126, 537, 1017,
- /* 1560 */ 537, 213, 237, 294, 537, 1185, 961, 961, 963, 964,
- /* 1570 */ 27, 293, 537, 1184, 537, 72, 72, 127, 127, 1186,
- /* 1580 */ 128, 128, 124, 124, 1505, 537, 148, 148, 537, 256,
- /* 1590 */ 195, 537, 1270, 537, 147, 147, 132, 132, 537, 11,
- /* 1600 */ 537, 215, 537, 199, 343, 345, 347, 131, 131, 154,
- /* 1610 */ 129, 129, 156, 130, 130, 74, 74, 537, 370, 1323,
- /* 1620 */ 76, 76, 73, 73, 43, 43, 214, 431, 211, 1331,
- /* 1630 */ 300, 916, 880, 815, 241, 107, 137, 307, 881, 47,
- /* 1640 */ 47, 107, 473, 378, 203, 448, 333, 1403, 1220, 1402,
- /* 1650 */ 349, 190, 527, 191, 363, 198, 1508, 1163, 245, 165,
- /* 1660 */ 387, 1450, 1448, 1160, 78, 288, 528, 1408, 81, 394,
- /* 1670 */ 82, 442, 175, 159, 167, 93, 1328, 35, 1320, 434,
- /* 1680 */ 170, 171, 172, 173, 435, 466, 221, 375, 426, 377,
- /* 1690 */ 1334, 179, 455, 441, 1397, 225, 87, 36, 461, 1419,
- /* 1700 */ 316, 257, 227, 184, 320, 464, 228, 479, 1187, 229,
- /* 1710 */ 380, 1240, 1239, 407, 1238, 1212, 834, 332, 1231, 381,
- /* 1720 */ 409, 1211, 204, 1210, 1491, 498, 1520, 1281, 92, 281,
- /* 1730 */ 1230, 489, 282, 492, 342, 243, 1282, 344, 244, 1280,
- /* 1740 */ 346, 412, 1279, 1477, 348, 122, 1476, 517, 10, 357,
- /* 1750 */ 286, 1305, 1304, 99, 1383, 94, 501, 251, 1193, 34,
- /* 1760 */ 1263, 355, 540, 194, 1262, 361, 362, 1122, 252, 254,
- /* 1770 */ 255, 388, 541, 1182, 1177, 151, 1435, 389, 1436, 1434,
- /* 1780 */ 1433, 791, 152, 135, 279, 200, 201, 420, 196, 77,
- /* 1790 */ 153, 290, 269, 210, 1031, 133, 1029, 945, 166, 155,
- /* 1800 */ 217, 168, 866, 306, 220, 1045, 174, 949, 157, 396,
- /* 1810 */ 83, 398, 176, 84, 85, 164, 86, 158, 1048, 222,
- /* 1820 */ 223, 1044, 144, 18, 224, 315, 1037, 180, 241, 460,
- /* 1830 */ 1157, 226, 181, 37, 806, 465, 334, 230, 328, 469,
- /* 1840 */ 182, 88, 474, 19, 20, 160, 89, 280, 145, 90,
- /* 1850 */ 481, 845, 1110, 146, 997, 205, 1080, 39, 91, 40,
- /* 1860 */ 488, 1081, 915, 491, 260, 262, 185, 910, 240, 107,
- /* 1870 */ 1100, 1096, 1098, 1104, 21, 1084, 33, 513, 247, 22,
- /* 1880 */ 23, 24, 1103, 25, 188, 95, 1012, 998, 996, 26,
- /* 1890 */ 1000, 1054, 7, 1053, 1001, 246, 28, 41, 533, 966,
- /* 1900 */ 816, 106, 29, 367, 248, 249, 1513, 1512, 364, 1117,
- /* 1910 */ 1173, 1173, 876,
+ /* 750 */ 422, 70, 70, 1499, 1061, 541, 98, 1248, 1248, 264,
+ /* 760 */ 264, 912, 375, 1080, 1131, 1131, 1132, 1133, 821, 1131,
+ /* 770 */ 1132, 1133, 538, 523, 140, 867, 390, 13, 13, 460,
+ /* 780 */ 192, 193, 525, 457, 323, 868, 326, 284, 369, 434,
+ /* 790 */ 989, 406, 383, 1081, 1552, 101, 390, 1552, 3, 399,
+ /* 800 */ 119, 120, 110, 1152, 1152, 995, 998, 988, 988, 117,
+ /* 810 */ 117, 118, 118, 118, 118, 390, 455, 1131, 1132, 1133,
+ /* 820 */ 119, 120, 110, 1152, 1152, 995, 998, 988, 988, 117,
+ /* 830 */ 117, 118, 118, 118, 118, 1131, 1358, 1416, 1173, 119,
+ /* 840 */ 108, 110, 1152, 1152, 995, 998, 988, 988, 117, 117,
+ /* 850 */ 118, 118, 118, 118, 1416, 1418, 116, 116, 116, 116,
+ /* 860 */ 115, 115, 114, 114, 114, 113, 422, 272, 539, 1079,
+ /* 870 */ 881, 881, 341, 1496, 313, 466, 116, 116, 116, 116,
+ /* 880 */ 115, 115, 114, 114, 114, 113, 422, 541, 1131, 1132,
+ /* 890 */ 1133, 541, 364, 541, 360, 116, 116, 116, 116, 115,
+ /* 900 */ 115, 114, 114, 114, 113, 422, 390, 264, 264, 13,
+ /* 910 */ 13, 273, 1131, 13, 13, 13, 13, 308, 1257, 390,
+ /* 920 */ 538, 1081, 1553, 408, 1416, 1553, 500, 277, 455, 186,
+ /* 930 */ 1256, 120, 110, 1152, 1152, 995, 998, 988, 988, 117,
+ /* 940 */ 117, 118, 118, 118, 118, 110, 1152, 1152, 995, 998,
+ /* 950 */ 988, 988, 117, 117, 118, 118, 118, 118, 105, 533,
+ /* 960 */ 541, 4, 1343, 264, 264, 1131, 1132, 1133, 1043, 1043,
+ /* 970 */ 463, 799, 800, 801, 540, 536, 538, 242, 305, 811,
+ /* 980 */ 307, 466, 69, 69, 455, 1357, 116, 116, 116, 116,
+ /* 990 */ 115, 115, 114, 114, 114, 113, 422, 1079, 423, 116,
+ /* 1000 */ 116, 116, 116, 115, 115, 114, 114, 114, 113, 422,
+ /* 1010 */ 530, 541, 1150, 192, 354, 105, 533, 541, 4, 501,
+ /* 1020 */ 162, 341, 1496, 314, 1253, 389, 1554, 376, 9, 466,
+ /* 1030 */ 242, 404, 536, 13, 13, 503, 975, 847, 440, 70,
+ /* 1040 */ 70, 363, 103, 103, 8, 343, 278, 187, 278, 104,
+ /* 1050 */ 1131, 423, 543, 542, 1343, 423, 965, 306, 1343, 1176,
+ /* 1060 */ 1, 1, 546, 2, 1180, 1150, 1150, 530, 480, 289,
+ /* 1070 */ 30, 134, 321, 288, 532, 285, 848, 1018, 1258, 276,
+ /* 1080 */ 1476, 510, 414, 1198, 6, 207, 509, 965, 965, 967,
+ /* 1090 */ 968, 27, 453, 975, 419, 418, 234, 233, 232, 103,
+ /* 1100 */ 103, 31, 1156, 1131, 1132, 1133, 104, 1158, 423, 543,
+ /* 1110 */ 542, 264, 264, 965, 1403, 1157, 264, 264, 1474, 1150,
+ /* 1120 */ 541, 216, 6, 405, 538, 1201, 396, 462, 410, 538,
+ /* 1130 */ 541, 489, 362, 541, 261, 541, 1343, 911, 219, 1159,
+ /* 1140 */ 471, 1159, 50, 50, 965, 965, 967, 968, 27, 1501,
+ /* 1150 */ 1120, 425, 70, 70, 268, 70, 70, 13, 13, 373,
+ /* 1160 */ 373, 372, 253, 370, 264, 264, 808, 235, 426, 105,
+ /* 1170 */ 533, 520, 4, 287, 491, 514, 497, 538, 490, 213,
+ /* 1180 */ 1059, 294, 494, 388, 1131, 454, 536, 342, 417, 293,
+ /* 1190 */ 526, 421, 339, 1040, 513, 1060, 107, 1040, 16, 16,
+ /* 1200 */ 1473, 1098, 338, 1109, 6, 415, 1149, 264, 264, 423,
+ /* 1210 */ 1061, 102, 515, 100, 1098, 264, 264, 1098, 926, 215,
+ /* 1220 */ 538, 530, 911, 264, 264, 208, 927, 154, 538, 461,
+ /* 1230 */ 156, 529, 395, 142, 218, 510, 538, 1131, 1132, 1133,
+ /* 1240 */ 511, 139, 1135, 38, 214, 534, 396, 975, 333, 1458,
+ /* 1250 */ 911, 1109, 541, 103, 103, 105, 533, 541, 4, 541,
+ /* 1260 */ 104, 428, 423, 543, 542, 541, 506, 965, 521, 541,
+ /* 1270 */ 1076, 541, 536, 377, 54, 54, 288, 532, 391, 55,
+ /* 1280 */ 55, 15, 15, 288, 532, 17, 136, 44, 44, 1455,
+ /* 1290 */ 541, 56, 56, 57, 57, 423, 1135, 291, 965, 965,
+ /* 1300 */ 967, 968, 27, 397, 163, 541, 430, 530, 263, 206,
+ /* 1310 */ 208, 521, 58, 58, 235, 444, 846, 845, 197, 105,
+ /* 1320 */ 533, 510, 4, 1037, 443, 1037, 509, 59, 59, 312,
+ /* 1330 */ 853, 854, 95, 975, 541, 911, 536, 952, 836, 103,
+ /* 1340 */ 103, 105, 533, 541, 4, 1025, 104, 541, 423, 543,
+ /* 1350 */ 542, 1120, 425, 965, 541, 268, 60, 60, 536, 423,
+ /* 1360 */ 373, 373, 372, 253, 370, 61, 61, 808, 969, 45,
+ /* 1370 */ 45, 530, 541, 1036, 1281, 1036, 46, 46, 541, 395,
+ /* 1380 */ 213, 423, 294, 266, 965, 965, 967, 968, 27, 292,
+ /* 1390 */ 293, 295, 836, 530, 48, 48, 1294, 975, 1293, 1025,
+ /* 1400 */ 49, 49, 436, 103, 103, 891, 957, 541, 1461, 241,
+ /* 1410 */ 104, 309, 423, 543, 542, 929, 930, 965, 448, 975,
+ /* 1420 */ 215, 241, 969, 1228, 541, 103, 103, 1435, 154, 62,
+ /* 1430 */ 62, 156, 104, 1434, 423, 543, 542, 97, 533, 965,
+ /* 1440 */ 4, 541, 458, 541, 318, 214, 63, 63, 965, 965,
+ /* 1450 */ 967, 968, 27, 541, 536, 450, 1290, 322, 241, 541,
+ /* 1460 */ 325, 327, 329, 64, 64, 14, 14, 1241, 541, 1227,
+ /* 1470 */ 965, 965, 967, 968, 27, 65, 65, 423, 541, 391,
+ /* 1480 */ 541, 125, 125, 541, 288, 532, 541, 1490, 541, 530,
+ /* 1490 */ 66, 66, 317, 528, 541, 95, 472, 1225, 1515, 237,
+ /* 1500 */ 51, 51, 67, 67, 334, 68, 68, 430, 52, 52,
+ /* 1510 */ 149, 149, 1226, 344, 345, 975, 150, 150, 1302, 467,
+ /* 1520 */ 331, 103, 103, 95, 541, 1342, 1277, 541, 104, 541,
+ /* 1530 */ 423, 543, 542, 1288, 541, 965, 268, 283, 527, 1348,
+ /* 1540 */ 1208, 373, 373, 372, 253, 370, 75, 75, 808, 53,
+ /* 1550 */ 53, 71, 71, 541, 1200, 541, 126, 126, 541, 1021,
+ /* 1560 */ 541, 213, 237, 294, 541, 1189, 965, 965, 967, 968,
+ /* 1570 */ 27, 293, 541, 1188, 541, 72, 72, 127, 127, 1190,
+ /* 1580 */ 128, 128, 124, 124, 1509, 541, 148, 148, 541, 256,
+ /* 1590 */ 195, 541, 1274, 541, 147, 147, 132, 132, 541, 11,
+ /* 1600 */ 541, 215, 541, 199, 347, 349, 351, 131, 131, 154,
+ /* 1610 */ 129, 129, 156, 130, 130, 74, 74, 541, 374, 300,
+ /* 1620 */ 76, 76, 73, 73, 43, 43, 214, 435, 211, 1335,
+ /* 1630 */ 304, 920, 884, 819, 241, 107, 137, 311, 885, 47,
+ /* 1640 */ 47, 107, 477, 382, 203, 452, 337, 1407, 1224, 1406,
+ /* 1650 */ 353, 190, 531, 191, 367, 198, 1512, 1167, 245, 165,
+ /* 1660 */ 391, 1454, 1452, 1164, 78, 288, 532, 1412, 81, 398,
+ /* 1670 */ 82, 446, 175, 122, 521, 159, 1332, 35, 1327, 299,
+ /* 1680 */ 167, 1324, 302, 93, 303, 438, 170, 171, 430, 172,
+ /* 1690 */ 173, 470, 439, 221, 379, 459, 1338, 445, 179, 225,
+ /* 1700 */ 1401, 87, 381, 36, 1423, 465, 320, 257, 227, 184,
+ /* 1710 */ 468, 324, 228, 384, 1191, 229, 483, 411, 1244, 1243,
+ /* 1720 */ 1242, 1235, 1216, 838, 385, 1215, 204, 336, 1495, 1214,
+ /* 1730 */ 413, 502, 1285, 1234, 1524, 281, 282, 92, 346, 493,
+ /* 1740 */ 496, 1286, 348, 243, 1284, 350, 244, 1283, 1481, 1480,
+ /* 1750 */ 416, 10, 1309, 361, 1387, 352, 99, 94, 286, 505,
+ /* 1760 */ 251, 1308, 1197, 34, 544, 1126, 252, 254, 255, 1267,
+ /* 1770 */ 1266, 359, 194, 365, 545, 366, 1186, 392, 1181, 1439,
+ /* 1780 */ 151, 1440, 1438, 1437, 152, 393, 135, 279, 200, 201,
+ /* 1790 */ 795, 77, 424, 153, 196, 164, 290, 210, 269, 133,
+ /* 1800 */ 1035, 1033, 166, 155, 949, 217, 220, 870, 168, 310,
+ /* 1810 */ 1049, 953, 174, 402, 157, 400, 83, 176, 84, 85,
+ /* 1820 */ 86, 158, 1052, 223, 222, 1048, 144, 18, 224, 1041,
+ /* 1830 */ 241, 319, 180, 1161, 226, 464, 181, 37, 810, 469,
+ /* 1840 */ 338, 230, 473, 849, 182, 88, 478, 19, 160, 332,
+ /* 1850 */ 20, 89, 280, 145, 90, 485, 492, 1114, 146, 1001,
+ /* 1860 */ 205, 1084, 39, 91, 1085, 40, 495, 260, 262, 919,
+ /* 1870 */ 185, 914, 107, 240, 1104, 7, 1100, 1102, 1108, 1088,
+ /* 1880 */ 33, 21, 1016, 22, 23, 24, 25, 517, 1107, 26,
+ /* 1890 */ 188, 95, 1002, 1000, 1004, 1058, 1005, 1057, 247, 246,
+ /* 1900 */ 28, 41, 880, 970, 820, 106, 29, 248, 537, 368,
+ /* 1910 */ 249, 1517, 371, 1121, 1177, 1177, 1177, 1516,
};
static const YYCODETYPE yy_lookahead[] = {
/* 0 */ 187, 187, 187, 216, 217, 187, 206, 187, 264, 265,
@@ -150369,31 +151142,31 @@ static const YYCODETYPE yy_lookahead[] =
/* 1640 */ 210, 26, 213, 238, 221, 283, 212, 212, 217, 212,
/* 1650 */ 251, 241, 270, 241, 237, 235, 190, 60, 137, 287,
/* 1660 */ 129, 194, 194, 38, 284, 134, 135, 273, 284, 194,
- /* 1670 */ 146, 111, 22, 43, 226, 145, 262, 261, 238, 18,
- /* 1680 */ 229, 229, 229, 229, 194, 18, 193, 238, 157, 262,
- /* 1690 */ 226, 226, 194, 238, 238, 193, 153, 261, 62, 280,
- /* 1700 */ 279, 194, 193, 22, 194, 214, 193, 111, 194, 193,
- /* 1710 */ 214, 211, 211, 64, 211, 211, 122, 211, 219, 214,
- /* 1720 */ 109, 213, 160, 211, 300, 140, 211, 253, 111, 272,
- /* 1730 */ 219, 214, 272, 214, 252, 194, 253, 252, 91, 253,
- /* 1740 */ 252, 82, 253, 305, 252, 144, 305, 141, 22, 194,
- /* 1750 */ 269, 257, 257, 153, 267, 143, 142, 25, 197, 26,
- /* 1760 */ 242, 241, 196, 240, 242, 239, 238, 13, 188, 188,
- /* 1770 */ 6, 293, 186, 186, 186, 200, 206, 293, 206, 206,
- /* 1780 */ 206, 4, 200, 215, 215, 207, 207, 3, 22, 206,
- /* 1790 */ 200, 158, 96, 15, 23, 16, 23, 135, 146, 126,
- /* 1800 */ 24, 138, 20, 16, 140, 1, 138, 147, 126, 61,
- /* 1810 */ 53, 37, 146, 53, 53, 290, 53, 126, 112, 34,
- /* 1820 */ 137, 1, 5, 22, 111, 156, 68, 68, 26, 41,
- /* 1830 */ 75, 137, 111, 24, 20, 19, 127, 121, 23, 67,
- /* 1840 */ 22, 22, 67, 22, 22, 37, 22, 67, 23, 145,
- /* 1850 */ 22, 28, 23, 23, 23, 137, 23, 22, 26, 22,
- /* 1860 */ 24, 23, 112, 24, 23, 23, 22, 139, 34, 26,
- /* 1870 */ 75, 88, 86, 75, 34, 23, 22, 24, 22, 34,
- /* 1880 */ 34, 34, 93, 34, 26, 26, 23, 23, 23, 34,
- /* 1890 */ 23, 23, 44, 23, 11, 26, 22, 22, 26, 23,
- /* 1900 */ 23, 22, 22, 15, 137, 137, 137, 137, 23, 1,
- /* 1910 */ 307, 307, 131, 307, 307, 307, 307, 307, 307, 307,
+ /* 1670 */ 146, 111, 22, 144, 141, 43, 262, 261, 242, 241,
+ /* 1680 */ 226, 242, 241, 145, 238, 18, 229, 229, 157, 229,
+ /* 1690 */ 229, 18, 194, 193, 238, 194, 226, 238, 226, 193,
+ /* 1700 */ 238, 153, 262, 261, 280, 62, 279, 194, 193, 22,
+ /* 1710 */ 214, 194, 193, 214, 194, 193, 111, 64, 211, 211,
+ /* 1720 */ 211, 219, 211, 122, 214, 213, 160, 211, 300, 211,
+ /* 1730 */ 109, 140, 253, 219, 211, 272, 272, 111, 252, 214,
+ /* 1740 */ 214, 253, 252, 194, 253, 252, 91, 253, 305, 305,
+ /* 1750 */ 82, 22, 257, 194, 267, 252, 153, 143, 269, 142,
+ /* 1760 */ 25, 257, 197, 26, 196, 13, 188, 188, 6, 242,
+ /* 1770 */ 242, 241, 240, 239, 186, 238, 186, 293, 186, 206,
+ /* 1780 */ 200, 206, 206, 206, 200, 293, 215, 215, 207, 207,
+ /* 1790 */ 4, 206, 3, 200, 22, 290, 158, 15, 96, 16,
+ /* 1800 */ 23, 23, 146, 126, 135, 24, 140, 20, 138, 16,
+ /* 1810 */ 1, 147, 138, 37, 126, 61, 53, 146, 53, 53,
+ /* 1820 */ 53, 126, 112, 137, 34, 1, 5, 22, 111, 68,
+ /* 1830 */ 26, 156, 68, 75, 137, 41, 111, 24, 20, 19,
+ /* 1840 */ 127, 121, 67, 28, 22, 22, 67, 22, 37, 23,
+ /* 1850 */ 22, 22, 67, 23, 145, 22, 24, 23, 23, 23,
+ /* 1860 */ 137, 23, 22, 26, 23, 22, 24, 23, 23, 112,
+ /* 1870 */ 22, 139, 26, 34, 75, 44, 88, 86, 75, 23,
+ /* 1880 */ 22, 34, 23, 34, 34, 34, 34, 24, 93, 34,
+ /* 1890 */ 26, 26, 23, 23, 23, 23, 11, 23, 22, 26,
+ /* 1900 */ 22, 22, 131, 23, 23, 22, 22, 137, 26, 23,
+ /* 1910 */ 137, 137, 15, 1, 307, 307, 307, 137, 307, 307,
/* 1920 */ 307, 307, 307, 307, 307, 307, 307, 307, 307, 307,
/* 1930 */ 307, 307, 307, 307, 307, 307, 307, 307, 307, 307,
/* 1940 */ 307, 307, 307, 307, 307, 307, 307, 307, 307, 307,
@@ -150411,11 +151184,11 @@ static const YYCODETYPE yy_lookahead[] =
/* 2060 */ 307, 307, 307, 307, 307, 307, 307, 307, 307, 307,
/* 2070 */ 307, 307, 307, 307, 307, 307, 307, 307, 307, 307,
/* 2080 */ 307, 307, 307, 307, 307, 307, 307, 307, 307, 307,
- /* 2090 */ 307, 307,
+ /* 2090 */ 307, 307, 307, 307, 307, 307, 307,
};
-#define YY_SHIFT_COUNT (542)
+#define YY_SHIFT_COUNT (546)
#define YY_SHIFT_MIN (0)
-#define YY_SHIFT_MAX (1908)
+#define YY_SHIFT_MAX (1912)
static const unsigned short int yy_shift_ofst[] = {
/* 0 */ 1350, 1149, 1531, 939, 939, 548, 996, 1150, 1236, 1322,
/* 10 */ 1322, 1322, 334, 0, 0, 178, 777, 1322, 1322, 1322,
@@ -150431,12 +151204,12 @@ static const unsigned short int yy_shift
/* 110 */ 1418, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322,
/* 120 */ 1322, 1322, 1322, 1322, 147, 254, 254, 254, 254, 254,
/* 130 */ 84, 185, 66, 853, 958, 1121, 853, 92, 92, 853,
- /* 140 */ 321, 321, 321, 321, 325, 350, 350, 461, 150, 1913,
- /* 150 */ 1913, 285, 285, 285, 236, 184, 349, 184, 184, 712,
+ /* 140 */ 321, 321, 321, 321, 325, 350, 350, 461, 150, 1918,
+ /* 150 */ 1918, 285, 285, 285, 236, 184, 349, 184, 184, 712,
/* 160 */ 712, 433, 553, 771, 899, 853, 853, 853, 853, 853,
/* 170 */ 853, 853, 853, 853, 853, 853, 853, 853, 853, 853,
/* 180 */ 853, 853, 853, 853, 853, 853, 46, 46, 853, 113,
- /* 190 */ 223, 223, 1183, 1183, 1127, 1142, 1913, 1913, 1913, 459,
+ /* 190 */ 223, 223, 1183, 1183, 1127, 1142, 1918, 1918, 1918, 459,
/* 200 */ 514, 514, 653, 495, 657, 305, 705, 560, 622, 776,
/* 210 */ 853, 853, 853, 853, 853, 853, 853, 853, 853, 545,
/* 220 */ 853, 853, 853, 853, 853, 853, 853, 853, 853, 853,
@@ -150446,36 +151219,36 @@ static const unsigned short int yy_shift
/* 260 */ 953, 953, 953, 1196, 738, 738, 45, 96, 964, 179,
/* 270 */ 580, 907, 907, 1073, 580, 580, 1073, 498, 388, 1268,
/* 280 */ 1187, 1187, 1187, 907, 1170, 1170, 1058, 1180, 328, 1219,
- /* 290 */ 1597, 1521, 1521, 1625, 1625, 1521, 1524, 1560, 1650, 1630,
- /* 300 */ 1530, 1661, 1661, 1661, 1661, 1521, 1667, 1530, 1530, 1560,
- /* 310 */ 1650, 1630, 1630, 1530, 1521, 1667, 1543, 1636, 1521, 1667,
- /* 320 */ 1681, 1521, 1667, 1521, 1667, 1681, 1596, 1596, 1596, 1649,
- /* 330 */ 1681, 1596, 1594, 1596, 1649, 1596, 1596, 1562, 1681, 1611,
- /* 340 */ 1611, 1681, 1585, 1617, 1585, 1617, 1585, 1617, 1585, 1617,
- /* 350 */ 1521, 1647, 1647, 1659, 1659, 1601, 1606, 1726, 1521, 1600,
- /* 360 */ 1601, 1612, 1614, 1530, 1732, 1733, 1754, 1754, 1764, 1764,
- /* 370 */ 1764, 1913, 1913, 1913, 1913, 1913, 1913, 1913, 1913, 1913,
- /* 380 */ 1913, 1913, 1913, 1913, 1913, 1913, 673, 901, 283, 740,
- /* 390 */ 707, 973, 655, 1247, 1048, 1097, 1190, 1306, 1263, 1383,
- /* 400 */ 1395, 1432, 1469, 1473, 1497, 1279, 1200, 1323, 1075, 1286,
- /* 410 */ 1536, 1608, 1332, 1609, 1175, 1225, 1610, 1615, 1309, 1361,
- /* 420 */ 1777, 1784, 1766, 1633, 1778, 1696, 1779, 1771, 1773, 1662,
- /* 430 */ 1652, 1673, 1776, 1663, 1782, 1664, 1787, 1804, 1668, 1660,
- /* 440 */ 1682, 1748, 1774, 1666, 1757, 1760, 1761, 1763, 1691, 1706,
- /* 450 */ 1785, 1683, 1820, 1817, 1801, 1713, 1669, 1758, 1802, 1759,
- /* 460 */ 1755, 1788, 1694, 1721, 1809, 1814, 1816, 1709, 1716, 1818,
- /* 470 */ 1772, 1819, 1821, 1815, 1822, 1775, 1823, 1824, 1780, 1808,
- /* 480 */ 1825, 1704, 1828, 1829, 1830, 1831, 1832, 1833, 1835, 1836,
- /* 490 */ 1838, 1837, 1839, 1718, 1841, 1842, 1750, 1834, 1844, 1728,
- /* 500 */ 1843, 1840, 1845, 1846, 1847, 1783, 1795, 1786, 1848, 1798,
- /* 510 */ 1789, 1849, 1852, 1854, 1853, 1858, 1859, 1855, 1863, 1843,
- /* 520 */ 1864, 1865, 1867, 1868, 1869, 1870, 1856, 1883, 1874, 1875,
- /* 530 */ 1876, 1877, 1879, 1880, 1872, 1781, 1767, 1768, 1769, 1770,
- /* 540 */ 1885, 1888, 1908,
+ /* 290 */ 1597, 1521, 1521, 1625, 1625, 1521, 1524, 1560, 1650, 1529,
+ /* 300 */ 1533, 1632, 1529, 1533, 1538, 1667, 1667, 1667, 1667, 1521,
+ /* 310 */ 1673, 1538, 1538, 1560, 1650, 1632, 1632, 1538, 1521, 1673,
+ /* 320 */ 1548, 1643, 1521, 1673, 1687, 1521, 1673, 1521, 1673, 1687,
+ /* 330 */ 1605, 1605, 1605, 1653, 1687, 1605, 1601, 1605, 1653, 1605,
+ /* 340 */ 1605, 1566, 1687, 1621, 1621, 1687, 1591, 1626, 1591, 1626,
+ /* 350 */ 1591, 1626, 1591, 1626, 1521, 1655, 1655, 1668, 1668, 1529,
+ /* 360 */ 1533, 1729, 1521, 1603, 1529, 1614, 1617, 1538, 1735, 1737,
+ /* 370 */ 1752, 1752, 1762, 1762, 1762, 1918, 1918, 1918, 1918, 1918,
+ /* 380 */ 1918, 1918, 1918, 1918, 1918, 1918, 1918, 1918, 1918, 1918,
+ /* 390 */ 673, 901, 283, 740, 707, 973, 655, 1247, 1048, 1097,
+ /* 400 */ 1190, 1306, 1263, 1383, 1395, 1432, 1469, 1473, 1497, 1279,
+ /* 410 */ 1200, 1323, 1075, 1286, 1536, 1608, 1332, 1609, 1175, 1225,
+ /* 420 */ 1610, 1615, 1309, 1361, 1786, 1789, 1772, 1638, 1782, 1702,
+ /* 430 */ 1783, 1777, 1778, 1669, 1656, 1677, 1781, 1670, 1787, 1666,
+ /* 440 */ 1793, 1809, 1674, 1664, 1688, 1754, 1776, 1671, 1763, 1765,
+ /* 450 */ 1766, 1767, 1695, 1710, 1790, 1686, 1824, 1821, 1805, 1717,
+ /* 460 */ 1675, 1761, 1804, 1764, 1758, 1794, 1697, 1725, 1813, 1818,
+ /* 470 */ 1820, 1713, 1720, 1822, 1775, 1823, 1825, 1826, 1828, 1779,
+ /* 480 */ 1815, 1829, 1785, 1811, 1830, 1709, 1833, 1834, 1835, 1836,
+ /* 490 */ 1837, 1838, 1840, 1832, 1841, 1843, 1842, 1723, 1844, 1845,
+ /* 500 */ 1757, 1839, 1848, 1732, 1846, 1847, 1849, 1850, 1851, 1788,
+ /* 510 */ 1799, 1791, 1831, 1803, 1795, 1852, 1856, 1858, 1863, 1864,
+ /* 520 */ 1865, 1855, 1859, 1846, 1869, 1870, 1871, 1872, 1873, 1874,
+ /* 530 */ 1876, 1885, 1878, 1879, 1880, 1881, 1883, 1884, 1882, 1771,
+ /* 540 */ 1770, 1773, 1774, 1780, 1886, 1897, 1912,
};
-#define YY_REDUCE_COUNT (385)
+#define YY_REDUCE_COUNT (389)
#define YY_REDUCE_MIN (-256)
-#define YY_REDUCE_MAX (1590)
+#define YY_REDUCE_MAX (1593)
static const short yy_reduce_ofst[] = {
/* 0 */ 880, -121, 269, 528, 933, -119, -187, -185, -182, -180,
/* 10 */ -176, -174, -62, -46, 131, -248, -133, 407, 568, 700,
@@ -150506,73 +151279,73 @@ static const short yy_reduce_ofst[] = {
/* 260 */ 1357, 1358, 1359, 1124, 1356, 1356, 1364, 1396, 1433, 1341,
/* 270 */ 1381, 1376, 1379, 1354, 1391, 1405, 1362, 1429, 1423, 1431,
/* 280 */ 1434, 1435, 1437, 1399, 1410, 1412, 1382, 1417, 1420, 1466,
- /* 290 */ 1372, 1467, 1468, 1380, 1384, 1475, 1394, 1414, 1416, 1448,
- /* 300 */ 1440, 1451, 1452, 1453, 1454, 1490, 1493, 1449, 1455, 1427,
- /* 310 */ 1436, 1464, 1465, 1456, 1498, 1502, 1419, 1421, 1507, 1509,
- /* 320 */ 1491, 1510, 1513, 1514, 1516, 1496, 1500, 1501, 1503, 1499,
- /* 330 */ 1505, 1504, 1508, 1506, 1511, 1512, 1515, 1424, 1517, 1457,
- /* 340 */ 1460, 1519, 1474, 1482, 1483, 1485, 1486, 1488, 1489, 1492,
- /* 350 */ 1541, 1438, 1441, 1494, 1495, 1518, 1520, 1487, 1555, 1481,
- /* 360 */ 1522, 1523, 1526, 1528, 1561, 1566, 1580, 1581, 1586, 1587,
- /* 370 */ 1588, 1478, 1484, 1525, 1575, 1570, 1572, 1573, 1574, 1582,
- /* 380 */ 1568, 1569, 1578, 1579, 1583, 1590,
+ /* 290 */ 1372, 1467, 1468, 1380, 1384, 1475, 1394, 1414, 1416, 1436,
+ /* 300 */ 1438, 1454, 1439, 1441, 1446, 1457, 1458, 1460, 1461, 1498,
+ /* 310 */ 1500, 1456, 1459, 1440, 1442, 1470, 1472, 1462, 1501, 1506,
+ /* 320 */ 1424, 1427, 1513, 1515, 1496, 1517, 1519, 1520, 1522, 1499,
+ /* 330 */ 1507, 1508, 1509, 1502, 1510, 1511, 1512, 1516, 1514, 1518,
+ /* 340 */ 1523, 1428, 1525, 1463, 1464, 1526, 1479, 1486, 1488, 1490,
+ /* 350 */ 1491, 1493, 1494, 1503, 1549, 1443, 1444, 1495, 1504, 1527,
+ /* 360 */ 1530, 1487, 1559, 1489, 1528, 1532, 1534, 1537, 1565, 1568,
+ /* 370 */ 1578, 1579, 1588, 1590, 1592, 1484, 1492, 1505, 1580, 1573,
+ /* 380 */ 1575, 1576, 1577, 1584, 1571, 1572, 1581, 1582, 1585, 1593,
};
static const YYACTIONTYPE yy_default[] = {
- /* 0 */ 1554, 1554, 1554, 1392, 1171, 1278, 1171, 1171, 1171, 1392,
- /* 10 */ 1392, 1392, 1171, 1308, 1308, 1445, 1202, 1171, 1171, 1171,
- /* 20 */ 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1391, 1171, 1171,
- /* 30 */ 1171, 1171, 1475, 1475, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 40 */ 1171, 1171, 1171, 1317, 1171, 1171, 1171, 1171, 1171, 1393,
- /* 50 */ 1394, 1171, 1171, 1171, 1444, 1446, 1409, 1327, 1326, 1325,
- /* 60 */ 1324, 1427, 1295, 1322, 1315, 1319, 1387, 1388, 1386, 1390,
- /* 70 */ 1394, 1393, 1171, 1318, 1358, 1372, 1357, 1171, 1171, 1171,
- /* 80 */ 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 90 */ 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 100 */ 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 110 */ 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 120 */ 1171, 1171, 1171, 1171, 1366, 1371, 1377, 1370, 1367, 1360,
- /* 130 */ 1359, 1361, 1362, 1171, 1192, 1242, 1171, 1171, 1171, 1171,
- /* 140 */ 1463, 1462, 1171, 1171, 1202, 1352, 1351, 1363, 1364, 1374,
- /* 150 */ 1373, 1452, 1510, 1509, 1410, 1171, 1171, 1171, 1171, 1171,
- /* 160 */ 1171, 1475, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 170 */ 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 180 */ 1171, 1171, 1171, 1171, 1171, 1171, 1475, 1475, 1171, 1202,
- /* 190 */ 1475, 1475, 1198, 1198, 1302, 1171, 1458, 1278, 1269, 1171,
- /* 200 */ 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 210 */ 1171, 1171, 1171, 1449, 1447, 1171, 1171, 1171, 1171, 1171,
- /* 220 */ 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 230 */ 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 240 */ 1171, 1171, 1171, 1274, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 250 */ 1171, 1171, 1171, 1171, 1171, 1504, 1171, 1422, 1256, 1274,
- /* 260 */ 1274, 1274, 1274, 1276, 1257, 1255, 1268, 1203, 1178, 1546,
- /* 270 */ 1321, 1297, 1297, 1543, 1321, 1321, 1543, 1217, 1524, 1214,
- /* 280 */ 1308, 1308, 1308, 1297, 1302, 1302, 1389, 1275, 1268, 1171,
- /* 290 */ 1546, 1283, 1283, 1545, 1545, 1283, 1410, 1330, 1336, 1245,
- /* 300 */ 1321, 1251, 1251, 1251, 1251, 1283, 1189, 1321, 1321, 1330,
- /* 310 */ 1336, 1245, 1245, 1321, 1283, 1189, 1426, 1540, 1283, 1189,
- /* 320 */ 1400, 1283, 1189, 1283, 1189, 1400, 1243, 1243, 1243, 1232,
- /* 330 */ 1400, 1243, 1217, 1243, 1232, 1243, 1243, 1493, 1400, 1404,
- /* 340 */ 1404, 1400, 1301, 1296, 1301, 1296, 1301, 1296, 1301, 1296,
- /* 350 */ 1283, 1485, 1485, 1311, 1311, 1316, 1302, 1395, 1283, 1171,
- /* 360 */ 1316, 1314, 1312, 1321, 1195, 1235, 1507, 1507, 1503, 1503,
- /* 370 */ 1503, 1551, 1551, 1458, 1519, 1202, 1202, 1202, 1202, 1519,
- /* 380 */ 1219, 1219, 1203, 1203, 1202, 1519, 1171, 1171, 1171, 1171,
- /* 390 */ 1171, 1171, 1514, 1171, 1411, 1287, 1171, 1171, 1171, 1171,
- /* 400 */ 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 410 */ 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1341,
- /* 420 */ 1171, 1174, 1455, 1171, 1171, 1453, 1171, 1171, 1171, 1171,
- /* 430 */ 1171, 1171, 1288, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 440 */ 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 450 */ 1171, 1542, 1171, 1171, 1171, 1171, 1171, 1171, 1425, 1424,
- /* 460 */ 1171, 1171, 1285, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 470 */ 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 480 */ 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 490 */ 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 500 */ 1313, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 510 */ 1171, 1171, 1171, 1171, 1171, 1490, 1303, 1171, 1171, 1533,
- /* 520 */ 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
- /* 530 */ 1171, 1171, 1171, 1171, 1528, 1259, 1343, 1171, 1342, 1346,
- /* 540 */ 1171, 1183, 1171,
+ /* 0 */ 1558, 1558, 1558, 1396, 1175, 1282, 1175, 1175, 1175, 1396,
+ /* 10 */ 1396, 1396, 1175, 1312, 1312, 1449, 1206, 1175, 1175, 1175,
+ /* 20 */ 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1395, 1175, 1175,
+ /* 30 */ 1175, 1175, 1479, 1479, 1175, 1175, 1175, 1175, 1175, 1175,
+ /* 40 */ 1175, 1175, 1175, 1321, 1175, 1175, 1175, 1175, 1175, 1397,
+ /* 50 */ 1398, 1175, 1175, 1175, 1448, 1450, 1413, 1331, 1330, 1329,
+ /* 60 */ 1328, 1431, 1299, 1326, 1319, 1323, 1391, 1392, 1390, 1394,
+ /* 70 */ 1398, 1397, 1175, 1322, 1362, 1376, 1361, 1175, 1175, 1175,
+ /* 80 */ 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175,
+ /* 90 */ 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175,
+ /* 100 */ 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175,
+ /* 110 */ 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175,
+ /* 120 */ 1175, 1175, 1175, 1175, 1370, 1375, 1381, 1374, 1371, 1364,
+ /* 130 */ 1363, 1365, 1366, 1175, 1196, 1246, 1175, 1175, 1175, 1175,
+ /* 140 */ 1467, 1466, 1175, 1175, 1206, 1356, 1355, 1367, 1368, 1378,
+ /* 150 */ 1377, 1456, 1514, 1513, 1414, 1175, 1175, 1175, 1175, 1175,
+ /* 160 */ 1175, 1479, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175,
+ /* 170 */ 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175,
+ /* 180 */ 1175, 1175, 1175, 1175, 1175, 1175, 1479, 1479, 1175, 1206,
+ /* 190 */ 1479, 1479, 1202, 1202, 1306, 1175, 1462, 1282, 1273, 1175,
+ /* 200 */ 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175,
+ /* 210 */ 1175, 1175, 1175, 1453, 1451, 1175, 1175, 1175, 1175, 1175,
+ /* 220 */ 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175,
+ /* 230 */ 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175,
+ /* 240 */ 1175, 1175, 1175, 1278, 1175, 1175, 1175, 1175, 1175, 1175,
+ /* 250 */ 1175, 1175, 1175, 1175, 1175, 1508, 1175, 1426, 1260, 1278,
+ /* 260 */ 1278, 1278, 1278, 1280, 1261, 1259, 1272, 1207, 1182, 1550,
+ /* 270 */ 1325, 1301, 1301, 1547, 1325, 1325, 1547, 1221, 1528, 1218,
+ /* 280 */ 1312, 1312, 1312, 1301, 1306, 1306, 1393, 1279, 1272, 1175,
+ /* 290 */ 1550, 1287, 1287, 1549, 1549, 1287, 1414, 1334, 1340, 1320,
+ /* 300 */ 1306, 1249, 1320, 1306, 1325, 1255, 1255, 1255, 1255, 1287,
+ /* 310 */ 1193, 1325, 1325, 1334, 1340, 1249, 1249, 1325, 1287, 1193,
+ /* 320 */ 1430, 1544, 1287, 1193, 1404, 1287, 1193, 1287, 1193, 1404,
+ /* 330 */ 1247, 1247, 1247, 1236, 1404, 1247, 1221, 1247, 1236, 1247,
+ /* 340 */ 1247, 1497, 1404, 1408, 1408, 1404, 1305, 1300, 1305, 1300,
+ /* 350 */ 1305, 1300, 1305, 1300, 1287, 1489, 1489, 1315, 1315, 1320,
+ /* 360 */ 1306, 1399, 1287, 1175, 1320, 1318, 1316, 1325, 1199, 1239,
+ /* 370 */ 1511, 1511, 1507, 1507, 1507, 1555, 1555, 1462, 1523, 1206,
+ /* 380 */ 1206, 1206, 1206, 1523, 1223, 1223, 1207, 1207, 1206, 1523,
+ /* 390 */ 1175, 1175, 1175, 1175, 1175, 1175, 1518, 1175, 1415, 1291,
+ /* 400 */ 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175,
+ /* 410 */ 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175,
+ /* 420 */ 1175, 1175, 1175, 1345, 1175, 1178, 1459, 1175, 1175, 1457,
+ /* 430 */ 1175, 1175, 1175, 1175, 1175, 1175, 1292, 1175, 1175, 1175,
+ /* 440 */ 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175,
+ /* 450 */ 1175, 1175, 1175, 1175, 1175, 1546, 1175, 1175, 1175, 1175,
+ /* 460 */ 1175, 1175, 1429, 1428, 1175, 1175, 1289, 1175, 1175, 1175,
+ /* 470 */ 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175,
+ /* 480 */ 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175,
+ /* 490 */ 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175,
+ /* 500 */ 1175, 1175, 1175, 1175, 1317, 1175, 1175, 1175, 1175, 1175,
+ /* 510 */ 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1494,
+ /* 520 */ 1307, 1175, 1175, 1537, 1175, 1175, 1175, 1175, 1175, 1175,
+ /* 530 */ 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1532, 1263,
+ /* 540 */ 1347, 1175, 1346, 1350, 1175, 1187, 1175,
};
/********** End of lemon-generated parsing tables *****************************/
@@ -151318,10 +152091,10 @@ static const char *const yyRuleName[] =
/* 143 */ "limit_opt ::= LIMIT expr",
/* 144 */ "limit_opt ::= LIMIT expr OFFSET expr",
/* 145 */ "limit_opt ::= LIMIT expr COMMA expr",
- /* 146 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt",
+ /* 146 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt orderby_opt limit_opt",
/* 147 */ "where_opt ::=",
/* 148 */ "where_opt ::= WHERE expr",
- /* 149 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt",
+ /* 149 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt orderby_opt limit_opt",
/* 150 */ "setlist ::= setlist COMMA nm EQ expr",
/* 151 */ "setlist ::= setlist COMMA LP idlist RP EQ expr",
/* 152 */ "setlist ::= nm EQ expr",
@@ -152206,10 +152979,10 @@ static const YYCODETYPE yyRuleInfoLhs[]
242, /* (143) limit_opt ::= LIMIT expr */
242, /* (144) limit_opt ::= LIMIT expr OFFSET expr */
242, /* (145) limit_opt ::= LIMIT expr COMMA expr */
- 184, /* (146) cmd ::= with DELETE FROM xfullname indexed_opt where_opt */
+ 184, /* (146) cmd ::= with DELETE FROM xfullname indexed_opt where_opt orderby_opt limit_opt */
238, /* (147) where_opt ::= */
238, /* (148) where_opt ::= WHERE expr */
- 184, /* (149) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */
+ 184, /* (149) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt orderby_opt limit_opt */
259, /* (150) setlist ::= setlist COMMA nm EQ expr */
259, /* (151) setlist ::= setlist COMMA LP idlist RP EQ expr */
259, /* (152) setlist ::= nm EQ expr */
@@ -152592,10 +153365,10 @@ static const signed char yyRuleInfoNRhs[
-2, /* (143) limit_opt ::= LIMIT expr */
-4, /* (144) limit_opt ::= LIMIT expr OFFSET expr */
-4, /* (145) limit_opt ::= LIMIT expr COMMA expr */
- -6, /* (146) cmd ::= with DELETE FROM xfullname indexed_opt where_opt */
+ -8, /* (146) cmd ::= with DELETE FROM xfullname indexed_opt where_opt orderby_opt limit_opt */
0, /* (147) where_opt ::= */
-2, /* (148) where_opt ::= WHERE expr */
- -8, /* (149) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */
+ -10, /* (149) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt orderby_opt limit_opt */
-5, /* (150) setlist ::= setlist COMMA nm EQ expr */
-7, /* (151) setlist ::= setlist COMMA LP idlist RP EQ expr */
-3, /* (152) setlist ::= nm EQ expr */
@@ -153511,17 +154284,21 @@ static YYACTIONTYPE yy_reduce(
case 145: /* limit_opt ::= LIMIT expr COMMA expr */
{yymsp[-3].minor.yy46 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy46,yymsp[-2].minor.yy46);}
break;
- case 146: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt */
+ case 146: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt orderby_opt limit_opt */
{
- sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy609, &yymsp[-1].minor.yy0);
- sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy609,yymsp[0].minor.yy46,0,0);
+ sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy609, &yymsp[-3].minor.yy0);
+#ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy138); yymsp[-1].minor.yy138 = 0;
+ sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy46); yymsp[0].minor.yy46 = 0;
+#endif
+ sqlite3DeleteFrom(pParse,yymsp[-4].minor.yy609,yymsp[-2].minor.yy46,yymsp[-1].minor.yy138,yymsp[0].minor.yy46);
}
break;
- case 149: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */
+ case 149: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt orderby_opt limit_opt */
{
- sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy609, &yymsp[-3].minor.yy0);
- sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy138,"set list");
- sqlite3Update(pParse,yymsp[-4].minor.yy609,yymsp[-1].minor.yy138,yymsp[0].minor.yy46,yymsp[-5].minor.yy32,0,0,0);
+ sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy609, &yymsp[-5].minor.yy0);
+ sqlite3ExprListCheckLength(pParse,yymsp[-3].minor.yy138,"set list");
+ sqlite3Update(pParse,yymsp[-6].minor.yy609,yymsp[-3].minor.yy138,yymsp[-2].minor.yy46,yymsp[-7].minor.yy32,yymsp[-1].minor.yy138,yymsp[0].minor.yy46,0);
}
break;
case 150: /* setlist ::= setlist COMMA nm EQ expr */
@@ -154323,7 +155100,7 @@ static YYACTIONTYPE yy_reduce(
break;
/********** End reduce actions ************************************************/
};
- assert( yyruleno<sizeof(yyRuleInfoLhs)/sizeof(yyRuleInfoLhs[0]) );
+ assert( (size_t)yyruleno<sizeof(yyRuleInfoLhs)/sizeof(yyRuleInfoLhs[0]) );
yygoto = yyRuleInfoLhs[yyruleno];
yysize = yyRuleInfoNRhs[yyruleno];
yyact = yy_find_reduce_action(yymsp[yysize].stateno,(YYCODETYPE)yygoto);
@@ -156259,7 +157036,7 @@ SQLITE_PRIVATE int sqlite3Fts5Init(sqlit
/* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant
** contains the text of SQLITE_VERSION macro.
*/
-SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
+const char sqlite3_version[] = SQLITE_VERSION;
#endif
/* IMPLEMENTATION-OF: R-53536-42575 The sqlite3_libversion() function returns
@@ -156305,7 +157082,7 @@ SQLITE_API int sqlite3_threadsafe(void){
** I/O active are written using this function. These messages
** are intended for debugging activity only.
*/
-SQLITE_API void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...) = 0;
+void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...) = 0;
#endif
/*
@@ -156315,7 +157092,7 @@ SQLITE_API void (SQLITE_CDECL *sqlite3Io
**
** See also the "PRAGMA temp_store_directory" SQL command.
*/
-SQLITE_API char *sqlite3_temp_directory = 0;
+char *sqlite3_temp_directory = 0;
/*
** If the following global variable points to a string which is the
@@ -156324,7 +157101,7 @@ SQLITE_API char *sqlite3_temp_directory
**
** See also the "PRAGMA data_store_directory" SQL command.
*/
-SQLITE_API char *sqlite3_data_directory = 0;
+char *sqlite3_data_directory = 0;
/*
** Initialize SQLite.
@@ -156639,7 +157416,7 @@ SQLITE_API int sqlite3_config(int op, ..
#endif
case SQLITE_CONFIG_MALLOC: {
- /* EVIDENCE-OF: R-55594-21030 The SQLITE_CONFIG_MALLOC option takes a
+ /* EVIDENCE-OF: R-55594-21030 The SQLITE_CONFIG_MALLOC2 option takes a
** single argument which is a pointer to an instance of the
** sqlite3_mem_methods structure. The argument specifies alternative
** low-level memory allocation routines to be used in place of the memory
@@ -156647,15 +157424,32 @@ SQLITE_API int sqlite3_config(int op, ..
sqlite3GlobalConfig.m = *va_arg(ap, sqlite3_mem_methods*);
break;
}
+ case SQLITE_CONFIG_MALLOC2: {
+ /* EVIDENCE-OF: R-55594-21030 The SQLITE_CONFIG_MALLOC2 option takes a
+ ** single argument which is a pointer to an instance of the
+ ** sqlite3_mem_methods2 structure. The argument specifies alternative
+ ** low-level memory allocation routines to be used in place of the memory
+ ** allocation routines built into SQLite. */
+ sqlite3GlobalConfig.m2 = *va_arg(ap, sqlite3_mem_methods2*);
+ break;
+ }
case SQLITE_CONFIG_GETMALLOC: {
- /* EVIDENCE-OF: R-51213-46414 The SQLITE_CONFIG_GETMALLOC option takes a
+ /* EVIDENCE-OF: R-51213-46414 The SQLITE_CONFIG_GETMALLOC2 option takes a
** single argument which is a pointer to an instance of the
** sqlite3_mem_methods structure. The sqlite3_mem_methods structure is
** filled with the currently defined memory allocation routines. */
- if( sqlite3GlobalConfig.m.xMalloc==0 ) sqlite3MemSetDefault();
*va_arg(ap, sqlite3_mem_methods*) = sqlite3GlobalConfig.m;
break;
}
+ case SQLITE_CONFIG_GETMALLOC2: {
+ /* EVIDENCE-OF: R-51213-46414 The SQLITE_CONFIG_GETMALLOC2 option takes a
+ ** single argument which is a pointer to an instance of the
+ ** sqlite3_mem_methods structure. The sqlite3_mem_methods structure is
+ ** filled with the currently defined memory allocation routines. */
+ if( sqlite3GlobalConfig.m2.xMalloc==0 ) sqlite3MemSetDefault();
+ *va_arg(ap, sqlite3_mem_methods2*) = sqlite3GlobalConfig.m2;
+ break;
+ }
case SQLITE_CONFIG_MEMSTATUS: {
/* EVIDENCE-OF: R-61275-35157 The SQLITE_CONFIG_MEMSTATUS option takes
** single argument of type int, interpreted as a boolean, which enables
@@ -156748,16 +157542,16 @@ SQLITE_API int sqlite3_config(int op, ..
** Setting sqlite3GlobalConfig.m to all zeros will cause malloc to
** revert to its default implementation when sqlite3_initialize() is run
*/
- memset(&sqlite3GlobalConfig.m, 0, sizeof(sqlite3GlobalConfig.m));
+ memset(&sqlite3GlobalConfig.m2, 0, sizeof(sqlite3GlobalConfig.m2));
}else{
/* EVIDENCE-OF: R-61006-08918 If the memory pointer is not NULL then the
** alternative memory allocator is engaged to handle all of SQLites
** memory allocation needs. */
#ifdef SQLITE_ENABLE_MEMSYS3
- sqlite3GlobalConfig.m = *sqlite3MemGetMemsys3();
+ sqlite3GlobalConfig.m2 = *sqlite3MemGetMemsys3();
#endif
#ifdef SQLITE_ENABLE_MEMSYS5
- sqlite3GlobalConfig.m = *sqlite3MemGetMemsys5();
+ sqlite3GlobalConfig.m2 = *sqlite3MemGetMemsys5();
#endif
}
break;
@@ -156857,6 +157651,19 @@ SQLITE_API int sqlite3_config(int op, ..
break;
}
+ case 64: /* SQLITE_CONFIG_EXPLAIN_COMMENTS */ {
+ /* Enable VDBE commenting (cannot be switched off) */
+ sqlite3GlobalConfig.bVdbeComments = 1;
+ break;
+ }
+
+ case 65: /* SQLITE_CONFIG_ENABLE_UNKOWN_SQL_FUNCTION */ {
+ /* Enable unknown sql function (cannot be switched off) */
+ sqlite3GlobalConfig.bEnableUnknownSqlFunction = 1;
+ break;
+ }
+
+
case SQLITE_CONFIG_STMTJRNL_SPILL: {
sqlite3GlobalConfig.nStmtSpill = va_arg(ap, int);
break;
@@ -157038,7 +157845,7 @@ SQLITE_API int sqlite3_db_config(sqlite3
case SQLITE_DBCONFIG_MAINDBNAME: {
/* IMP: R-06824-28531 */
/* IMP: R-36257-52125 */
- db->aDb[0].zDbSName = va_arg(ap,char*);
+ db->aDb[0].zDbSName = va_arg(ap,const char*);
rc = SQLITE_OK;
break;
}
@@ -157200,7 +158007,8 @@ SQLITE_API void sqlite3_set_last_insert_
/*
** Return the number of changes in the most recent call to sqlite3_exec().
*/
-SQLITE_API int sqlite3_changes(sqlite3 *db){
+#undef sqlite3_changes
+SQLITE_API u64 sqlite3_changes(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
@@ -157213,7 +158021,8 @@ SQLITE_API int sqlite3_changes(sqlite3 *
/*
** Return the number of changes since the database handle was opened.
*/
-SQLITE_API int sqlite3_total_changes(sqlite3 *db){
+#undef sqlite3_total_changes
+SQLITE_API u64 sqlite3_total_changes(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
@@ -158070,6 +158879,7 @@ static int createFunctionApi(
/*
** Create new user functions.
*/
+#undef sqlite3_create_function
SQLITE_API int sqlite3_create_function(
sqlite3 *db,
const char *zFunc,
@@ -158397,7 +159207,7 @@ SQLITE_PRIVATE int sqlite3WalDefaultHook
){
if( nFrame>=SQLITE_PTR_TO_INT(pClientData) ){
sqlite3BeginBenignMalloc();
- sqlite3_wal_checkpoint(db, zDb);
+ sqlite3_wal_checkpoint_v2(db, zDb, SQLITE_CHECKPOINT_PASSIVE, 0, 0);
sqlite3EndBenignMalloc();
}
return SQLITE_OK;
@@ -158525,6 +159335,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2
** to contains a zero-length string, all attached databases are
** checkpointed.
*/
+#undef sqlite3_wal_checkpoint
SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
/* EVIDENCE-OF: R-41613-20553 The sqlite3_wal_checkpoint(D,X) is equivalent to
** sqlite3_wal_checkpoint_v2(D,X,SQLITE_CHECKPOINT_PASSIVE,0,0). */
@@ -158955,14 +159766,14 @@ SQLITE_PRIVATE int sqlite3ParseUri(
int eState; /* Parser state when parsing URI */
int iIn; /* Input character index */
int iOut = 0; /* Output character index */
- u64 nByte = nUri+2; /* Bytes of space to allocate */
+ size_t nByte = nUri+2; /* Bytes of space to allocate */
/* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen
** method that there may be extra parameters following the file-name. */
flags |= SQLITE_OPEN_URI;
for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&');
- zFile = sqlite3_malloc64(nByte);
+ zFile = sqlite3Malloc(nByte);
if( !zFile ) return SQLITE_NOMEM_BKPT;
iIn = 5;
@@ -159065,21 +159876,21 @@ SQLITE_PRIVATE int sqlite3ParseUri(
while( zOpt[0] ){
int nOpt = sqlite3Strlen30(zOpt);
char *zVal = &zOpt[nOpt+1];
- int nVal = sqlite3Strlen30(zVal);
+ size_t nVal = sqlite3Strlen30(zVal);
if( nOpt==3 && memcmp("vfs", zOpt, 3)==0 ){
zVfs = zVal;
}else{
- struct OpenMode {
+ const struct OpenMode {
const char *z;
int mode;
} *aMode = 0;
- char *zModeType = 0;
+ const char *zModeType = 0;
int mask = 0;
int limit = 0;
if( nOpt==5 && memcmp("cache", zOpt, 5)==0 ){
- static struct OpenMode aCacheMode[] = {
+ static const struct OpenMode aCacheMode[] = {
{ "shared", SQLITE_OPEN_SHAREDCACHE },
{ "private", SQLITE_OPEN_PRIVATECACHE },
{ 0, 0 }
@@ -159091,7 +159902,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
zModeType = "cache";
}
if( nOpt==4 && memcmp("mode", zOpt, 4)==0 ){
- static struct OpenMode aOpenMode[] = {
+ static const struct OpenMode aOpenMode[] = {
{ "ro", SQLITE_OPEN_READONLY },
{ "rw", SQLITE_OPEN_READWRITE },
{ "rwc", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE },
@@ -159135,7 +159946,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
}
}else{
- zFile = sqlite3_malloc64(nUri+2);
+ zFile = sqlite3Malloc(nUri+2);
if( !zFile ) return SQLITE_NOMEM_BKPT;
if( nUri ){
memcpy(zFile, zUri, nUri);
@@ -159332,9 +160143,6 @@ static int openDatabase(
#if SQLITE_DEFAULT_FILE_FORMAT<4
| SQLITE_LegacyFileFmt
#endif
-#ifdef SQLITE_ENABLE_LOAD_EXTENSION
- | SQLITE_LoadExtension
-#endif
#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS
| SQLITE_RecTriggers
#endif
@@ -159637,6 +160445,7 @@ SQLITE_API int sqlite3_open16(
/*
** Register a new collation sequence with the database handle db.
*/
+#undef sqlite3_create_collation
SQLITE_API int sqlite3_create_collation(
sqlite3* db,
const char *zName,
@@ -159748,6 +160557,7 @@ SQLITE_API int sqlite3_collation_needed1
** This function is now an anachronism. It used to be used to recover from a
** malloc() failure, but SQLite now does this automatically.
*/
+#undef sqlite3_global_recover
SQLITE_API int sqlite3_global_recover(void){
return SQLITE_OK;
}
@@ -159822,6 +160632,7 @@ SQLITE_PRIVATE int sqlite3IoerrnomemErro
** SQLite no longer uses thread-specific data so this routine is now a
** no-op. It is retained for historical compatibility.
*/
+#undef sqlite3_thread_cleanup
SQLITE_API void sqlite3_thread_cleanup(void){
}
#endif
@@ -160249,6 +161060,7 @@ SQLITE_API int sqlite3_test_control(int
break;
}
+#ifndef SQLITE_UNTESTABLE
/* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff);
**
** If parameter onoff is non-zero, subsequent calls to localtime()
@@ -160258,6 +161070,7 @@ SQLITE_API int sqlite3_test_control(int
sqlite3GlobalConfig.bLocaltimeFault = va_arg(ap, int);
break;
}
+#endif
/* sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCS, int onoff);
**
@@ -161671,10 +162484,10 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3
#ifndef MIN
-# define MIN(x,y) ((x)<(y)?(x):(y))
+# define MIN(A,B) ((A)<(B)?(A):(B))
#endif
#ifndef MAX
-# define MAX(x,y) ((x)>(y)?(x):(y))
+# define MAX(A,B) ((A)>(B)?(A):(B))
#endif
/*
@@ -162216,6 +163029,8 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold
SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int);
SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int);
#endif
+#define sqlite3Fts5UnicodeIsdiacritic sqlite3FtsUnicodeIsdiacritic
+#define sqlite3Fts5UnicodeFold sqlite3FtsUnicodeFold
#endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */
#endif /* _FTSINT_H */
@@ -162757,10 +163572,10 @@ static void fts3Appendf(
** memory.
*/
static char *fts3QuoteId(char const *zInput){
- sqlite3_int64 nRet;
+ size_t nRet;
char *zRet;
- nRet = 2 + (int)strlen(zInput)*2 + 1;
- zRet = sqlite3_malloc64(nRet);
+ nRet = 2 + strlen(zInput)*2 + 1;
+ zRet = sqlite3_malloc(nRet);
if( zRet ){
int i;
char *z = zRet;
@@ -162801,14 +163616,14 @@ static char *fts3QuoteId(char const *zIn
static char *fts3ReadExprList(Fts3Table *p, const char *zFunc, int *pRc){
char *zRet = 0;
char *zFree = 0;
- char *zFunction;
+ const char *zFunction;
int i;
if( p->zContentTbl==0 ){
if( !zFunc ){
zFunction = "";
}else{
- zFree = zFunction = fts3QuoteId(zFunc);
+ zFunction = zFree = fts3QuoteId(zFunc);
}
fts3Appendf(pRc, &zRet, "docid");
for(i=0; i<p->nColumn; i++){
@@ -162858,13 +163673,13 @@ static char *fts3ReadExprList(Fts3Table
static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){
char *zRet = 0;
char *zFree = 0;
- char *zFunction;
+ const char *zFunction;
int i;
if( !zFunc ){
zFunction = "";
}else{
- zFree = zFunction = fts3QuoteId(zFunc);
+ zFunction = zFree = fts3QuoteId(zFunc);
}
fts3Appendf(pRc, &zRet, "?");
for(i=0; i<p->nColumn; i++){
@@ -162941,7 +163756,7 @@ static int fts3PrefixParameter(
}
}
- aIndex = sqlite3_malloc64(sizeof(struct Fts3Index) * nIndex);
+ aIndex = sqlite3_malloc(sizeof(struct Fts3Index) * nIndex);
*apIndex = aIndex;
if( !aIndex ){
return SQLITE_NOMEM;
@@ -163034,7 +163849,7 @@ static int fts3ContentColumns(
}
/* Allocate and populate the array to return. */
- azCol = (const char **)sqlite3_malloc64(sizeof(char *) * nCol + nStr);
+ azCol = (const char **)sqlite3_malloc(sizeof(char *) * nCol + nStr);
if( azCol==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -163082,7 +163897,7 @@ static int fts3InitVtab(
Fts3Table *p = 0; /* Pointer to allocated vtab */
int rc = SQLITE_OK; /* Return code */
int i; /* Iterator variable */
- sqlite3_int64 nByte; /* Size of allocation used for *p */
+ size_t nByte; /* Size of allocation used for *p */
int iCol; /* Column index */
int nString = 0; /* Bytes required to hold all column names */
int nCol = 0; /* Number of columns in the FTS table */
@@ -163116,10 +163931,10 @@ static int fts3InitVtab(
nName = (int)strlen(argv[2]) + 1;
nByte = sizeof(const char *) * (argc-2);
- aCol = (const char **)sqlite3_malloc64(nByte);
+ aCol = (const char **)sqlite3_malloc(nByte);
if( aCol ){
memset((void*)aCol, 0, nByte);
- azNotindexed = (char **)sqlite3_malloc64(nByte);
+ azNotindexed = (char **)sqlite3_malloc(nByte);
}
if( azNotindexed ){
memset(azNotindexed, 0, nByte);
@@ -163314,7 +164129,7 @@ static int fts3InitVtab(
nName + /* zName */
nDb + /* zDb */
nString; /* Space for azColumn strings */
- p = (Fts3Table*)sqlite3_malloc64(nByte);
+ p = (Fts3Table*)sqlite3_malloc(nByte);
if( p==0 ){
rc = SQLITE_NOMEM;
goto fts3_init_out;
@@ -163614,9 +164429,9 @@ static int fts3BestIndexMethod(sqlite3_v
struct sqlite3_index_orderby *pOrder = &pInfo->aOrderBy[0];
if( pOrder->iColumn<0 || pOrder->iColumn==p->nColumn+1 ){
if( pOrder->desc ){
- pInfo->idxStr = "DESC";
+ pInfo->idxStr = (char *)"DESC";
}else{
- pInfo->idxStr = "ASC";
+ pInfo->idxStr = (char *)"ASC";
}
pInfo->orderByConsumed = 1;
}
@@ -164503,7 +165318,7 @@ static int fts3DoclistOrMerge(
** A symetric argument may be made if the doclists are in descending
** order.
*/
- aOut = sqlite3_malloc64((i64)n1+n2+FTS3_VARINT_MAX-1+FTS3_BUFFER_PADDING);
+ aOut = sqlite3_malloc((size_t)n1+n2+FTS3_VARINT_MAX-1+FTS3_BUFFER_PADDING);
if( !aOut ) return SQLITE_NOMEM;
p = aOut;
@@ -164575,7 +165390,7 @@ static int fts3DoclistPhraseMerge(
assert( nDist>0 );
if( bDescDoclist ){
- aOut = sqlite3_malloc64((sqlite3_int64)*pnRight + FTS3_VARINT_MAX);
+ aOut = sqlite3_malloc((size_t)*pnRight + FTS3_VARINT_MAX);
if( aOut==0 ) return SQLITE_NOMEM;
}else{
aOut = aRight;
@@ -165933,6 +166748,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlit
#ifndef SQLITE_DISABLE_FTS3_UNICODE
|| sqlite3Fts3HashInsert(pHash, "unicode61", 10, (void *)pUnicode)
+ || sqlite3Fts3HashInsert(pHash, "unicode", 8, (void *)pUnicode)
#endif
#ifdef SQLITE_ENABLE_ICU
|| (pIcu && sqlite3Fts3HashInsert(pHash, "icu", 4, (void *)pIcu))
@@ -166974,7 +167790,7 @@ static int fts3EvalStart(Fts3Cursor *pCs
if( rc==SQLITE_OK && nToken>1 && pTab->bFts4 ){
Fts3TokenAndCost *aTC;
Fts3Expr **apOr;
- aTC = (Fts3TokenAndCost *)sqlite3_malloc64(
+ aTC = (Fts3TokenAndCost *)sqlite3_malloc(
sizeof(Fts3TokenAndCost) * nToken
+ sizeof(Fts3Expr *) * nOr * 2
);
@@ -167285,7 +168101,7 @@ static int fts3EvalNearTest(Fts3Expr *pE
&& (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR)
){
Fts3Expr *p;
- sqlite3_int64 nTmp = 0; /* Bytes of temp space */
+ size_t nTmp = 0; /* Bytes of temp space */
char *aTmp; /* Temp space for PoslistNearMerge() */
/* Allocate temporary working space. */
@@ -167294,7 +168110,7 @@ static int fts3EvalNearTest(Fts3Expr *pE
nTmp += p->pRight->pPhrase->doclist.nList;
}
nTmp += p->pPhrase->doclist.nList;
- aTmp = sqlite3_malloc64(nTmp*2);
+ aTmp = sqlite3_malloc(nTmp*2);
if( !aTmp ){
*pRc = SQLITE_NOMEM;
res = 0;
@@ -167635,7 +168451,7 @@ static int fts3EvalGatherStats(
for(p=pRoot; p; p=p->pLeft){
Fts3Expr *pE = (p->eType==FTSQUERY_PHRASE?p:p->pRight);
assert( pE->aMI==0 );
- pE->aMI = (u32 *)sqlite3_malloc64(pTab->nColumn * 3 * sizeof(u32));
+ pE->aMI = (u32 *)sqlite3_malloc(pTab->nColumn * 3 * sizeof(u32));
if( !pE->aMI ) return SQLITE_NOMEM;
memset(pE->aMI, 0, pTab->nColumn * 3 * sizeof(u32));
}
@@ -168011,7 +168827,7 @@ static int fts3auxConnectMethod(
char const *zFts3; /* Name of fts3 table */
int nDb; /* Result of strlen(zDb) */
int nFts3; /* Result of strlen(zFts3) */
- sqlite3_int64 nByte; /* Bytes of space to allocate here */
+ size_t nByte; /* Bytes of space to allocate here */
int rc; /* value returned by declare_vtab() */
Fts3auxTable *p; /* Virtual table object to return */
@@ -168043,7 +168859,7 @@ static int fts3auxConnectMethod(
if( rc!=SQLITE_OK ) return rc;
nByte = sizeof(Fts3auxTable) + sizeof(Fts3Table) + nDb + nFts3 + 2;
- p = (Fts3auxTable *)sqlite3_malloc64(nByte);
+ p = (Fts3auxTable *)sqlite3_malloc(nByte);
if( !p ) return SQLITE_NOMEM;
memset(p, 0, nByte);
@@ -168489,7 +169305,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitAux(sq
};
int rc; /* Return code */
- rc = sqlite3_create_module(db, "fts4aux", &fts3aux_module, 0);
+ rc = sqlite3_create_module_v2(db, "fts4aux", &fts3aux_module, 0, 0);
return rc;
}
@@ -168621,8 +169437,8 @@ static int fts3isspace(char c){
** zero the memory before returning a pointer to it. If unsuccessful,
** return NULL.
*/
-static void *fts3MallocZero(sqlite3_int64 nByte){
- void *pRet = sqlite3_malloc64(nByte);
+static void *fts3MallocZero(size_t nByte){
+ void *pRet = sqlite3_malloc(nByte);
if( pRet ) memset(pRet, 0, nByte);
return pRet;
}
@@ -168896,7 +169712,7 @@ static int getNextNode(
int *pnConsumed /* OUT: Number of bytes consumed */
){
static const struct Fts3Keyword {
- char *z; /* Keyword text */
+ const char *z; /* Keyword text */
unsigned char n; /* Length of the keyword */
unsigned char parenOnly; /* Only valid in paren mode */
unsigned char eType; /* Keyword code */
@@ -169294,7 +170110,7 @@ static int fts3ExprBalance(Fts3Expr **pp
if( rc==SQLITE_OK ){
if( (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){
Fts3Expr **apLeaf;
- apLeaf = (Fts3Expr **)sqlite3_malloc64(sizeof(Fts3Expr *) * nMaxDepth);
+ apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth);
if( 0==apLeaf ){
rc = SQLITE_NOMEM;
}else{
@@ -169714,7 +170530,7 @@ static void fts3ExprTestCommon(
zExpr = (const char *)sqlite3_value_text(argv[1]);
nExpr = sqlite3_value_bytes(argv[1]);
nCol = argc-2;
- azCol = (char **)sqlite3_malloc64(nCol*sizeof(char *));
+ azCol = (char **)sqlite3_malloc(nCol*sizeof(char *));
if( !azCol ){
sqlite3_result_error_nomem(context);
goto exprtest_out;
@@ -169828,8 +170644,8 @@ SQLITE_PRIVATE int sqlite3Fts3ExprInitTe
/*
** Malloc and Free functions
*/
-static void *fts3HashMalloc(sqlite3_int64 n){
- void *p = sqlite3_malloc64(n);
+static void *fts3HashMalloc(size_t n){
+ void *p = sqlite3_malloc(n);
if( p ){
memset(p, 0, n);
}
@@ -171168,7 +171984,7 @@ static void testFunc(
}
while( SQLITE_OK==p->xNext(pCsr, &zToken, &nToken, &iStart, &iEnd, &iPos) ){
- Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(iPos));
+ Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(iPos));
Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zToken, nToken));
zToken = &zInput[iStart];
nToken = iEnd-iStart;
@@ -171717,14 +172533,14 @@ static int fts3tokDequoteArray(
*pazDequote = 0;
}else{
int i;
- int nByte = 0;
+ size_t nByte = 0;
char **azDequote;
for(i=0; i<argc; i++){
- nByte += (int)(strlen(argv[i]) + 1);
+ nByte += strlen(argv[i]) + 1;
}
- *pazDequote = azDequote = sqlite3_malloc64(sizeof(char *)*argc + nByte);
+ *pazDequote = azDequote = sqlite3_malloc(sizeof(char *)*argc + nByte);
if( azDequote==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -172050,7 +172866,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitTok(sq
};
int rc; /* Return code */
- rc = sqlite3_create_module(db, "fts3tokenize", &fts3tok_module, (void*)pHash);
+ rc = sqlite3_create_module_v2(db, "fts3tokenize", &fts3tok_module, (void*)pHash, 0);
return rc;
}
@@ -172350,7 +173166,7 @@ static int fts3SqlStmt(
sqlite3_stmt **pp, /* OUT: Statement handle */
sqlite3_value **apVal /* Values to bind to statement */
){
- const char *azSql[] = {
+ const char *const azSql[] = {
/* 0 */ "DELETE FROM %Q.'%q_content' WHERE rowid = ?",
/* 1 */ "SELECT NOT EXISTS(SELECT docid FROM %Q.'%q_content' WHERE rowid!=?)",
/* 2 */ "DELETE FROM %Q.'%q_content'",
@@ -177969,7 +178785,7 @@ static void (*fts3MIBufferAlloc(Matchinf
aOut = &p->aMatchinfo[p->nElem+2];
xRet = fts3MIBufferFree;
}else{
- aOut = (u32*)sqlite3_malloc64(p->nElem * sizeof(u32));
+ aOut = (u32*)sqlite3_malloc(p->nElem * sizeof(u32));
if( aOut ){
xRet = sqlite3_free;
if( p->bGlobal ) memcpy(aOut, &p->aMatchinfo[1], p->nElem*sizeof(u32));
@@ -178329,7 +179145,7 @@ static int fts3BestSnippet(
** the required space using malloc().
*/
nByte = sizeof(SnippetPhrase) * nList;
- sIter.aPhrase = (SnippetPhrase *)sqlite3_malloc64(nByte);
+ sIter.aPhrase = (SnippetPhrase *)sqlite3_malloc(nByte);
if( !sIter.aPhrase ){
return SQLITE_NOMEM;
}
@@ -178922,7 +179738,7 @@ static int fts3MatchinfoLcs(Fts3Cursor *
/* Allocate and populate the array of LcsIterator objects. The array
** contains one element for each matchable phrase in the query.
**/
- aIter = sqlite3_malloc64(sizeof(LcsIterator) * pCsr->nPhrase);
+ aIter = sqlite3_malloc(sizeof(LcsIterator) * pCsr->nPhrase);
if( !aIter ) return SQLITE_NOMEM;
memset(aIter, 0, sizeof(LcsIterator) * pCsr->nPhrase);
(void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
@@ -179375,7 +180191,7 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
if( rc!=SQLITE_OK ) goto offsets_out;
/* Allocate the array of TermOffset iterators. */
- sCtx.aTerm = (TermOffset *)sqlite3_malloc64(sizeof(TermOffset)*nToken);
+ sCtx.aTerm = (TermOffset *)sqlite3_malloc(sizeof(TermOffset)*nToken);
if( 0==sCtx.aTerm ){
rc = SQLITE_NOMEM;
goto offsets_out;
@@ -179961,84 +180777,105 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsal
0x0002D001, 0x0002D803, 0x0002EC01, 0x0002FC01, 0x00035C01,
0x0003DC01, 0x000B0804, 0x000B480E, 0x000B9407, 0x000BB401,
0x000BBC81, 0x000DD401, 0x000DF801, 0x000E1002, 0x000E1C01,
- 0x000FD801, 0x00120808, 0x00156806, 0x00162402, 0x00163C01,
- 0x00164437, 0x0017CC02, 0x00180005, 0x00181816, 0x00187802,
- 0x00192C15, 0x0019A804, 0x0019C001, 0x001B5001, 0x001B580F,
- 0x001B9C07, 0x001BF402, 0x001C000E, 0x001C3C01, 0x001C4401,
- 0x001CC01B, 0x001E980B, 0x001FAC09, 0x001FD804, 0x00205804,
+ 0x000FD801, 0x00120808, 0x00156806, 0x00162402, 0x00163403,
+ 0x00164437, 0x0017CC02, 0x0018001D, 0x00187802, 0x00192C15,
+ 0x0019A804, 0x0019C001, 0x001B5001, 0x001B580F, 0x001B9C07,
+ 0x001BF402, 0x001C000E, 0x001C3C01, 0x001C4401, 0x001CC01B,
+ 0x001E980B, 0x001FAC09, 0x001FD804, 0x001FF403, 0x00205804,
0x00206C09, 0x00209403, 0x0020A405, 0x0020C00F, 0x00216403,
- 0x00217801, 0x0023901B, 0x00240004, 0x0024E803, 0x0024F812,
- 0x00254407, 0x00258804, 0x0025C001, 0x00260403, 0x0026F001,
- 0x0026F807, 0x00271C02, 0x00272C03, 0x00275C01, 0x00278802,
- 0x0027C802, 0x0027E802, 0x00280403, 0x0028F001, 0x0028F805,
- 0x00291C02, 0x00292C03, 0x00294401, 0x0029C002, 0x0029D401,
+ 0x00217801, 0x00234C31, 0x0024E803, 0x0024F812, 0x00254407,
+ 0x00258804, 0x0025C001, 0x00260403, 0x0026F001, 0x0026F807,
+ 0x00271C02, 0x00272C03, 0x00275C01, 0x00278802, 0x0027C802,
+ 0x0027E802, 0x0027F402, 0x00280403, 0x0028F001, 0x0028F805,
+ 0x00291C02, 0x00292C03, 0x00294401, 0x0029C002, 0x0029D402,
0x002A0403, 0x002AF001, 0x002AF808, 0x002B1C03, 0x002B2C03,
- 0x002B8802, 0x002BC002, 0x002C0403, 0x002CF001, 0x002CF807,
- 0x002D1C02, 0x002D2C03, 0x002D5802, 0x002D8802, 0x002DC001,
- 0x002E0801, 0x002EF805, 0x002F1803, 0x002F2804, 0x002F5C01,
- 0x002FCC08, 0x00300403, 0x0030F807, 0x00311803, 0x00312804,
- 0x00315402, 0x00318802, 0x0031FC01, 0x00320802, 0x0032F001,
- 0x0032F807, 0x00331803, 0x00332804, 0x00335402, 0x00338802,
- 0x00340802, 0x0034F807, 0x00351803, 0x00352804, 0x00355C01,
- 0x00358802, 0x0035E401, 0x00360802, 0x00372801, 0x00373C06,
- 0x00375801, 0x00376008, 0x0037C803, 0x0038C401, 0x0038D007,
- 0x0038FC01, 0x00391C09, 0x00396802, 0x003AC401, 0x003AD006,
- 0x003AEC02, 0x003B2006, 0x003C041F, 0x003CD00C, 0x003DC417,
- 0x003E340B, 0x003E6424, 0x003EF80F, 0x003F380D, 0x0040AC14,
- 0x00412806, 0x00415804, 0x00417803, 0x00418803, 0x00419C07,
- 0x0041C404, 0x0042080C, 0x00423C01, 0x00426806, 0x0043EC01,
- 0x004D740C, 0x004E400A, 0x00500001, 0x0059B402, 0x005A0001,
- 0x005A6C02, 0x005BAC03, 0x005C4803, 0x005CC805, 0x005D4802,
- 0x005DC802, 0x005ED023, 0x005F6004, 0x005F7401, 0x0060000F,
- 0x0062A401, 0x0064800C, 0x0064C00C, 0x00650001, 0x00651002,
- 0x0066C011, 0x00672002, 0x00677822, 0x00685C05, 0x00687802,
- 0x0069540A, 0x0069801D, 0x0069FC01, 0x006A8007, 0x006AA006,
- 0x006C0005, 0x006CD011, 0x006D6823, 0x006E0003, 0x006E840D,
- 0x006F980E, 0x006FF004, 0x00709014, 0x0070EC05, 0x0071F802,
- 0x00730008, 0x00734019, 0x0073B401, 0x0073C803, 0x00770027,
- 0x0077F004, 0x007EF401, 0x007EFC03, 0x007F3403, 0x007F7403,
- 0x007FB403, 0x007FF402, 0x00800065, 0x0081A806, 0x0081E805,
- 0x00822805, 0x0082801A, 0x00834021, 0x00840002, 0x00840C04,
- 0x00842002, 0x00845001, 0x00845803, 0x00847806, 0x00849401,
- 0x00849C01, 0x0084A401, 0x0084B801, 0x0084E802, 0x00850005,
- 0x00852804, 0x00853C01, 0x00864264, 0x00900027, 0x0091000B,
- 0x0092704E, 0x00940200, 0x009C0475, 0x009E53B9, 0x00AD400A,
- 0x00B39406, 0x00B3BC03, 0x00B3E404, 0x00B3F802, 0x00B5C001,
- 0x00B5FC01, 0x00B7804F, 0x00B8C00C, 0x00BA001A, 0x00BA6C59,
- 0x00BC00D6, 0x00BFC00C, 0x00C00005, 0x00C02019, 0x00C0A807,
- 0x00C0D802, 0x00C0F403, 0x00C26404, 0x00C28001, 0x00C3EC01,
- 0x00C64002, 0x00C6580A, 0x00C70024, 0x00C8001F, 0x00C8A81E,
- 0x00C94001, 0x00C98020, 0x00CA2827, 0x00CB003F, 0x00CC0100,
- 0x01370040, 0x02924037, 0x0293F802, 0x02983403, 0x0299BC10,
- 0x029A7C01, 0x029BC008, 0x029C0017, 0x029C8002, 0x029E2402,
- 0x02A00801, 0x02A01801, 0x02A02C01, 0x02A08C09, 0x02A0D804,
- 0x02A1D004, 0x02A20002, 0x02A2D011, 0x02A33802, 0x02A38012,
- 0x02A3E003, 0x02A4980A, 0x02A51C0D, 0x02A57C01, 0x02A60004,
- 0x02A6CC1B, 0x02A77802, 0x02A8A40E, 0x02A90C01, 0x02A93002,
- 0x02A97004, 0x02A9DC03, 0x02A9EC01, 0x02AAC001, 0x02AAC803,
- 0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802, 0x02ABAC07,
- 0x02ABD402, 0x02AF8C0B, 0x03600001, 0x036DFC02, 0x036FFC02,
- 0x037FFC01, 0x03EC7801, 0x03ECA401, 0x03EEC810, 0x03F4F802,
- 0x03F7F002, 0x03F8001A, 0x03F88007, 0x03F8C023, 0x03F95013,
- 0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807, 0x03FCEC06,
- 0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405, 0x04040003,
- 0x0404DC09, 0x0405E411, 0x0406400C, 0x0407402E, 0x040E7C01,
- 0x040F4001, 0x04215C01, 0x04247C01, 0x0424FC01, 0x04280403,
- 0x04281402, 0x04283004, 0x0428E003, 0x0428FC01, 0x04294009,
- 0x0429FC01, 0x042CE407, 0x04400003, 0x0440E016, 0x04420003,
- 0x0442C012, 0x04440003, 0x04449C0E, 0x04450004, 0x04460003,
- 0x0446CC0E, 0x04471404, 0x045AAC0D, 0x0491C004, 0x05BD442E,
- 0x05BE3C04, 0x074000F6, 0x07440027, 0x0744A4B5, 0x07480046,
- 0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01, 0x075C5401,
- 0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401, 0x075EA401,
- 0x075F0C01, 0x07BBC002, 0x07C0002C, 0x07C0C064, 0x07C2800F,
- 0x07C2C40E, 0x07C3040F, 0x07C3440F, 0x07C4401F, 0x07C4C03C,
- 0x07C5C02B, 0x07C7981D, 0x07C8402B, 0x07C90009, 0x07C94002,
- 0x07CC0021, 0x07CCC006, 0x07CCDC46, 0x07CE0014, 0x07CE8025,
- 0x07CF1805, 0x07CF8011, 0x07D0003F, 0x07D10001, 0x07D108B6,
- 0x07D3E404, 0x07D4003E, 0x07D50004, 0x07D54018, 0x07D7EC46,
- 0x07D9140B, 0x07DA0046, 0x07DC0074, 0x38000401, 0x38008060,
- 0x380400F0,
+ 0x002B8802, 0x002BC002, 0x002BE806, 0x002C0403, 0x002CF001,
+ 0x002CF807, 0x002D1C02, 0x002D2C03, 0x002D5802, 0x002D8802,
+ 0x002DC001, 0x002E0801, 0x002EF805, 0x002F1803, 0x002F2804,
+ 0x002F5C01, 0x002FCC08, 0x00300005, 0x0030F807, 0x00311803,
+ 0x00312804, 0x00315402, 0x00318802, 0x0031DC01, 0x0031FC01,
+ 0x00320404, 0x0032F001, 0x0032F807, 0x00331803, 0x00332804,
+ 0x00335402, 0x00338802, 0x00340004, 0x0034EC02, 0x0034F807,
+ 0x00351803, 0x00352804, 0x00353C01, 0x00355C01, 0x00358802,
+ 0x0035E401, 0x00360802, 0x00372801, 0x00373C06, 0x00375801,
+ 0x00376008, 0x0037C803, 0x0038C401, 0x0038D007, 0x0038FC01,
+ 0x00391C09, 0x00396802, 0x003AC401, 0x003AD009, 0x003B2006,
+ 0x003C041F, 0x003CD00C, 0x003DC417, 0x003E340B, 0x003E6424,
+ 0x003EF80F, 0x003F380D, 0x0040AC14, 0x00412806, 0x00415804,
+ 0x00417803, 0x00418803, 0x00419C07, 0x0041C404, 0x0042080C,
+ 0x00423C01, 0x00426806, 0x0043EC01, 0x004D740C, 0x004E400A,
+ 0x00500001, 0x0059B402, 0x005A0001, 0x005A6C02, 0x005BAC03,
+ 0x005C4803, 0x005CC805, 0x005D4802, 0x005DC802, 0x005ED023,
+ 0x005F6004, 0x005F7401, 0x0060000F, 0x00621402, 0x0062A401,
+ 0x0064800C, 0x0064C00C, 0x00650001, 0x00651002, 0x00677822,
+ 0x00685C05, 0x00687802, 0x0069540A, 0x0069801D, 0x0069FC01,
+ 0x006A8007, 0x006AA006, 0x006AC00F, 0x006C0005, 0x006CD011,
+ 0x006D6823, 0x006E0003, 0x006E840D, 0x006F980E, 0x006FF004,
+ 0x00709014, 0x0070EC05, 0x0071F802, 0x00730008, 0x00734019,
+ 0x0073B401, 0x0073D001, 0x0073DC03, 0x0077003A, 0x0077EC05,
+ 0x007EF401, 0x007EFC03, 0x007F3403, 0x007F7403, 0x007FB403,
+ 0x007FF402, 0x00800065, 0x0081980A, 0x0081E805, 0x00822805,
+ 0x00828020, 0x00834021, 0x00840002, 0x00840C04, 0x00842002,
+ 0x00845001, 0x00845803, 0x00847806, 0x00849401, 0x00849C01,
+ 0x0084A401, 0x0084B801, 0x0084E802, 0x00850005, 0x00852804,
+ 0x00853C01, 0x00862802, 0x00864297, 0x0091000B, 0x0092704E,
+ 0x00940276, 0x009E53E0, 0x00ADD820, 0x00AE6068, 0x00B39406,
+ 0x00B3BC03, 0x00B3E404, 0x00B3F802, 0x00B5C001, 0x00B5FC01,
+ 0x00B7804F, 0x00B8C020, 0x00BA001A, 0x00BA6C59, 0x00BC00D6,
+ 0x00BFC00C, 0x00C00005, 0x00C02019, 0x00C0A807, 0x00C0D802,
+ 0x00C0F403, 0x00C26404, 0x00C28001, 0x00C3EC01, 0x00C64002,
+ 0x00C6580A, 0x00C70024, 0x00C8001F, 0x00C8A81E, 0x00C94001,
+ 0x00C98020, 0x00CA2827, 0x00CB0140, 0x01370040, 0x02924037,
+ 0x0293F802, 0x02983403, 0x0299BC10, 0x029A7802, 0x029BC008,
+ 0x029C0017, 0x029C8002, 0x029E2402, 0x02A00801, 0x02A01801,
+ 0x02A02C01, 0x02A08C09, 0x02A0D804, 0x02A1D004, 0x02A20002,
+ 0x02A2D012, 0x02A33802, 0x02A38012, 0x02A3E003, 0x02A3F001,
+ 0x02A3FC01, 0x02A4980A, 0x02A51C0D, 0x02A57C01, 0x02A60004,
+ 0x02A6CC1B, 0x02A77802, 0x02A79401, 0x02A8A40E, 0x02A90C01,
+ 0x02A93002, 0x02A97004, 0x02A9DC03, 0x02A9EC03, 0x02AAC001,
+ 0x02AAC803, 0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802,
+ 0x02ABAC07, 0x02ABD402, 0x02AD6C01, 0x02AF8C0B, 0x03600001,
+ 0x036DFC02, 0x036FFC02, 0x037FFC01, 0x03EC7801, 0x03ECA401,
+ 0x03EEC810, 0x03F4F802, 0x03F7F002, 0x03F8001A, 0x03F88033,
+ 0x03F95013, 0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807,
+ 0x03FCEC06, 0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405,
+ 0x04040003, 0x0404DC09, 0x0405E411, 0x04063003, 0x0406400C,
+ 0x04068001, 0x0407402E, 0x040B8001, 0x040DD805, 0x040E7C01,
+ 0x040F4001, 0x0415BC01, 0x04215C01, 0x0421DC02, 0x04247C01,
+ 0x0424FC01, 0x04280403, 0x04281402, 0x04283004, 0x0428E003,
+ 0x0428FC01, 0x04294009, 0x0429FC01, 0x042B2001, 0x042B9402,
+ 0x042BC007, 0x042CE407, 0x042E6404, 0x04349004, 0x043D180B,
+ 0x043D5405, 0x04400003, 0x0440E016, 0x0441FC04, 0x0442C012,
+ 0x04433401, 0x04440003, 0x04449C0E, 0x04450004, 0x04451402,
+ 0x0445CC03, 0x04460003, 0x0446CC0E, 0x04471409, 0x04476C01,
+ 0x04477403, 0x0448B013, 0x044AA401, 0x044B7C0C, 0x044C0004,
+ 0x044CEC02, 0x044CF807, 0x044D1C02, 0x044D2C03, 0x044D5C01,
+ 0x044D8802, 0x044D9807, 0x044DC005, 0x0450D412, 0x04512C05,
+ 0x04516C01, 0x04517402, 0x0452C014, 0x04531801, 0x0456BC07,
+ 0x0456E020, 0x04577002, 0x0458C014, 0x0459800D, 0x045AAC0D,
+ 0x045C740F, 0x045CF004, 0x0460B010, 0x04674407, 0x04676807,
+ 0x04678801, 0x04679001, 0x0468040A, 0x0468CC07, 0x0468EC0D,
+ 0x0469440B, 0x046A2813, 0x046A7805, 0x0470BC08, 0x0470E008,
+ 0x04710405, 0x0471C002, 0x04724816, 0x0472A40E, 0x0474C406,
+ 0x0474E801, 0x0474F002, 0x0474FC07, 0x04751C01, 0x04762805,
+ 0x04764002, 0x04764C05, 0x047BCC06, 0x047F541D, 0x047FFC01,
+ 0x0491C005, 0x04D0C009, 0x05A9B802, 0x05ABC006, 0x05ACC010,
+ 0x05AD1002, 0x05BA5C04, 0x05BD3C01, 0x05BD4437, 0x05BE3C04,
+ 0x05BF8801, 0x06F27008, 0x074000F6, 0x07440027, 0x0744A4C0,
+ 0x07480046, 0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01,
+ 0x075C5401, 0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401,
+ 0x075EA401, 0x075F0C01, 0x0760028C, 0x076A6C05, 0x076A840F,
+ 0x07800007, 0x07802011, 0x07806C07, 0x07808C02, 0x07809805,
+ 0x0784C007, 0x07853C01, 0x078BB004, 0x078BFC01, 0x07A34007,
+ 0x07A51007, 0x07A57802, 0x07B2B001, 0x07B2C001, 0x07B4B801,
+ 0x07BBC002, 0x07C0002C, 0x07C0C064, 0x07C2800F, 0x07C2C40F,
+ 0x07C3040F, 0x07C34425, 0x07C4405D, 0x07C5C03D, 0x07C7981D,
+ 0x07C8402C, 0x07C90009, 0x07C94002, 0x07C98006, 0x07CC03D6,
+ 0x07DB800D, 0x07DBC00B, 0x07DC0074, 0x07DE0059, 0x07DF800C,
+ 0x07E0000C, 0x07E04038, 0x07E1400A, 0x07E18028, 0x07E2401E,
+ 0x07E4000C, 0x07E43465, 0x07E5CC04, 0x07E5E829, 0x07E69406,
+ 0x07E6B81D, 0x07E73487, 0x07E9800E, 0x07E9C004, 0x07E9E003,
+ 0x07EA0003, 0x07EA4006, 0x38000401, 0x38008060, 0x380400F0,
};
static const unsigned int aAscii[4] = {
0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001,
@@ -180067,7 +180904,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsal
return 1;
}
-
+#if !defined(SQLITE_AMALGAMATION) || !defined(SQLITE_ENABLE_FTS5)
/*
** If the argument is a codepoint corresponding to a lowercase letter
** in the ASCII range with a diacritic added, return the codepoint
@@ -180077,7 +180914,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsal
** uppercase letter are undefined.
*/
static int remove_diacritic(int c, int bComplex){
- unsigned short aDia[] = {
+ static const unsigned short aDia[] = {
0, 1797, 1848, 1859, 1891, 1928, 1940, 1995,
2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286,
2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732,
@@ -180096,7 +180933,7 @@ static int remove_diacritic(int c, int b
63182, 63242, 63274, 63310, 63368, 63390,
};
#define HIBIT ((unsigned char)0x80)
- unsigned char aChar[] = {
+ static const unsigned char aChar[] = {
'\0', 'a', 'c', 'e', 'i', 'n',
'o', 'u', 'y', 'y', 'a', 'c',
'd', 'e', 'e', 'g', 'h', 'i',
@@ -180185,73 +181022,84 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold
unsigned char flags;
unsigned char nRange;
} aEntry[] = {
- {65, 14, 26}, {181, 64, 1}, {192, 14, 23},
+ {65, 14, 26}, {181, 66, 1}, {192, 14, 23},
{216, 14, 7}, {256, 1, 48}, {306, 1, 6},
- {313, 1, 16}, {330, 1, 46}, {376, 116, 1},
- {377, 1, 6}, {383, 104, 1}, {385, 50, 1},
- {386, 1, 4}, {390, 44, 1}, {391, 0, 1},
- {393, 42, 2}, {395, 0, 1}, {398, 32, 1},
- {399, 38, 1}, {400, 40, 1}, {401, 0, 1},
- {403, 42, 1}, {404, 46, 1}, {406, 52, 1},
- {407, 48, 1}, {408, 0, 1}, {412, 52, 1},
- {413, 54, 1}, {415, 56, 1}, {416, 1, 6},
- {422, 60, 1}, {423, 0, 1}, {425, 60, 1},
- {428, 0, 1}, {430, 60, 1}, {431, 0, 1},
- {433, 58, 2}, {435, 1, 4}, {439, 62, 1},
+ {313, 1, 16}, {330, 1, 46}, {376, 156, 1},
+ {377, 1, 6}, {383, 144, 1}, {385, 52, 1},
+ {386, 1, 4}, {390, 46, 1}, {391, 0, 1},
+ {393, 44, 2}, {395, 0, 1}, {398, 34, 1},
+ {399, 40, 1}, {400, 42, 1}, {401, 0, 1},
+ {403, 44, 1}, {404, 48, 1}, {406, 54, 1},
+ {407, 50, 1}, {408, 0, 1}, {412, 54, 1},
+ {413, 56, 1}, {415, 58, 1}, {416, 1, 6},
+ {422, 62, 1}, {423, 0, 1}, {425, 62, 1},
+ {428, 0, 1}, {430, 62, 1}, {431, 0, 1},
+ {433, 60, 2}, {435, 1, 4}, {439, 64, 1},
{440, 0, 1}, {444, 0, 1}, {452, 2, 1},
{453, 0, 1}, {455, 2, 1}, {456, 0, 1},
{458, 2, 1}, {459, 1, 18}, {478, 1, 18},
- {497, 2, 1}, {498, 1, 4}, {502, 122, 1},
- {503, 134, 1}, {504, 1, 40}, {544, 110, 1},
- {546, 1, 18}, {570, 70, 1}, {571, 0, 1},
- {573, 108, 1}, {574, 68, 1}, {577, 0, 1},
- {579, 106, 1}, {580, 28, 1}, {581, 30, 1},
- {582, 1, 10}, {837, 36, 1}, {880, 1, 4},
- {886, 0, 1}, {902, 18, 1}, {904, 16, 3},
- {908, 26, 1}, {910, 24, 2}, {913, 14, 17},
- {931, 14, 9}, {962, 0, 1}, {975, 4, 1},
- {976, 140, 1}, {977, 142, 1}, {981, 146, 1},
- {982, 144, 1}, {984, 1, 24}, {1008, 136, 1},
- {1009, 138, 1}, {1012, 130, 1}, {1013, 128, 1},
- {1015, 0, 1}, {1017, 152, 1}, {1018, 0, 1},
- {1021, 110, 3}, {1024, 34, 16}, {1040, 14, 32},
- {1120, 1, 34}, {1162, 1, 54}, {1216, 6, 1},
- {1217, 1, 14}, {1232, 1, 88}, {1329, 22, 38},
- {4256, 66, 38}, {4295, 66, 1}, {4301, 66, 1},
- {7680, 1, 150}, {7835, 132, 1}, {7838, 96, 1},
- {7840, 1, 96}, {7944, 150, 8}, {7960, 150, 6},
- {7976, 150, 8}, {7992, 150, 8}, {8008, 150, 6},
- {8025, 151, 8}, {8040, 150, 8}, {8072, 150, 8},
- {8088, 150, 8}, {8104, 150, 8}, {8120, 150, 2},
- {8122, 126, 2}, {8124, 148, 1}, {8126, 100, 1},
- {8136, 124, 4}, {8140, 148, 1}, {8152, 150, 2},
- {8154, 120, 2}, {8168, 150, 2}, {8170, 118, 2},
- {8172, 152, 1}, {8184, 112, 2}, {8186, 114, 2},
- {8188, 148, 1}, {8486, 98, 1}, {8490, 92, 1},
- {8491, 94, 1}, {8498, 12, 1}, {8544, 8, 16},
- {8579, 0, 1}, {9398, 10, 26}, {11264, 22, 47},
- {11360, 0, 1}, {11362, 88, 1}, {11363, 102, 1},
- {11364, 90, 1}, {11367, 1, 6}, {11373, 84, 1},
- {11374, 86, 1}, {11375, 80, 1}, {11376, 82, 1},
- {11378, 0, 1}, {11381, 0, 1}, {11390, 78, 2},
+ {497, 2, 1}, {498, 1, 4}, {502, 162, 1},
+ {503, 174, 1}, {504, 1, 40}, {544, 150, 1},
+ {546, 1, 18}, {570, 74, 1}, {571, 0, 1},
+ {573, 148, 1}, {574, 72, 1}, {577, 0, 1},
+ {579, 146, 1}, {580, 30, 1}, {581, 32, 1},
+ {582, 1, 10}, {837, 38, 1}, {880, 1, 4},
+ {886, 0, 1}, {895, 38, 1}, {902, 20, 1},
+ {904, 18, 3}, {908, 28, 1}, {910, 26, 2},
+ {913, 14, 17}, {931, 14, 9}, {962, 0, 1},
+ {975, 4, 1}, {976, 180, 1}, {977, 182, 1},
+ {981, 186, 1}, {982, 184, 1}, {984, 1, 24},
+ {1008, 176, 1}, {1009, 178, 1}, {1012, 170, 1},
+ {1013, 168, 1}, {1015, 0, 1}, {1017, 192, 1},
+ {1018, 0, 1}, {1021, 150, 3}, {1024, 36, 16},
+ {1040, 14, 32}, {1120, 1, 34}, {1162, 1, 54},
+ {1216, 6, 1}, {1217, 1, 14}, {1232, 1, 96},
+ {1329, 24, 38}, {4256, 70, 38}, {4295, 70, 1},
+ {4301, 70, 1}, {5112, 190, 6}, {7296, 126, 1},
+ {7297, 128, 1}, {7298, 130, 1}, {7299, 134, 2},
+ {7301, 132, 1}, {7302, 136, 1}, {7303, 138, 1},
+ {7304, 100, 1}, {7312, 142, 43}, {7357, 142, 3},
+ {7680, 1, 150}, {7835, 172, 1}, {7838, 120, 1},
+ {7840, 1, 96}, {7944, 190, 8}, {7960, 190, 6},
+ {7976, 190, 8}, {7992, 190, 8}, {8008, 190, 6},
+ {8025, 191, 8}, {8040, 190, 8}, {8072, 190, 8},
+ {8088, 190, 8}, {8104, 190, 8}, {8120, 190, 2},
+ {8122, 166, 2}, {8124, 188, 1}, {8126, 124, 1},
+ {8136, 164, 4}, {8140, 188, 1}, {8152, 190, 2},
+ {8154, 160, 2}, {8168, 190, 2}, {8170, 158, 2},
+ {8172, 192, 1}, {8184, 152, 2}, {8186, 154, 2},
+ {8188, 188, 1}, {8486, 122, 1}, {8490, 116, 1},
+ {8491, 118, 1}, {8498, 12, 1}, {8544, 8, 16},
+ {8579, 0, 1}, {9398, 10, 26}, {11264, 24, 47},
+ {11360, 0, 1}, {11362, 112, 1}, {11363, 140, 1},
+ {11364, 114, 1}, {11367, 1, 6}, {11373, 108, 1},
+ {11374, 110, 1}, {11375, 104, 1}, {11376, 106, 1},
+ {11378, 0, 1}, {11381, 0, 1}, {11390, 102, 2},
{11392, 1, 100}, {11499, 1, 4}, {11506, 0, 1},
- {42560, 1, 46}, {42624, 1, 24}, {42786, 1, 14},
- {42802, 1, 62}, {42873, 1, 4}, {42877, 76, 1},
- {42878, 1, 10}, {42891, 0, 1}, {42893, 74, 1},
- {42896, 1, 4}, {42912, 1, 10}, {42922, 72, 1},
- {65313, 14, 26},
+ {42560, 1, 46}, {42624, 1, 28}, {42786, 1, 14},
+ {42802, 1, 62}, {42873, 1, 4}, {42877, 98, 1},
+ {42878, 1, 10}, {42891, 0, 1}, {42893, 88, 1},
+ {42896, 1, 4}, {42902, 1, 20}, {42922, 80, 1},
+ {42923, 76, 1}, {42924, 78, 1}, {42925, 84, 1},
+ {42926, 80, 1}, {42928, 92, 1}, {42929, 86, 1},
+ {42930, 90, 1}, {42931, 68, 1}, {42932, 1, 12},
+ {42946, 0, 1}, {42948, 178, 1}, {42949, 82, 1},
+ {42950, 96, 1}, {43888, 94, 80}, {65313, 14, 26},
};
static const unsigned short aiOff[] = {
1, 2, 8, 15, 16, 26, 28, 32,
- 37, 38, 40, 48, 63, 64, 69, 71,
- 79, 80, 116, 202, 203, 205, 206, 207,
- 209, 210, 211, 213, 214, 217, 218, 219,
- 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721,
- 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274,
- 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406,
- 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462,
- 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511,
- 65514, 65521, 65527, 65528, 65529,
+ 34, 37, 38, 40, 48, 63, 64, 69,
+ 71, 79, 80, 116, 202, 203, 205, 206,
+ 207, 209, 210, 211, 213, 214, 217, 218,
+ 219, 775, 928, 7264, 10792, 10795, 23217, 23221,
+ 23228, 23229, 23231, 23254, 23256, 23275, 23278, 26672,
+ 30152, 30204, 35267, 54721, 54753, 54754, 54756, 54787,
+ 54793, 54809, 57153, 57274, 57921, 58019, 58363, 59314,
+ 59315, 59324, 59325, 59326, 59332, 59356, 61722, 62528,
+ 65268, 65341, 65373, 65406, 65408, 65410, 65415, 65424,
+ 65436, 65439, 65450, 65462, 65472, 65476, 65478, 65480,
+ 65482, 65488, 65506, 65511, 65514, 65521, 65527, 65528,
+ 65529,
};
int ret = c;
@@ -180293,9 +181141,25 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold
else if( c>=66560 && c<66600 ){
ret = c + 40;
}
+ else if( c>=66736 && c<66772 ){
+ ret = c + 40;
+ }
+ else if( c>=68736 && c<68787 ){
+ ret = c + 64;
+ }
+ else if( c>=71840 && c<71872 ){
+ ret = c + 32;
+ }
+ else if( c>=93760 && c<93792 ){
+ ret = c + 32;
+ }
+ else if( c>=125184 && c<125218 ){
+ ret = c + 34;
+ }
return ret;
}
+#endif /* !defined(SQLITE_AMALGAMATION) || !defined(SQLITE_ENABLE_FTS5) */
#endif /* defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) */
#endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */
@@ -180391,7 +181255,6 @@ static const char jsonIsSpace[] = {
#ifndef SQLITE_AMALGAMATION
/* Unsigned integer types. These are already defined in the sqliteInt.h,
** but the definitions need to be repeated for separate compilation. */
- typedef sqlite3_uint64 u64;
typedef unsigned int u32;
typedef unsigned short int u16;
typedef unsigned char u8;
@@ -180409,8 +181272,8 @@ typedef struct JsonParse JsonParse;
struct JsonString {
sqlite3_context *pCtx; /* Function context - put error messages here */
char *zBuf; /* Append JSON content here */
- u64 nAlloc; /* Bytes of storage available in zBuf[] */
- u64 nUsed; /* Bytes of zBuf[] currently used */
+ size_t nAlloc; /* Bytes of storage available in zBuf[] */
+ size_t nUsed; /* Bytes of zBuf[] currently used */
u8 bStatic; /* True if zBuf is static space */
u8 bErr; /* True if an error has been encountered */
char zSpace[100]; /* Initial static space */
@@ -180433,7 +181296,7 @@ struct JsonString {
/*
** Names of the various JSON types:
*/
-static const char * const jsonType[] = {
+static const char jsonType[][8] = {
"null", "true", "false", "integer", "real", "text", "array", "object"
};
@@ -180530,11 +181393,11 @@ static void jsonOom(JsonString *p){
** Return zero on success. Return non-zero on an OOM error
*/
static int jsonGrow(JsonString *p, u32 N){
- u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
+ size_t nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
char *zNew;
if( p->bStatic ){
if( p->bErr ) return 1;
- zNew = sqlite3_malloc64(nTotal);
+ zNew = sqlite3_malloc(nTotal);
if( zNew==0 ){
jsonOom(p);
return SQLITE_NOMEM;
@@ -180543,7 +181406,7 @@ static int jsonGrow(JsonString *p, u32 N
p->zBuf = zNew;
p->bStatic = 0;
}else{
- zNew = sqlite3_realloc64(p->zBuf, nTotal);
+ zNew = sqlite3_realloc(p->zBuf, nTotal);
if( zNew==0 ){
jsonOom(p);
return SQLITE_NOMEM;
@@ -181268,7 +182131,7 @@ static void jsonParseFillInParentage(Jso
static int jsonParseFindParents(JsonParse *pParse){
u32 *aUp;
assert( pParse->aUp==0 );
- aUp = pParse->aUp = sqlite3_malloc64( sizeof(u32)*pParse->nNode );
+ aUp = pParse->aUp = sqlite3_malloc( sizeof(u32)*pParse->nNode );
if( aUp==0 ){
pParse->oom = 1;
return SQLITE_NOMEM;
@@ -181330,7 +182193,7 @@ static JsonParse *jsonParseCached(
pMatch->iHold = iMaxHold+1;
return pMatch;
}
- p = sqlite3_malloc64( sizeof(*p) + nJson + 1 );
+ p = sqlite3_malloc( sizeof(*p) + nJson + 1 );
if( p==0 ){
sqlite3_result_error_nomem(pCtx);
return 0;
@@ -182628,7 +183491,7 @@ static int jsonEachFilter(
JsonEachCursor *p = (JsonEachCursor*)cur;
const char *z;
const char *zRoot = 0;
- sqlite3_int64 n;
+ size_t n;
UNUSED_PARAM(idxStr);
UNUSED_PARAM(argc);
@@ -182636,10 +183499,10 @@ static int jsonEachFilter(
if( idxNum==0 ) return SQLITE_OK;
z = (const char*)sqlite3_value_text(argv[0]);
if( z==0 ) return SQLITE_OK;
- n = sqlite3_value_bytes(argv[0]);
- p->zJson = sqlite3_malloc64( n+1 );
+ n = (size_t)sqlite3_value_bytes(argv[0]);
+ p->zJson = sqlite3_malloc( n+1 );
if( p->zJson==0 ) return SQLITE_NOMEM;
- memcpy(p->zJson, z, (size_t)n+1);
+ memcpy(p->zJson, z, n+1);
if( jsonParse(&p->sParse, 0, p->zJson) ){
int rc = SQLITE_NOMEM;
if( p->sParse.oom==0 ){
@@ -182658,10 +183521,10 @@ static int jsonEachFilter(
const char *zErr = 0;
zRoot = (const char*)sqlite3_value_text(argv[1]);
if( zRoot==0 ) return SQLITE_OK;
- n = sqlite3_value_bytes(argv[1]);
- p->zRoot = sqlite3_malloc64( n+1 );
+ n = (size_t)sqlite3_value_bytes(argv[1]);
+ p->zRoot = sqlite3_malloc( n+1 );
if( p->zRoot==0 ) return SQLITE_NOMEM;
- memcpy(p->zRoot, zRoot, (size_t)n+1);
+ memcpy(p->zRoot, zRoot, n+1);
if( zRoot[0]!='$' ){
zErr = zRoot;
}else{
@@ -182699,7 +183562,7 @@ static int jsonEachFilter(
}
/* The methods of the json_each virtual table */
-static sqlite3_module jsonEachModule = {
+static const sqlite3_module jsonEachModule = {
0, /* iVersion */
0, /* xCreate */
jsonEachConnect, /* xConnect */
@@ -182727,7 +183590,7 @@ static sqlite3_module jsonEachModule = {
};
/* The methods of the json_tree virtual table. */
-static sqlite3_module jsonTreeModule = {
+static const sqlite3_module jsonTreeModule = {
0, /* iVersion */
0, /* xCreate */
jsonEachConnect, /* xConnect */
@@ -182807,7 +183670,7 @@ SQLITE_PRIVATE int sqlite3Json1Init(sqli
#ifndef SQLITE_OMIT_VIRTUALTABLE
static const struct {
const char *zName;
- sqlite3_module *pModule;
+ const sqlite3_module *pModule;
} aMod[] = {
{ "json_each", &jsonEachModule },
{ "json_tree", &jsonTreeModule },
@@ -183241,11 +184104,11 @@ struct RtreeMatchArg {
RtreeDValue aParam[1]; /* Values for parameters to the SQL function */
};
-#ifndef MAX
-# define MAX(x,y) ((x) < (y) ? (y) : (x))
-#endif
#ifndef MIN
-# define MIN(x,y) ((x) > (y) ? (y) : (x))
+# define MIN(A,B) ((A)<(B)?(A):(B))
+#endif
+#ifndef MAX
+# define MAX(A,B) ((A)>(B)?(A):(B))
#endif
/* What version of GCC is being used. 0 means GCC is not being used .
@@ -183473,7 +184336,7 @@ static void nodeHashDelete(Rtree *pRtree
*/
static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
RtreeNode *pNode;
- pNode = (RtreeNode *)sqlite3_malloc64(sizeof(RtreeNode) + pRtree->iNodeSize);
+ pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode) + pRtree->iNodeSize);
if( pNode ){
memset(pNode, 0, sizeof(RtreeNode) + pRtree->iNodeSize);
pNode->zData = (u8 *)&pNode[1];
@@ -183568,7 +184431,7 @@ static int nodeAcquire(
RTREE_IS_CORRUPT(pRtree);
}
}else if( pRtree->iNodeSize==sqlite3_blob_bytes(pRtree->pNodeBlob) ){
- pNode = (RtreeNode *)sqlite3_malloc64(sizeof(RtreeNode)+pRtree->iNodeSize);
+ pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize);
if( !pNode ){
rc = SQLITE_NOMEM;
}else{
@@ -183900,7 +184763,7 @@ static int rtreeOpen(sqlite3_vtab *pVTab
Rtree *pRtree = (Rtree *)pVTab;
RtreeCursor *pCsr;
- pCsr = (RtreeCursor *)sqlite3_malloc64(sizeof(RtreeCursor));
+ pCsr = (RtreeCursor *)sqlite3_malloc(sizeof(RtreeCursor));
if( pCsr ){
memset(pCsr, 0, sizeof(RtreeCursor));
pCsr->base.pVtab = pVTab;
@@ -184608,7 +185471,7 @@ static int deserializeGeometry(sqlite3_v
pSrc = sqlite3_value_pointer(pValue, "RtreeMatchArg");
if( pSrc==0 ) return SQLITE_ERROR;
pInfo = (sqlite3_rtree_query_info*)
- sqlite3_malloc64( sizeof(*pInfo)+pSrc->iSize );
+ sqlite3_malloc( sizeof(*pInfo)+pSrc->iSize );
if( !pInfo ) return SQLITE_NOMEM;
memset(pInfo, 0, sizeof(*pInfo));
pBlob = (RtreeMatchArg*)&pInfo[1];
@@ -184680,7 +185543,7 @@ static int rtreeFilter(
*/
rc = nodeAcquire(pRtree, 1, 0, &pRoot);
if( rc==SQLITE_OK && argc>0 ){
- pCsr->aConstraint = sqlite3_malloc64(sizeof(RtreeConstraint)*argc);
+ pCsr->aConstraint = sqlite3_malloc(sizeof(RtreeConstraint)*argc);
pCsr->nConstraint = argc;
if( !pCsr->aConstraint ){
rc = SQLITE_NOMEM;
@@ -185251,9 +186114,9 @@ static int splitNodeStartree(
int iBestSplit = 0;
RtreeDValue fBestMargin = RTREE_ZERO;
- sqlite3_int64 nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int));
+ size_t nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int));
- aaSorted = (int **)sqlite3_malloc64(nByte);
+ aaSorted = (int **)sqlite3_malloc(nByte);
if( !aaSorted ){
return SQLITE_NOMEM;
}
@@ -185374,7 +186237,7 @@ static int SplitNode(
/* Allocate an array and populate it with a copy of pCell and
** all cells from node pLeft. Then zero the original node.
*/
- aCell = sqlite3_malloc64((sizeof(RtreeCell)+sizeof(int))*(nCell+1));
+ aCell = sqlite3_malloc((sizeof(RtreeCell)+sizeof(int))*(nCell+1));
if( !aCell ){
rc = SQLITE_NOMEM;
goto splitnode_out;
@@ -185665,7 +186528,7 @@ static int Reinsert(
/* Allocate the buffers used by this operation. The allocation is
** relinquished before this function returns.
*/
- aCell = (RtreeCell *)sqlite3_malloc64(n * (
+ aCell = (RtreeCell *)sqlite3_malloc(n * (
sizeof(RtreeCell) + /* aCell array */
sizeof(int) + /* aOrder array */
sizeof(int) + /* aSpare array */
@@ -186260,7 +187123,7 @@ static int rtreeShadowName(const char *z
return 0;
}
-static sqlite3_module rtreeModule = {
+static const sqlite3_module rtreeModule = {
3, /* iVersion */
rtreeCreate, /* xCreate - create a table */
rtreeConnect, /* xConnect - connect to an existing table */
@@ -186297,7 +187160,7 @@ static int rtreeSqlInit(
int rc = SQLITE_OK;
#define N_STATEMENT 8
- static const char *azSql[N_STATEMENT] = {
+ static const char *const azSql[N_STATEMENT] = {
/* Write the xxx_node table */
"INSERT OR REPLACE INTO '%q'.'%q_node' VALUES(?1, ?2)",
"DELETE FROM '%q'.'%q_node' WHERE nodeno = ?1",
@@ -186514,7 +187377,7 @@ static int rtreeInit(
int ii = 4;
int iErr;
- const char *aErrMsg[] = {
+ const char *const aErrMsg[] = {
0, /* 0 */
"Wrong number of columns for an rtree table", /* 1 */
"Too few columns for an rtree table", /* 2 */
@@ -186533,7 +187396,7 @@ static int rtreeInit(
/* Allocate the sqlite3_vtab structure */
nDb = (int)strlen(argv[1]);
nName = (int)strlen(argv[2]);
- pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2);
+ pRtree = (Rtree *)sqlite3_malloc(sizeof(Rtree)+nDb+nName+2);
if( !pRtree ){
return SQLITE_NOMEM;
}
@@ -186807,9 +187670,9 @@ static u8 *rtreeCheckGetNode(RtreeCheck
if( pCheck->rc==SQLITE_OK ){
sqlite3_bind_int64(pCheck->pGetNode, 1, iNode);
if( sqlite3_step(pCheck->pGetNode)==SQLITE_ROW ){
- int nNode = sqlite3_column_bytes(pCheck->pGetNode, 0);
+ size_t nNode = sqlite3_column_bytes(pCheck->pGetNode, 0);
const u8 *pNode = (const u8*)sqlite3_column_blob(pCheck->pGetNode, 0);
- pRet = sqlite3_malloc64(nNode);
+ pRet = sqlite3_malloc(nNode);
if( pRet==0 ){
pCheck->rc = SQLITE_NOMEM;
}else{
@@ -187433,7 +188296,7 @@ static GeoPoly *geopolyParseJson(const u
GeoPoly *pOut;
int x = 1;
s.nVertex--; /* Remove the redundant vertex at the end */
- pOut = sqlite3_malloc64( GEOPOLY_SZ((sqlite3_int64)s.nVertex) );
+ pOut = sqlite3_malloc( GEOPOLY_SZ((size_t)s.nVertex) );
x = 1;
if( pOut==0 ) goto parse_json_err;
pOut->nVertex = s.nVertex;
@@ -187478,7 +188341,7 @@ static GeoPoly *geopolyFuncParam(
if( (a[0]==0 || a[0]==1)
&& (nVertex*2*sizeof(GeoCoord) + 4)==(unsigned int)nByte
){
- p = sqlite3_malloc64( sizeof(*p) + (nVertex-1)*2*sizeof(GeoCoord) );
+ p = sqlite3_malloc( sizeof(*p) + (nVertex-1)*2*sizeof(GeoCoord) );
if( p==0 ){
if( pRc ) *pRc = SQLITE_NOMEM;
if( pCtx ) sqlite3_result_error_nomem(pCtx);
@@ -187756,7 +188619,7 @@ static void geopolyRegularFunc(
if( n<3 || r<=0.0 ) return;
if( n>1000 ) n = 1000;
- p = sqlite3_malloc64( sizeof(*p) + (n-1)*2*sizeof(GeoCoord) );
+ p = sqlite3_malloc( sizeof(*p) + (n-1)*2*sizeof(GeoCoord) );
if( p==0 ){
sqlite3_result_error_nomem(context);
return;
@@ -188659,7 +189522,7 @@ static int geopolyBestIndex(sqlite3_vtab
if( iRowidTerm>=0 ){
pIdxInfo->idxNum = 1;
- pIdxInfo->idxStr = "rowid";
+ pIdxInfo->idxStr = (char *)"rowid";
pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1;
pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1;
pIdxInfo->estimatedCost = 30.0;
@@ -188669,7 +189532,7 @@ static int geopolyBestIndex(sqlite3_vtab
}
if( iFuncTerm>=0 ){
pIdxInfo->idxNum = idxNum;
- pIdxInfo->idxStr = "rtree";
+ pIdxInfo->idxStr = (char *)"rtree";
pIdxInfo->aConstraintUsage[iFuncTerm].argvIndex = 1;
pIdxInfo->aConstraintUsage[iFuncTerm].omit = 0;
pIdxInfo->estimatedCost = 300.0;
@@ -188677,7 +189540,7 @@ static int geopolyBestIndex(sqlite3_vtab
return SQLITE_OK;
}
pIdxInfo->idxNum = 4;
- pIdxInfo->idxStr = "fullscan";
+ pIdxInfo->idxStr = (char *)"fullscan";
pIdxInfo->estimatedCost = 3000000.0;
pIdxInfo->estimatedRows = 100000;
return SQLITE_OK;
@@ -188899,7 +189762,7 @@ static int geopolyFindFunction(
}
-static sqlite3_module geopolyModule = {
+static const sqlite3_module geopolyModule = {
3, /* iVersion */
geopolyCreate, /* xCreate - create a table */
geopolyConnect, /* xConnect - connect to an existing table */
@@ -189054,12 +189917,12 @@ static void rtreeMatchArgFree(void *pArg
static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
RtreeGeomCallback *pGeomCtx = (RtreeGeomCallback *)sqlite3_user_data(ctx);
RtreeMatchArg *pBlob;
- sqlite3_int64 nBlob;
+ size_t nBlob;
int memErr = 0;
nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue)
+ nArg*sizeof(sqlite3_value*);
- pBlob = (RtreeMatchArg *)sqlite3_malloc64(nBlob);
+ pBlob = (RtreeMatchArg *)sqlite3_malloc(nBlob);
if( !pBlob ){
sqlite3_result_error_nomem(ctx);
}else{
@@ -189383,7 +190246,7 @@ static void icuLikeFunc(
/* The escape character string must consist of a single UTF-8 character.
** Otherwise, return an error.
*/
- int nE= sqlite3_value_bytes(argv[2]);
+ size_t nE= sqlite3_value_bytes(argv[2]);
const unsigned char *zE = sqlite3_value_text(argv[2]);
int i = 0;
if( zE==0 ) return;
@@ -189514,8 +190377,8 @@ static void icuRegexpFunc(sqlite3_contex
static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
const UChar *zInput; /* Pointer to input string */
UChar *zOutput = 0; /* Pointer to output buffer */
- int nInput; /* Size of utf-16 input string in bytes */
- int nOut; /* Size of output buffer in bytes */
+ size_t nInput; /* Size of utf-16 input string in bytes */
+ size_t nOut; /* Size of output buffer in bytes */
int cnt;
int bToUpper; /* True for toupper(), false for tolower() */
UErrorCode status;
@@ -189680,10 +190543,10 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite
for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){
const struct IcuScalar *p = &scalars[i];
- rc = sqlite3_create_function(
+ rc = sqlite3_create_function_v2(
db, p->zName, p->nArg, p->enc,
p->iContext ? (void*)db : (void*)0,
- p->xFunc, 0, 0
+ p->xFunc, 0, 0, 0
);
}
@@ -189702,6 +190565,16 @@ SQLITE_API int sqlite3_icu_init(
SQLITE_EXTENSION_INIT2(pApi)
return sqlite3IcuInit(db);
}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+SQLITE_API int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi)
+ return sqlite3IcuInit(db);
+}
+#endif
#endif
#endif
@@ -189770,7 +190643,7 @@ static int icuCreate(
if( argc>0 ){
n = strlen(argv[0])+1;
}
- p = (IcuTokenizer *)sqlite3_malloc64(sizeof(IcuTokenizer)+n);
+ p = (IcuTokenizer *)sqlite3_malloc(sizeof(IcuTokenizer)+n);
if( !p ){
return SQLITE_NOMEM;
}
@@ -189827,7 +190700,7 @@ static int icuOpen(
nInput = strlen(zInput);
}
nChar = nInput+1;
- pCsr = (IcuCursor *)sqlite3_malloc64(
+ pCsr = (IcuCursor *)sqlite3_malloc(
sizeof(IcuCursor) + /* IcuCursor */
((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */
(nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */
@@ -191643,7 +192516,7 @@ static void *rbuMalloc(sqlite3rbu *p, sq
void *pRet = 0;
if( p->rc==SQLITE_OK ){
assert( nByte>0 );
- pRet = sqlite3_malloc64(nByte);
+ pRet = sqlite3_malloc(nByte);
if( pRet==0 ){
p->rc = SQLITE_NOMEM;
}else{
@@ -191690,7 +192563,7 @@ static char *rbuStrndup(const char *zStr
if( *pRc==SQLITE_OK ){
if( zStr ){
size_t nCopy = strlen(zStr) + 1;
- zRet = (char*)sqlite3_malloc64(nCopy);
+ zRet = (char*)sqlite3_malloc(nCopy);
if( zRet ){
memcpy(zRet, zStr, nCopy);
}else{
@@ -193663,7 +194536,7 @@ static int rbuCaptureWalRead(sqlite3rbu
if( pRbu->nFrame==pRbu->nFrameAlloc ){
int nNew = (pRbu->nFrameAlloc ? pRbu->nFrameAlloc : 64) * 2;
RbuFrame *aNew;
- aNew = (RbuFrame*)sqlite3_realloc64(pRbu->aFrame, nNew * sizeof(RbuFrame));
+ aNew = (RbuFrame*)sqlite3_realloc(pRbu->aFrame, nNew * sizeof(RbuFrame));
if( aNew==0 ) return SQLITE_NOMEM;
pRbu->aFrame = aNew;
pRbu->nFrameAlloc = nNew;
@@ -193728,7 +194601,7 @@ static LPWSTR rbuWinUtf8ToUnicode(const
if( nChar==0 ){
return 0;
}
- zWideFilename = sqlite3_malloc64( nChar*sizeof(zWideFilename[0]) );
+ zWideFilename = sqlite3_malloc( nChar*sizeof(zWideFilename[0]) );
if( zWideFilename==0 ){
return 0;
}
@@ -194536,7 +195409,7 @@ static sqlite3rbu *openRbuHandle(
size_t nRbu = strlen(zRbu);
size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1;
- p = (sqlite3rbu*)sqlite3_malloc64(nByte);
+ p = (sqlite3rbu*)sqlite3_malloc(nByte);
if( p ){
RbuState *pState = 0;
@@ -194684,7 +195557,7 @@ static sqlite3rbu *openRbuHandle(
*/
static sqlite3rbu *rbuMisuseError(void){
sqlite3rbu *pRet;
- pRet = sqlite3_malloc64(sizeof(sqlite3rbu));
+ pRet = sqlite3_malloc(sizeof(sqlite3rbu));
if( pRet ){
memset(pRet, 0, sizeof(sqlite3rbu));
pRet->rc = SQLITE_MISUSE;
@@ -195454,8 +196327,8 @@ static int rbuVfsShmMap(
** instead of a file on disk. */
assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
if( eStage==RBU_STAGE_OAL ){
- sqlite3_int64 nByte = (iRegion+1) * sizeof(char*);
- char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte);
+ size_t nByte = (iRegion+1) * sizeof(char*);
+ char **apNew = (char**)sqlite3_realloc(p->apShm, nByte);
/* This is an RBU connection that uses its own heap memory for the
** pages of the *-shm file. Since no other process can have run
@@ -195471,7 +196344,7 @@ static int rbuVfsShmMap(
}
if( rc==SQLITE_OK ){
- char *pNew = (char*)sqlite3_malloc64(szRegion);
+ char *pNew = (char*)sqlite3_malloc(szRegion);
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -195613,7 +196486,7 @@ static int rbuVfsOpen(
zBase = rbuMainToWal(zBase, SQLITE_OPEN_URI);
}
nCopy = strlen(zBase);
- zCopy = sqlite3_malloc64(nCopy+2);
+ zCopy = sqlite3_malloc(nCopy+2);
if( zCopy ){
memcpy(zCopy, zBase, nCopy);
zCopy[nCopy-3] = 'o';
@@ -195859,7 +196732,7 @@ SQLITE_API int sqlite3rbu_create_vfs(con
nName = strlen(zName);
nByte = sizeof(rbu_vfs) + nName + 1;
- pNew = (rbu_vfs*)sqlite3_malloc64(nByte);
+ pNew = (rbu_vfs*)sqlite3_malloc(nByte);
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -196033,7 +196906,7 @@ struct StatCursor {
char *zName; /* Value of 'name' column */
char *zPath; /* Value of 'path' column */
u32 iPageno; /* Value of 'pageno' column */
- char *zPagetype; /* Value of 'pagetype' column */
+ const char *zPagetype; /* Value of 'pagetype' column */
int nCell; /* Value of 'ncell' column */
int nPayload; /* Value of 'payload' column */
int nUnused; /* Value of 'unused' column */
@@ -196079,7 +196952,7 @@ static int statConnect(
}
rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
if( rc==SQLITE_OK ){
- pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
+ pTab = (StatTable *)sqlite3Malloc(sizeof(StatTable));
if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
}
@@ -196157,7 +197030,7 @@ static int statOpen(sqlite3_vtab *pVTab,
StatTable *pTab = (StatTable *)pVTab;
StatCursor *pCsr;
- pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
+ pCsr = (StatCursor *)sqlite3Malloc(sizeof(StatCursor));
if( pCsr==0 ){
return SQLITE_NOMEM_BKPT;
}else{
@@ -196281,7 +197154,7 @@ static int statDecodePage(Btree *pBt, St
sqlite3BtreeEnter(pBt);
nUsable = szPage - sqlite3BtreeGetReserveNoMutex(pBt);
sqlite3BtreeLeave(pBt);
- p->aCell = sqlite3_malloc64((p->nCell+1) * sizeof(StatCell));
+ p->aCell = sqlite3Malloc((p->nCell+1) * sizeof(StatCell));
if( p->aCell==0 ) return SQLITE_NOMEM_BKPT;
memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell));
@@ -196316,7 +197189,7 @@ static int statDecodePage(Btree *pBt, St
if( iOff+nLocal>nUsable ) goto statPageIsCorrupt;
pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
pCell->nOvfl = nOvfl;
- pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
+ pCell->aOvfl = sqlite3Malloc(sizeof(u32)*nOvfl);
if( pCell->aOvfl==0 ) return SQLITE_NOMEM_BKPT;
pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);
for(j=1; j<nOvfl; j++){
@@ -196615,7 +197488,7 @@ static int statRowid(sqlite3_vtab_cursor
** Invoke this routine to register the "dbstat" virtual table module
*/
SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){
- static sqlite3_module dbstat_module = {
+ static const sqlite3_module dbstat_module = {
0, /* iVersion */
statConnect, /* xCreate */
statConnect, /* xConnect */
@@ -196641,7 +197514,7 @@ SQLITE_PRIVATE int sqlite3DbstatRegister
0, /* xRollbackTo */
0 /* xShadowName */
};
- return sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
+ return sqlite3_create_module_v2(db, "dbstat", &dbstat_module, 0, 0);
}
#elif defined(SQLITE_ENABLE_DBSTAT_VTAB)
SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }
@@ -196956,7 +197829,7 @@ static int dbpageUpdate(
Pgno pgno;
DbPage *pDbPage = 0;
int rc = SQLITE_OK;
- char *zErr = 0;
+ const char *zErr = 0;
const char *zSchema;
int iDb;
Btree *pBt;
@@ -197033,7 +197906,7 @@ static int dbpageBegin(sqlite3_vtab *pVt
** Invoke this routine to register the "dbpage" virtual table module
*/
SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){
- static sqlite3_module dbpage_module = {
+ static const sqlite3_module dbpage_module = {
0, /* iVersion */
dbpageConnect, /* xCreate */
dbpageConnect, /* xConnect */
@@ -197903,7 +198776,6 @@ static int sessionPreupdateEqual(
a += sessionSerialLen(a);
}else{
sqlite3_value *pVal; /* Value returned by preupdate_new/old */
- int rc; /* Error code from preupdate_new/old */
int eType = *a++; /* Type of value from change record */
/* The following calls to preupdate_new() and preupdate_old() can not
@@ -197913,12 +198785,11 @@ static int sessionPreupdateEqual(
** this (that the method has already been called). */
if( op==SQLITE_INSERT ){
/* assert( db->pPreUpdate->pNewUnpacked || db->pPreUpdate->aNew ); */
- rc = pSession->hook.xNew(pSession->hook.pCtx, iCol, &pVal);
+ pSession->hook.xNew(pSession->hook.pCtx, iCol, &pVal);
}else{
/* assert( db->pPreUpdate->pUnpacked ); */
- rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal);
+ pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal);
}
- assert( rc==SQLITE_OK );
if( sqlite3_value_type(pVal)!=eType ) return 0;
/* A SessionChange object never has a NULL value in a PK column */
@@ -197941,7 +198812,7 @@ static int sessionPreupdateEqual(
int n;
const u8 *z;
a += sessionVarintGet(a, &n);
- if( sqlite3_value_bytes(pVal)!=n ) return 0;
+ if( sqlite3_value_bytes(pVal)!=(size_t)n ) return 0;
if( eType==SQLITE_TEXT ){
z = sqlite3_value_text(pVal);
}else{
@@ -197973,7 +198844,7 @@ static int sessionGrowHash(int bPatchset
SessionChange **apNew;
sqlite3_int64 nNew = 2*(sqlite3_int64)(pTab->nChange ? pTab->nChange : 128);
- apNew = (SessionChange **)sqlite3_malloc64(sizeof(SessionChange *) * nNew);
+ apNew = (SessionChange **)sqlite3_malloc(sizeof(SessionChange *) * nNew);
if( apNew==0 ){
if( pTab->nChange==0 ){
return SQLITE_ERROR;
@@ -198039,7 +198910,7 @@ static int sessionTableInfo(
char *zPragma;
sqlite3_stmt *pStmt;
int rc;
- sqlite3_int64 nByte;
+ size_t nByte;
int nDbCol = 0;
int nThis;
int i;
@@ -198082,7 +198953,7 @@ static int sessionTableInfo(
if( rc==SQLITE_OK ){
nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
- pAlloc = sqlite3_malloc64(nByte);
+ pAlloc = sqlite3_malloc(nByte);
if( pAlloc==0 ){
rc = SQLITE_NOMEM;
}
@@ -198305,7 +199176,7 @@ static void sessionPreupdateOneChange(
}
/* Allocate the change object */
- pChange = (SessionChange *)sqlite3_malloc64(nByte);
+ pChange = (SessionChange *)sqlite3_malloc(nByte);
if( !pChange ){
rc = SQLITE_NOMEM;
goto error_out;
@@ -198751,7 +199622,7 @@ SQLITE_API int sqlite3session_create(
*ppSession = 0;
/* Allocate and populate the new session object. */
- pNew = (sqlite3_session *)sqlite3_malloc64(sizeof(sqlite3_session) + nDb + 1);
+ pNew = (sqlite3_session *)sqlite3_malloc(sizeof(sqlite3_session) + nDb + 1);
if( !pNew ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(sqlite3_session));
pNew->db = db;
@@ -198870,7 +199741,7 @@ SQLITE_API int sqlite3session_attach(
if( !pTab ){
/* Allocate new SessionTable object. */
- pTab = (SessionTable *)sqlite3_malloc64(sizeof(SessionTable) + nName + 1);
+ pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1);
if( !pTab ){
rc = SQLITE_NOMEM;
}else{
@@ -199172,7 +200043,7 @@ static int sessionAppendUpdate(
assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
nAdvance = nHdr + n;
if( eType==sqlite3_column_type(pStmt, i)
- && n==sqlite3_column_bytes(pStmt, i)
+ && (size_t)n==sqlite3_column_bytes(pStmt, i)
&& (n==0 || 0==memcmp(&pCsr[nHdr], sqlite3_column_blob(pStmt, i), n))
){
break;
@@ -199806,7 +200677,7 @@ static int sessionValueSetStr(
** argument to sqlite3ValueSetStr() and have the copy created
** automatically. But doing so makes it difficult to detect any OOM
** error. Hence the code to create the copy externally. */
- u8 *aCopy = sqlite3_malloc64((sqlite3_int64)nData+1);
+ u8 *aCopy = sqlite3_malloc(nData+1);
if( aCopy==0 ) return SQLITE_NOMEM;
memcpy(aCopy, aData, nData);
sqlite3ValueSetStr(pVal, nData, (char*)aCopy, enc, sqlite3_free);
@@ -200419,7 +201290,7 @@ static int sessionChangesetInvert(
int iCol;
if( 0==apVal ){
- apVal = (sqlite3_value **)sqlite3_malloc64(sizeof(apVal[0])*nCol*2);
+ apVal = (sqlite3_value **)sqlite3_malloc(sizeof(apVal[0])*nCol*2);
if( 0==apVal ){
rc = SQLITE_NOMEM;
goto finished_invert;
@@ -201692,7 +202563,7 @@ static int sessionChangeMerge(
int rc = SQLITE_OK;
if( !pExist ){
- pNew = (SessionChange *)sqlite3_malloc64(sizeof(SessionChange) + nRec);
+ pNew = (SessionChange *)sqlite3_malloc(sizeof(SessionChange) + nRec);
if( !pNew ){
return SQLITE_NOMEM;
}
@@ -201726,7 +202597,7 @@ static int sessionChangeMerge(
*ppNew = pExist;
}else{
sqlite3_int64 nByte = nRec + pExist->nRecord + sizeof(SessionChange);
- pNew = (SessionChange*)sqlite3_malloc64(nByte);
+ pNew = (SessionChange*)sqlite3_malloc(nByte);
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -201793,7 +202664,7 @@ static int sessionChangeMerge(
** buffer of the new object is large enough to hold any record that
** may be generated by combining the input records. */
nByte = sizeof(SessionChange) + pExist->nRecord + nRec;
- pNew = (SessionChange *)sqlite3_malloc64(nByte);
+ pNew = (SessionChange *)sqlite3_malloc(nByte);
if( !pNew ){
sqlite3_free(pExist);
return SQLITE_NOMEM;
@@ -201899,7 +202770,7 @@ static int sessionChangesetToHash(
if( !pTab ){
SessionTable **ppTab;
- pTab = sqlite3_malloc64(sizeof(SessionTable) + nCol + nNew+1);
+ pTab = sqlite3_malloc(sizeof(SessionTable) + nCol + nNew+1);
if( !pTab ){
rc = SQLITE_NOMEM;
break;
@@ -203095,7 +203966,7 @@ struct fts5_api {
fts5_api *pApi,
const char *zName,
void *pContext,
- fts5_tokenizer *pTokenizer,
+ const fts5_tokenizer *pTokenizer,
void (*xDestroy)(void*)
);
@@ -203167,8 +204038,12 @@ typedef sqlite3_uint64 u64;
#define ALWAYS(x) 1
#define NEVER(x) 0
-#define MIN(x,y) (((x) < (y)) ? (x) : (y))
-#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+#ifndef MIN
+# define MIN(A,B) ((A)<(B)?(A):(B))
+#endif
+#ifndef MAX
+# define MAX(A,B) ((A)>(B)?(A):(B))
+#endif
/*
** Constants for the largest and smallest possible 64-bit signed integers.
@@ -203178,6 +204053,10 @@ typedef sqlite3_uint64 u64;
#endif
+#ifndef SQLITE_PRIVATE
+# define SQLITE_PRIVATE static
+#endif
+
/* Truncate very long tokens to this many bytes. Hard limit is
** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset
** field that occurs at the start of each leaf page (see fts5_index.c). */
@@ -203390,7 +204269,7 @@ static void sqlite3Fts5BufferAppendStrin
static void sqlite3Fts5BufferFree(Fts5Buffer*);
static void sqlite3Fts5BufferZero(Fts5Buffer*);
static void sqlite3Fts5BufferSet(int*, Fts5Buffer*, int, const u8*);
-static void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...);
+static void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, const char *zFmt, ...);
static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...);
@@ -203445,8 +204324,8 @@ static int sqlite3Fts5PoslistNext64(
);
/* Malloc utility */
-static void *sqlite3Fts5MallocZero(int *pRc, sqlite3_int64 nByte);
-static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn);
+static void *sqlite3Fts5MallocZero(int *pRc, size_t nByte);
+static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, size_t nIn);
/* Character set tests (like isspace(), isalpha() etc.) */
static int sqlite3Fts5IsBareword(char t);
@@ -203934,8 +204813,8 @@ static int sqlite3Fts5VocabInit(Fts5Glob
/**************************************************************************
** Interface to automatically generated code in fts5_unicode2.c.
*/
-static int sqlite3Fts5UnicodeIsdiacritic(int c);
-static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
+SQLITE_PRIVATE int sqlite3Fts5UnicodeIsdiacritic(int c);
+SQLITE_PRIVATE int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
static int sqlite3Fts5UnicodeCatParse(const char*, u8*);
static int sqlite3Fts5UnicodeCategory(u32 iCode);
@@ -204014,7 +204893,7 @@ static void sqlite3Fts5UnicodeAscii(u8*,
** Alternative datatype for the argument to the malloc() routine passed
** into sqlite3ParserAlloc(). The default is size_t.
*/
-#define fts5YYMALLOCARGTYPE u64
+#define fts5YYMALLOCARGTYPE size_t
/**************** End of %include directives **********************************/
/* These constants specify the various numeric values for terminal symbols
@@ -205132,7 +206011,7 @@ static fts5YYACTIONTYPE fts5yy_reduce(
break;
/********** End reduce actions ************************************************/
};
- assert( fts5yyruleno<sizeof(fts5yyRuleInfoLhs)/sizeof(fts5yyRuleInfoLhs[0]) );
+ assert( (size_t)fts5yyruleno<sizeof(fts5yyRuleInfoLhs)/sizeof(fts5yyRuleInfoLhs[0]) );
fts5yygoto = fts5yyRuleInfoLhs[fts5yyruleno];
fts5yysize = fts5yyRuleInfoNRhs[fts5yyruleno];
fts5yyact = fts5yy_find_reduce_action(fts5yymsp[fts5yysize].stateno,(fts5YYCODETYPE)fts5yygoto);
@@ -205999,13 +206878,13 @@ static int fts5Bm25GetData(
int nPhrase; /* Number of phrases in query */
sqlite3_int64 nRow = 0; /* Number of rows in table */
sqlite3_int64 nToken = 0; /* Number of tokens in table */
- sqlite3_int64 nByte; /* Bytes of space to allocate */
+ size_t nByte; /* Bytes of space to allocate */
int i;
/* Allocate the Fts5Bm25Data object */
nPhrase = pApi->xPhraseCount(pFts);
nByte = sizeof(Fts5Bm25Data) + nPhrase*2*sizeof(double);
- p = (Fts5Bm25Data*)sqlite3_malloc64(nByte);
+ p = (Fts5Bm25Data*)sqlite3_malloc(nByte);
if( p==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -206129,7 +207008,7 @@ static int sqlite3Fts5AuxInit(fts5_api *
{ "bm25", 0, fts5Bm25Function, 0 },
};
int rc = SQLITE_OK; /* Return code */
- int i; /* To iterate through builtin functions */
+ unsigned int i; /* To iterate through builtin functions */
for(i=0; rc==SQLITE_OK && i<ArraySize(aBuiltin); i++){
rc = pApi->xCreateFunction(pApi,
@@ -206245,7 +207124,7 @@ static void sqlite3Fts5BufferAppendStrin
static void sqlite3Fts5BufferAppendPrintf(
int *pRc,
Fts5Buffer *pBuf,
- char *zFmt, ...
+ const char *zFmt, ...
){
if( *pRc==SQLITE_OK ){
char *zTmp;
@@ -206398,10 +207277,10 @@ static int sqlite3Fts5PoslistWriterAppen
return SQLITE_OK;
}
-static void *sqlite3Fts5MallocZero(int *pRc, sqlite3_int64 nByte){
+static void *sqlite3Fts5MallocZero(int *pRc, size_t nByte){
void *pRet = 0;
if( *pRc==SQLITE_OK ){
- pRet = sqlite3_malloc64(nByte);
+ pRet = sqlite3_malloc(nByte);
if( pRet==0 ){
if( nByte>0 ) *pRc = SQLITE_NOMEM;
}else{
@@ -206419,11 +207298,11 @@ static void *sqlite3Fts5MallocZero(int *
** It is the responsibility of the caller to eventually free the returned
** buffer using sqlite3_free(). If an OOM error occurs, NULL is returned.
*/
-static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){
+static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, size_t nIn){
char *zRet = 0;
if( *pRc==SQLITE_OK ){
- if( nIn<0 ){
- nIn = (int)strlen(pIn);
+ if( nIn>(((size_t)-1)>>1) ){
+ nIn = strlen(pIn);
}
zRet = (char*)sqlite3_malloc(nIn+1);
if( zRet ){
@@ -206844,7 +207723,7 @@ static int fts5ConfigParseSpecial(
if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){
const char *p = (const char*)zArg;
- sqlite3_int64 nArg = strlen(zArg) + 1;
+ size_t nArg = strlen(zArg) + 1;
char **azArg = sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg);
char *pDel = sqlite3Fts5MallocZero(&rc, nArg * 2);
char *pSpace = pDel;
@@ -206974,8 +207853,8 @@ static const char *fts5ConfigGobbleWord(
){
const char *zRet = 0;
- sqlite3_int64 nIn = strlen(zIn);
- char *zOut = sqlite3_malloc64(nIn+1);
+ size_t nIn = strlen(zIn);
+ char *zOut = sqlite3_malloc(nIn+1);
assert( *pRc==SQLITE_OK );
*pbQuoted = 0;
@@ -207078,7 +207957,7 @@ static int sqlite3Fts5ConfigParse(
int rc = SQLITE_OK; /* Return code */
Fts5Config *pRet; /* New object to return */
int i;
- sqlite3_int64 nByte;
+ size_t nByte;
*ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config));
if( pRet==0 ) return SQLITE_NOMEM;
@@ -207377,7 +208256,7 @@ static int sqlite3Fts5ConfigSetValue(
if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
pgsz = sqlite3_value_int(pVal);
}
- if( pgsz<=0 || pgsz>FTS5_MAX_PAGE_SIZE ){
+ if( pgsz<32 || pgsz>FTS5_MAX_PAGE_SIZE ){
*pbBadkey = 1;
}else{
pConfig->pgsz = pgsz;
@@ -207540,7 +208419,7 @@ typedef struct Fts5ExprTerm Fts5ExprTerm
/*
** Functions generated by lemon from fts5parse.y.
*/
-static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(u64));
+static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(size_t));
static void sqlite3Fts5ParserFree(void*, void (*freeProc)(void*));
static void sqlite3Fts5Parser(void*, int, Fts5Token, Fts5Parse*);
#ifndef NDEBUG
@@ -207555,7 +208434,7 @@ struct Fts5Expr {
Fts5Config *pConfig;
Fts5ExprNode *pRoot;
int bDesc; /* Iterate in descending rowid order */
- int nPhrase; /* Number of phrases in expression */
+ unsigned int nPhrase; /* Number of phrases in expression */
Fts5ExprPhrase **apExprPhrase; /* Pointers to phrase objects */
};
@@ -207722,7 +208601,7 @@ static int fts5ExprGetToken(
return tok;
}
-static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc64((sqlite3_int64)t);}
+static void *fts5ParseAlloc(size_t t){ return sqlite3_malloc(t);}
static void fts5ParseFree(void *p){ sqlite3_free(p); }
static int sqlite3Fts5ExprNew(
@@ -207903,8 +208782,8 @@ static int fts5ExprSynonymList(
if( sqlite3Fts5IterEof(pIter)==0 && pIter->iRowid==iRowid ){
if( pIter->nData==0 ) continue;
if( nIter==nAlloc ){
- sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * nAlloc * 2;
- Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc64(nByte);
+ size_t nByte = sizeof(Fts5PoslistReader) * nAlloc * 2;
+ Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc(nByte);
if( aNew==0 ){
rc = SQLITE_NOMEM;
goto synonym_poslist_out;
@@ -207984,8 +208863,8 @@ static int fts5ExprPhraseIsMatch(
/* If the aStatic[] array is not large enough, allocate a large array
** using sqlite3_malloc(). This approach could be improved upon. */
if( pPhrase->nTerm>ArraySize(aStatic) ){
- sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm;
- aIter = (Fts5PoslistReader*)sqlite3_malloc64(nByte);
+ size_t nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm;
+ aIter = (Fts5PoslistReader*)sqlite3_malloc(nByte);
if( !aIter ) return SQLITE_NOMEM;
}
memset(aIter, 0, sizeof(Fts5PoslistReader) * pPhrase->nTerm);
@@ -208119,7 +208998,7 @@ static int fts5ExprNearIsMatch(int *pRc,
/* If the aStatic[] array is not large enough, allocate a large array
** using sqlite3_malloc(). This approach could be improved upon. */
if( pNear->nPhrase>ArraySize(aStatic) ){
- sqlite3_int64 nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase;
+ size_t nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase;
a = (Fts5NearTrimmer*)sqlite3Fts5MallocZero(&rc, nByte);
}else{
memset(aStatic, 0, sizeof(aStatic));
@@ -209028,9 +209907,9 @@ static Fts5ExprNearset *sqlite3Fts5Parse
return pNear;
}
if( pNear==0 ){
- sqlite3_int64 nByte;
+ size_t nByte;
nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*);
- pRet = sqlite3_malloc64(nByte);
+ pRet = sqlite3_malloc(nByte);
if( pRet==0 ){
pParse->rc = SQLITE_NOMEM;
}else{
@@ -209105,8 +209984,8 @@ static int fts5ParseTokenize(
if( pPhrase && pPhrase->nTerm>0 && (tflags & FTS5_TOKEN_COLOCATED) ){
Fts5ExprTerm *pSyn;
- sqlite3_int64 nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1;
- pSyn = (Fts5ExprTerm*)sqlite3_malloc64(nByte);
+ size_t nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1;
+ pSyn = (Fts5ExprTerm*)sqlite3_malloc(nByte);
if( pSyn==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -209638,7 +210517,7 @@ static Fts5ExprNode *sqlite3Fts5ParseNod
if( pParse->rc==SQLITE_OK ){
int nChild = 0; /* Number of children of returned node */
- sqlite3_int64 nByte; /* Bytes of space to allocate for this node */
+ size_t nByte; /* Bytes of space to allocate for this node */
assert( (eType!=FTS5_STRING && !pNear)
|| (eType==FTS5_STRING && !pLeft && !pRight)
@@ -209770,7 +210649,7 @@ static Fts5ExprNode *sqlite3Fts5ParseImp
}
static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
- sqlite3_int64 nByte = 0;
+ size_t nByte = 0;
Fts5ExprTerm *p;
char *zQuoted;
@@ -209778,7 +210657,7 @@ static char *fts5ExprTermPrint(Fts5ExprT
for(p=pTerm; p; p=p->pSynonym){
nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2;
}
- zQuoted = sqlite3_malloc64(nByte);
+ zQuoted = sqlite3_malloc(nByte);
if( zQuoted ){
int i = 0;
@@ -210018,7 +210897,7 @@ static void fts5ExprFunction(
}
nConfig = 3 + (nArg-iArg);
- azConfig = (const char**)sqlite3_malloc64(sizeof(char*) * nConfig);
+ azConfig = (const char**)sqlite3_malloc(sizeof(char*) * nConfig);
if( azConfig==0 ){
sqlite3_result_error_nomem(pCtx);
return;
@@ -210139,13 +211018,13 @@ static int sqlite3Fts5ExprInit(Fts5Globa
{ "fts5_isalnum", fts5ExprIsAlnum },
{ "fts5_fold", fts5ExprFold },
};
- int i;
+ unsigned int i;
int rc = SQLITE_OK;
void *pCtx = (void*)pGlobal;
for(i=0; rc==SQLITE_OK && i<ArraySize(aFunc); i++){
struct Fts5ExprFunc *p = &aFunc[i];
- rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0);
+ rc = sqlite3_create_function_v2(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0, 0);
}
/* Avoid warnings indicating that sqlite3Fts5ParserTrace() and
@@ -210169,7 +211048,7 @@ static int sqlite3Fts5ExprPhraseCount(Ft
** Return the number of terms in the iPhrase'th phrase in pExpr.
*/
static int sqlite3Fts5ExprPhraseSize(Fts5Expr *pExpr, int iPhrase){
- if( iPhrase<0 || iPhrase>=pExpr->nPhrase ) return 0;
+ if( iPhrase<0 || iPhrase>=(int)pExpr->nPhrase ) return 0;
return pExpr->apExprPhrase[iPhrase]->nTerm;
}
@@ -210199,9 +211078,9 @@ struct Fts5PoslistPopulator {
static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){
Fts5PoslistPopulator *pRet;
- pRet = sqlite3_malloc64(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
+ pRet = sqlite3_malloc(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
if( pRet ){
- int i;
+ size_t i;
memset(pRet, 0, sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
for(i=0; i<pExpr->nPhrase; i++){
Fts5Buffer *pBuf = &pExpr->apExprPhrase[i]->poslist;
@@ -210247,7 +211126,7 @@ static int fts5ExprPopulatePoslistsCb(
){
Fts5ExprCtx *p = (Fts5ExprCtx*)pCtx;
Fts5Expr *pExpr = p->pExpr;
- int i;
+ size_t i;
UNUSED_PARAM2(iUnused1, iUnused2);
@@ -210279,7 +211158,7 @@ static int sqlite3Fts5ExprPopulatePoslis
int iCol,
const char *z, int n
){
- int i;
+ size_t i;
Fts5ExprCtx sCtx;
sCtx.pExpr = pExpr;
sCtx.aPopulator = aPopulator;
@@ -210491,14 +211370,14 @@ static int sqlite3Fts5HashNew(Fts5Config
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
- sqlite3_int64 nByte;
+ size_t nByte;
memset(pNew, 0, sizeof(Fts5Hash));
pNew->pnByte = pnByte;
pNew->eDetail = pConfig->eDetail;
pNew->nSlot = 1024;
nByte = sizeof(Fts5HashEntry*) * pNew->nSlot;
- pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc64(nByte);
+ pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc(nByte);
if( pNew->aSlot==0 ){
sqlite3_free(pNew);
*ppNew = 0;
@@ -210566,7 +211445,7 @@ static int fts5HashResize(Fts5Hash *pHas
Fts5HashEntry **apNew;
Fts5HashEntry **apOld = pHash->aSlot;
- apNew = (Fts5HashEntry**)sqlite3_malloc64(nNew*sizeof(Fts5HashEntry*));
+ apNew = (Fts5HashEntry**)sqlite3_malloc(nNew*sizeof(Fts5HashEntry*));
if( !apNew ) return SQLITE_NOMEM;
memset(apNew, 0, nNew*sizeof(Fts5HashEntry*));
@@ -210671,7 +211550,7 @@ static int sqlite3Fts5HashWrite(
if( p==0 ){
/* Figure out how much space to allocate */
char *zKey;
- sqlite3_int64 nByte = sizeof(Fts5HashEntry) + (nToken+1) + 1 + 64;
+ size_t nByte = sizeof(Fts5HashEntry) + (nToken+1) + 1 + 64;
if( nByte<128 ) nByte = 128;
/* Grow the Fts5Hash.aSlot[] array if necessary. */
@@ -210682,7 +211561,7 @@ static int sqlite3Fts5HashWrite(
}
/* Allocate new Fts5HashEntry and add it to the hash table. */
- p = (Fts5HashEntry*)sqlite3_malloc64(nByte);
+ p = (Fts5HashEntry*)sqlite3_malloc(nByte);
if( !p ) return SQLITE_NOMEM;
memset(p, 0, sizeof(Fts5HashEntry));
p->nAlloc = (int)nByte;
@@ -210850,7 +211729,7 @@ static int fts5HashEntrySort(
int i;
*ppSorted = 0;
- ap = sqlite3_malloc64(sizeof(Fts5HashEntry*) * nMergeSlot);
+ ap = sqlite3_malloc(sizeof(Fts5HashEntry*) * nMergeSlot);
if( !ap ) return SQLITE_NOMEM;
memset(ap, 0, sizeof(Fts5HashEntry*) * nMergeSlot);
@@ -211534,7 +212413,7 @@ static u16 fts5GetU16(const u8 *aIn){
** If an OOM error is encountered, return NULL and set the error code in
** the Fts5Index handle passed as the first argument.
*/
-static void *fts5IdxMalloc(Fts5Index *p, sqlite3_int64 nByte){
+static void *fts5IdxMalloc(Fts5Index *p, size_t nByte){
return sqlite3Fts5MallocZero(&p->rc, nByte);
}
@@ -211634,8 +212513,8 @@ static Fts5Data *fts5DataRead(Fts5Index
if( rc==SQLITE_OK ){
u8 *aOut = 0; /* Read blob data into this buffer */
int nByte = sqlite3_blob_bytes(p->pReader);
- sqlite3_int64 nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING;
- pRet = (Fts5Data*)sqlite3_malloc64(nAlloc);
+ size_t nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING;
+ pRet = (Fts5Data*)sqlite3_malloc(nAlloc);
if( pRet ){
pRet->nn = nByte;
aOut = pRet->p = (u8*)&pRet[1];
@@ -211811,7 +212690,7 @@ static int fts5StructureDecode(
int iLvl;
int nLevel = 0;
int nSegment = 0;
- sqlite3_int64 nByte; /* Bytes of space to allocate at pRet */
+ size_t nByte; /* Bytes of space to allocate at pRet */
Fts5Structure *pRet = 0; /* Structure object to return */
/* Grab the cookie value */
@@ -215627,7 +216506,7 @@ static Fts5Structure *fts5IndexOptimizeS
Fts5Structure *pStruct
){
Fts5Structure *pNew = 0;
- sqlite3_int64 nByte = sizeof(Fts5Structure);
+ size_t nByte = sizeof(Fts5Structure);
int nSeg = pStruct->nSegment;
int i;
@@ -216852,7 +217731,8 @@ static void fts5IndexIntegrityCheckSegme
if( pSeg->pgnoFirst==0 ) return;
fts5IndexPrepareStmt(p, &pStmt, sqlite3_mprintf(
- "SELECT segid, term, (pgno>>1), (pgno&1) FROM %Q.'%q_idx' WHERE segid=%d",
+ "SELECT segid, term, (pgno>>1), (pgno&1) FROM %Q.'%q_idx' WHERE segid=%d "
+ "ORDER BY 1, 2",
pConfig->zDb, pConfig->zName, pSeg->iSegid
));
@@ -217524,8 +218404,8 @@ static void fts5RowidFunction(
** SQLite error code is returned instead.
*/
static int sqlite3Fts5IndexInit(sqlite3 *db){
- int rc = sqlite3_create_function(
- db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0
+ int rc = sqlite3_create_function_v2(
+ db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0, 0
);
if( rc==SQLITE_OK ){
@@ -217536,8 +218416,8 @@ static int sqlite3Fts5IndexInit(sqlite3
}
if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(
- db, "fts5_rowid", -1, SQLITE_UTF8, 0, fts5RowidFunction, 0, 0
+ rc = sqlite3_create_function_v2(
+ db, "fts5_rowid", -1, SQLITE_UTF8, 0, fts5RowidFunction, 0, 0, 0
);
}
return rc;
@@ -217576,7 +218456,9 @@ static int sqlite3Fts5IndexReset(Fts5Ind
** assert() conditions in the fts5 code are activated - conditions that are
** only true if it is guaranteed that the fts5 database is not corrupt.
*/
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
SQLITE_API int sqlite3_fts5_may_be_corrupt = 1;
+#endif
typedef struct Fts5Auxdata Fts5Auxdata;
@@ -217676,7 +218558,7 @@ struct Fts5FullTable {
struct Fts5MatchPhrase {
Fts5Buffer *pPoslist; /* Pointer to current poslist */
- int nTerm; /* Size of phrase in terms */
+ unsigned int nTerm; /* Size of phrase in terms */
};
/*
@@ -218110,7 +218992,7 @@ static int fts5BestIndexMethod(sqlite3_v
pInfo->idxStr = idxStr;
pInfo->needToFreeIdxStr = 1;
- for(i=0; i<pInfo->nConstraint; i++){
+ for(i=0; (int)i<pInfo->nConstraint; i++){
struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
int iCol = p->iColumn;
if( p->op==SQLITE_INDEX_CONSTRAINT_MATCH
@@ -218220,13 +219102,13 @@ static int fts5OpenMethod(sqlite3_vtab *
Fts5FullTable *pTab = (Fts5FullTable*)pVTab;
Fts5Config *pConfig = pTab->p.pConfig;
Fts5Cursor *pCsr = 0; /* New cursor object */
- sqlite3_int64 nByte; /* Bytes of space to allocate */
+ size_t nByte; /* Bytes of space to allocate */
int rc; /* Return code */
rc = fts5NewTransaction(pTab);
if( rc==SQLITE_OK ){
nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
- pCsr = (Fts5Cursor*)sqlite3_malloc64(nByte);
+ pCsr = (Fts5Cursor*)sqlite3_malloc(nByte);
if( pCsr ){
Fts5Global *pGlobal = pTab->pGlobal;
memset(pCsr, 0, (size_t)nByte);
@@ -218501,14 +219383,14 @@ static int fts5CursorFirstSorted(
Fts5Config *pConfig = pTab->p.pConfig;
Fts5Sorter *pSorter;
int nPhrase;
- sqlite3_int64 nByte;
+ size_t nByte;
int rc;
const char *zRank = pCsr->zRank;
const char *zRankArgs = pCsr->zRankArgs;
nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1);
- pSorter = (Fts5Sorter*)sqlite3_malloc64(nByte);
+ pSorter = (Fts5Sorter*)sqlite3_malloc(nByte);
if( pSorter==0 ) return SQLITE_NOMEM;
memset(pSorter, 0, (size_t)nByte);
pSorter->nIdx = nPhrase;
@@ -220087,8 +220969,8 @@ static int fts5CreateAux(
int rc = sqlite3_overload_function(pGlobal->db, zName, -1);
if( rc==SQLITE_OK ){
Fts5Auxiliary *pAux;
- sqlite3_int64 nName; /* Size of zName in bytes, including \0 */
- sqlite3_int64 nByte; /* Bytes of space to allocate */
+ size_t nName; /* Size of zName in bytes, including \0 */
+ size_t nByte; /* Bytes of space to allocate */
nName = strlen(zName) + 1;
nByte = sizeof(Fts5Auxiliary) + nName;
@@ -220119,13 +221001,13 @@ static int fts5CreateTokenizer(
fts5_api *pApi, /* Global context (one per db handle) */
const char *zName, /* Name of new function */
void *pUserData, /* User data for aux. function */
- fts5_tokenizer *pTokenizer, /* Tokenizer implementation */
+ const fts5_tokenizer *pTokenizer,/* Tokenizer implementation */
void(*xDestroy)(void*) /* Destructor for pUserData */
){
Fts5Global *pGlobal = (Fts5Global*)pApi;
Fts5TokenizerModule *pNew;
- sqlite3_int64 nName; /* Size of zName and its \0 terminator */
- sqlite3_int64 nByte; /* Bytes of space to allocate */
+ size_t nName; /* Size of zName and its \0 terminator */
+ size_t nByte; /* Bytes of space to allocate */
int rc = SQLITE_OK;
nName = strlen(zName) + 1;
@@ -220334,13 +221216,13 @@ static int fts5Init(sqlite3 *db){
if( rc==SQLITE_OK ) rc = sqlite3Fts5TokenizerInit(&pGlobal->api);
if( rc==SQLITE_OK ) rc = sqlite3Fts5VocabInit(pGlobal, db);
if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(
- db, "fts5", 1, SQLITE_UTF8, p, fts5Fts5Func, 0, 0
+ rc = sqlite3_create_function_v2(
+ db, "fts5", 1, SQLITE_UTF8, p, fts5Fts5Func, 0, 0, 0
);
}
if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(
- db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0
+ rc = sqlite3_create_function_v2(
+ db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0, 0
);
}
}
@@ -220470,7 +221352,7 @@ static int fts5StorageGetStmt(
assert( eStmt>=0 && eStmt<ArraySize(p->aStmt) );
if( p->aStmt[eStmt]==0 ){
- const char *azStmt[] = {
+ const char *const azStmt[] = {
"SELECT %s FROM %s T WHERE T.%Q >= ? AND T.%Q <= ? ORDER BY T.%Q ASC",
"SELECT %s FROM %s T WHERE T.%Q <= ? AND T.%Q >= ? ORDER BY T.%Q DESC",
"SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP */
@@ -220512,11 +221394,11 @@ static int fts5StorageGetStmt(
case FTS5_STMT_INSERT_CONTENT:
case FTS5_STMT_REPLACE_CONTENT: {
- int nCol = pC->nCol + 1;
+ size_t nCol = pC->nCol + 1;
char *zBind;
- int i;
+ size_t i;
- zBind = sqlite3_malloc64(1 + nCol*2);
+ zBind = sqlite3_malloc(1 + nCol*2);
if( zBind ){
for(i=0; i<nCol; i++){
zBind[i*2] = '?';
@@ -220685,11 +221567,11 @@ static int sqlite3Fts5StorageOpen(
){
int rc = SQLITE_OK;
Fts5Storage *p; /* New object */
- sqlite3_int64 nByte; /* Bytes of space to allocate */
+ size_t nByte; /* Bytes of space to allocate */
nByte = sizeof(Fts5Storage) /* Fts5Storage object */
+ pConfig->nCol * sizeof(i64); /* Fts5Storage.aTotalSize[] */
- *pp = p = (Fts5Storage*)sqlite3_malloc64(nByte);
+ *pp = p = (Fts5Storage*)sqlite3_malloc(nByte);
if( !p ) return SQLITE_NOMEM;
memset(p, 0, (size_t)nByte);
@@ -220700,7 +221582,7 @@ static int sqlite3Fts5StorageOpen(
if( bCreate ){
if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
int nDefn = 32 + pConfig->nCol*10;
- char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 10);
+ char *zDefn = sqlite3_malloc(32 + (size_t)pConfig->nCol * 10);
if( zDefn==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -221281,7 +222163,7 @@ static int sqlite3Fts5StorageIntegrity(F
memset(&ctx, 0, sizeof(Fts5IntegrityCtx));
ctx.pConfig = p->pConfig;
- aTotalSize = (i64*)sqlite3_malloc64(pConfig->nCol*(sizeof(int)+sizeof(i64)));
+ aTotalSize = (i64*)sqlite3_malloc(pConfig->nCol*(sizeof(int)+sizeof(i64)));
if( !aTotalSize ) return SQLITE_NOMEM;
aColSize = (int*)&aTotalSize[pConfig->nCol];
memset(aTotalSize, 0, sizeof(i64) * pConfig->nCol);
@@ -221567,7 +222449,7 @@ static int sqlite3Fts5StorageConfigValue
** For tokenizers with no "unicode" modifier, the set of token characters
** is the same as the set of ASCII range alphanumeric characters.
*/
-static unsigned char aAsciiTokenChar[128] = {
+static const unsigned char aAsciiTokenChar[128] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00..0x0F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10..0x1F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20..0x2F */
@@ -221672,14 +222554,14 @@ static int fts5AsciiTokenize(
int is = 0;
char aFold[64];
- int nFold = sizeof(aFold);
+ size_t nFold = sizeof(aFold);
char *pFold = aFold;
unsigned char *a = p->aTokenChar;
UNUSED_PARAM(iUnused);
while( is<nText && rc==SQLITE_OK ){
- int nByte;
+ size_t nByte;
/* Skip any leading divider characters. */
while( is<nText && ((pText[is]&0x80)==0 && a[(int)pText[is]]==0) ){
@@ -221697,7 +222579,7 @@ static int fts5AsciiTokenize(
nByte = ie-is;
if( nByte>nFold ){
if( pFold!=aFold ) sqlite3_free(pFold);
- pFold = sqlite3_malloc64((sqlite3_int64)nByte*2);
+ pFold = sqlite3_malloc(nByte*2);
if( pFold==0 ){
rc = SQLITE_NOMEM;
break;
@@ -221996,7 +222878,7 @@ static int fts5UnicodeTokenize(
/* Output buffer */
char *aFold = p->aFold;
- int nFold = p->nFold;
+ size_t nFold = p->nFold;
const char *pEnd = &aFold[nFold-6];
UNUSED_PARAM(iUnused);
@@ -222036,7 +222918,7 @@ static int fts5UnicodeTokenize(
/* Grow the output buffer so that there is sufficient space to fit the
** largest possible utf-8 character. */
if( zOut>pEnd ){
- aFold = sqlite3_malloc64((sqlite3_int64)nFold*2);
+ aFold = sqlite3_malloc(nFold*2);
if( aFold==0 ){
rc = SQLITE_NOMEM;
goto tokenize_done;
@@ -222807,17 +223689,18 @@ static int fts5PorterTokenize(
** Register all built-in tokenizers with FTS5.
*/
static int sqlite3Fts5TokenizerInit(fts5_api *pApi){
- struct BuiltinTokenizer {
+ static const struct BuiltinTokenizer {
const char *zName;
fts5_tokenizer x;
} aBuiltin[] = {
{ "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}},
+ { "unicode", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}},
{ "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }},
{ "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }},
};
int rc = SQLITE_OK; /* Return code */
- int i; /* To iterate through builtin functions */
+ unsigned int i; /* To iterate through builtin functions */
for(i=0; rc==SQLITE_OK && i<ArraySize(aBuiltin); i++){
rc = pApi->xCreateTokenizer(pApi,
@@ -222862,7 +223745,7 @@ static int sqlite3Fts5TokenizerInit(fts5
** uppercase letter are undefined.
*/
static int fts5_remove_diacritic(int c, int bComplex){
- unsigned short aDia[] = {
+ static const unsigned short aDia[] = {
0, 1797, 1848, 1859, 1891, 1928, 1940, 1995,
2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286,
2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732,
@@ -222881,7 +223764,7 @@ static int fts5_remove_diacritic(int c,
63182, 63242, 63274, 63310, 63368, 63390,
};
#define HIBIT ((unsigned char)0x80)
- unsigned char aChar[] = {
+ static const unsigned char aChar[] = {
'\0', 'a', 'c', 'e', 'i', 'n',
'o', 'u', 'y', 'y', 'a', 'c',
'd', 'e', 'e', 'g', 'h', 'i',
@@ -222928,7 +223811,7 @@ static int fts5_remove_diacritic(int c,
** Return true if the argument interpreted as a unicode codepoint
** is a diacritical modifier character.
*/
-static int sqlite3Fts5UnicodeIsdiacritic(int c){
+SQLITE_PRIVATE int sqlite3Fts5UnicodeIsdiacritic(int c){
unsigned int mask0 = 0x08029FDF;
unsigned int mask1 = 0x000361F8;
if( c<768 || c>817 ) return 0;
@@ -222947,7 +223830,7 @@ static int sqlite3Fts5UnicodeIsdiacritic
** The results are undefined if the value passed to this function
** is less than zero.
*/
-static int sqlite3Fts5UnicodeFold(int c, int eRemoveDiacritic){
+SQLITE_PRIVATE int sqlite3Fts5UnicodeFold(int c, int eRemoveDiacritic){
/* Each entry in the following array defines a rule for folding a range
** of codepoints to lower case. The rule applies to a range of nRange
** codepoints starting at codepoint iCode.
@@ -222970,73 +223853,84 @@ static int sqlite3Fts5UnicodeFold(int c,
unsigned char flags;
unsigned char nRange;
} aEntry[] = {
- {65, 14, 26}, {181, 64, 1}, {192, 14, 23},
+ {65, 14, 26}, {181, 66, 1}, {192, 14, 23},
{216, 14, 7}, {256, 1, 48}, {306, 1, 6},
- {313, 1, 16}, {330, 1, 46}, {376, 116, 1},
- {377, 1, 6}, {383, 104, 1}, {385, 50, 1},
- {386, 1, 4}, {390, 44, 1}, {391, 0, 1},
- {393, 42, 2}, {395, 0, 1}, {398, 32, 1},
- {399, 38, 1}, {400, 40, 1}, {401, 0, 1},
- {403, 42, 1}, {404, 46, 1}, {406, 52, 1},
- {407, 48, 1}, {408, 0, 1}, {412, 52, 1},
- {413, 54, 1}, {415, 56, 1}, {416, 1, 6},
- {422, 60, 1}, {423, 0, 1}, {425, 60, 1},
- {428, 0, 1}, {430, 60, 1}, {431, 0, 1},
- {433, 58, 2}, {435, 1, 4}, {439, 62, 1},
+ {313, 1, 16}, {330, 1, 46}, {376, 156, 1},
+ {377, 1, 6}, {383, 144, 1}, {385, 52, 1},
+ {386, 1, 4}, {390, 46, 1}, {391, 0, 1},
+ {393, 44, 2}, {395, 0, 1}, {398, 34, 1},
+ {399, 40, 1}, {400, 42, 1}, {401, 0, 1},
+ {403, 44, 1}, {404, 48, 1}, {406, 54, 1},
+ {407, 50, 1}, {408, 0, 1}, {412, 54, 1},
+ {413, 56, 1}, {415, 58, 1}, {416, 1, 6},
+ {422, 62, 1}, {423, 0, 1}, {425, 62, 1},
+ {428, 0, 1}, {430, 62, 1}, {431, 0, 1},
+ {433, 60, 2}, {435, 1, 4}, {439, 64, 1},
{440, 0, 1}, {444, 0, 1}, {452, 2, 1},
{453, 0, 1}, {455, 2, 1}, {456, 0, 1},
{458, 2, 1}, {459, 1, 18}, {478, 1, 18},
- {497, 2, 1}, {498, 1, 4}, {502, 122, 1},
- {503, 134, 1}, {504, 1, 40}, {544, 110, 1},
- {546, 1, 18}, {570, 70, 1}, {571, 0, 1},
- {573, 108, 1}, {574, 68, 1}, {577, 0, 1},
- {579, 106, 1}, {580, 28, 1}, {581, 30, 1},
- {582, 1, 10}, {837, 36, 1}, {880, 1, 4},
- {886, 0, 1}, {902, 18, 1}, {904, 16, 3},
- {908, 26, 1}, {910, 24, 2}, {913, 14, 17},
- {931, 14, 9}, {962, 0, 1}, {975, 4, 1},
- {976, 140, 1}, {977, 142, 1}, {981, 146, 1},
- {982, 144, 1}, {984, 1, 24}, {1008, 136, 1},
- {1009, 138, 1}, {1012, 130, 1}, {1013, 128, 1},
- {1015, 0, 1}, {1017, 152, 1}, {1018, 0, 1},
- {1021, 110, 3}, {1024, 34, 16}, {1040, 14, 32},
- {1120, 1, 34}, {1162, 1, 54}, {1216, 6, 1},
- {1217, 1, 14}, {1232, 1, 88}, {1329, 22, 38},
- {4256, 66, 38}, {4295, 66, 1}, {4301, 66, 1},
- {7680, 1, 150}, {7835, 132, 1}, {7838, 96, 1},
- {7840, 1, 96}, {7944, 150, 8}, {7960, 150, 6},
- {7976, 150, 8}, {7992, 150, 8}, {8008, 150, 6},
- {8025, 151, 8}, {8040, 150, 8}, {8072, 150, 8},
- {8088, 150, 8}, {8104, 150, 8}, {8120, 150, 2},
- {8122, 126, 2}, {8124, 148, 1}, {8126, 100, 1},
- {8136, 124, 4}, {8140, 148, 1}, {8152, 150, 2},
- {8154, 120, 2}, {8168, 150, 2}, {8170, 118, 2},
- {8172, 152, 1}, {8184, 112, 2}, {8186, 114, 2},
- {8188, 148, 1}, {8486, 98, 1}, {8490, 92, 1},
- {8491, 94, 1}, {8498, 12, 1}, {8544, 8, 16},
- {8579, 0, 1}, {9398, 10, 26}, {11264, 22, 47},
- {11360, 0, 1}, {11362, 88, 1}, {11363, 102, 1},
- {11364, 90, 1}, {11367, 1, 6}, {11373, 84, 1},
- {11374, 86, 1}, {11375, 80, 1}, {11376, 82, 1},
- {11378, 0, 1}, {11381, 0, 1}, {11390, 78, 2},
+ {497, 2, 1}, {498, 1, 4}, {502, 162, 1},
+ {503, 174, 1}, {504, 1, 40}, {544, 150, 1},
+ {546, 1, 18}, {570, 74, 1}, {571, 0, 1},
+ {573, 148, 1}, {574, 72, 1}, {577, 0, 1},
+ {579, 146, 1}, {580, 30, 1}, {581, 32, 1},
+ {582, 1, 10}, {837, 38, 1}, {880, 1, 4},
+ {886, 0, 1}, {895, 38, 1}, {902, 20, 1},
+ {904, 18, 3}, {908, 28, 1}, {910, 26, 2},
+ {913, 14, 17}, {931, 14, 9}, {962, 0, 1},
+ {975, 4, 1}, {976, 180, 1}, {977, 182, 1},
+ {981, 186, 1}, {982, 184, 1}, {984, 1, 24},
+ {1008, 176, 1}, {1009, 178, 1}, {1012, 170, 1},
+ {1013, 168, 1}, {1015, 0, 1}, {1017, 192, 1},
+ {1018, 0, 1}, {1021, 150, 3}, {1024, 36, 16},
+ {1040, 14, 32}, {1120, 1, 34}, {1162, 1, 54},
+ {1216, 6, 1}, {1217, 1, 14}, {1232, 1, 96},
+ {1329, 24, 38}, {4256, 70, 38}, {4295, 70, 1},
+ {4301, 70, 1}, {5112, 190, 6}, {7296, 126, 1},
+ {7297, 128, 1}, {7298, 130, 1}, {7299, 134, 2},
+ {7301, 132, 1}, {7302, 136, 1}, {7303, 138, 1},
+ {7304, 100, 1}, {7312, 142, 43}, {7357, 142, 3},
+ {7680, 1, 150}, {7835, 172, 1}, {7838, 120, 1},
+ {7840, 1, 96}, {7944, 190, 8}, {7960, 190, 6},
+ {7976, 190, 8}, {7992, 190, 8}, {8008, 190, 6},
+ {8025, 191, 8}, {8040, 190, 8}, {8072, 190, 8},
+ {8088, 190, 8}, {8104, 190, 8}, {8120, 190, 2},
+ {8122, 166, 2}, {8124, 188, 1}, {8126, 124, 1},
+ {8136, 164, 4}, {8140, 188, 1}, {8152, 190, 2},
+ {8154, 160, 2}, {8168, 190, 2}, {8170, 158, 2},
+ {8172, 192, 1}, {8184, 152, 2}, {8186, 154, 2},
+ {8188, 188, 1}, {8486, 122, 1}, {8490, 116, 1},
+ {8491, 118, 1}, {8498, 12, 1}, {8544, 8, 16},
+ {8579, 0, 1}, {9398, 10, 26}, {11264, 24, 47},
+ {11360, 0, 1}, {11362, 112, 1}, {11363, 140, 1},
+ {11364, 114, 1}, {11367, 1, 6}, {11373, 108, 1},
+ {11374, 110, 1}, {11375, 104, 1}, {11376, 106, 1},
+ {11378, 0, 1}, {11381, 0, 1}, {11390, 102, 2},
{11392, 1, 100}, {11499, 1, 4}, {11506, 0, 1},
- {42560, 1, 46}, {42624, 1, 24}, {42786, 1, 14},
- {42802, 1, 62}, {42873, 1, 4}, {42877, 76, 1},
- {42878, 1, 10}, {42891, 0, 1}, {42893, 74, 1},
- {42896, 1, 4}, {42912, 1, 10}, {42922, 72, 1},
- {65313, 14, 26},
+ {42560, 1, 46}, {42624, 1, 28}, {42786, 1, 14},
+ {42802, 1, 62}, {42873, 1, 4}, {42877, 98, 1},
+ {42878, 1, 10}, {42891, 0, 1}, {42893, 88, 1},
+ {42896, 1, 4}, {42902, 1, 20}, {42922, 80, 1},
+ {42923, 76, 1}, {42924, 78, 1}, {42925, 84, 1},
+ {42926, 80, 1}, {42928, 92, 1}, {42929, 86, 1},
+ {42930, 90, 1}, {42931, 68, 1}, {42932, 1, 12},
+ {42946, 0, 1}, {42948, 178, 1}, {42949, 82, 1},
+ {42950, 96, 1}, {43888, 94, 80}, {65313, 14, 26},
};
static const unsigned short aiOff[] = {
1, 2, 8, 15, 16, 26, 28, 32,
- 37, 38, 40, 48, 63, 64, 69, 71,
- 79, 80, 116, 202, 203, 205, 206, 207,
- 209, 210, 211, 213, 214, 217, 218, 219,
- 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721,
- 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274,
- 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406,
- 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462,
- 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511,
- 65514, 65521, 65527, 65528, 65529,
+ 34, 37, 38, 40, 48, 63, 64, 69,
+ 71, 79, 80, 116, 202, 203, 205, 206,
+ 207, 209, 210, 211, 213, 214, 217, 218,
+ 219, 775, 928, 7264, 10792, 10795, 23217, 23221,
+ 23228, 23229, 23231, 23254, 23256, 23275, 23278, 26672,
+ 30152, 30204, 35267, 54721, 54753, 54754, 54756, 54787,
+ 54793, 54809, 57153, 57274, 57921, 58019, 58363, 59314,
+ 59315, 59324, 59325, 59326, 59332, 59356, 61722, 62528,
+ 65268, 65341, 65373, 65406, 65408, 65410, 65415, 65424,
+ 65436, 65439, 65450, 65462, 65472, 65476, 65478, 65480,
+ 65482, 65488, 65506, 65511, 65514, 65521, 65527, 65528,
+ 65529,
};
int ret = c;
@@ -223078,6 +223972,21 @@ static int sqlite3Fts5UnicodeFold(int c,
else if( c>=66560 && c<66600 ){
ret = c + 40;
}
+ else if( c>=66736 && c<66772 ){
+ ret = c + 40;
+ }
+ else if( c>=68736 && c<68787 ){
+ ret = c + 64;
+ }
+ else if( c>=71840 && c<71872 ){
+ ret = c + 32;
+ }
+ else if( c>=93760 && c<93792 ){
+ ret = c + 32;
+ }
+ else if( c>=125184 && c<125218 ){
+ ret = c + 34;
+ }
return ret;
}
@@ -223201,11 +224110,11 @@ static int sqlite3Fts5UnicodeCatParse(co
return 0;
}
-static u16 aFts5UnicodeBlock[] = {
- 0, 1471, 1753, 1760, 1760, 1760, 1760, 1760, 1760, 1760,
- 1760, 1760, 1760, 1760, 1760, 1763, 1765,
+static const u16 aFts5UnicodeBlock[] = {
+ 0, 1533, 2167, 2178, 2178, 2178, 2178, 2178, 2178, 2178,
+ 2178, 2178, 2178, 2178, 2178, 2181, 2183,
};
-static u16 aFts5UnicodeMap[] = {
+static const u16 aFts5UnicodeMap[] = {
0, 32, 33, 36, 37, 40, 41, 42, 43, 44,
45, 46, 48, 58, 60, 63, 65, 91, 92, 93,
94, 95, 96, 97, 123, 124, 125, 126, 127, 160,
@@ -223220,171 +224129,213 @@ static u16 aFts5UnicodeMap[] = {
497, 498, 499, 500, 503, 505, 506, 564, 570, 572,
573, 575, 577, 580, 583, 584, 592, 660, 661, 688,
706, 710, 722, 736, 741, 748, 749, 750, 751, 768,
- 880, 884, 885, 886, 890, 891, 894, 900, 902, 903,
- 904, 908, 910, 912, 913, 931, 940, 975, 977, 978,
- 981, 984, 1008, 1012, 1014, 1015, 1018, 1020, 1021, 1072,
- 1120, 1154, 1155, 1160, 1162, 1217, 1231, 1232, 1329, 1369,
- 1370, 1377, 1417, 1418, 1423, 1425, 1470, 1471, 1472, 1473,
- 1475, 1476, 1478, 1479, 1488, 1520, 1523, 1536, 1542, 1545,
- 1547, 1548, 1550, 1552, 1563, 1566, 1568, 1600, 1601, 1611,
- 1632, 1642, 1646, 1648, 1649, 1748, 1749, 1750, 1757, 1758,
- 1759, 1765, 1767, 1769, 1770, 1774, 1776, 1786, 1789, 1791,
- 1792, 1807, 1808, 1809, 1810, 1840, 1869, 1958, 1969, 1984,
- 1994, 2027, 2036, 2038, 2039, 2042, 2048, 2070, 2074, 2075,
- 2084, 2085, 2088, 2089, 2096, 2112, 2137, 2142, 2208, 2210,
- 2276, 2304, 2307, 2308, 2362, 2363, 2364, 2365, 2366, 2369,
- 2377, 2381, 2382, 2384, 2385, 2392, 2402, 2404, 2406, 2416,
- 2417, 2418, 2425, 2433, 2434, 2437, 2447, 2451, 2474, 2482,
- 2486, 2492, 2493, 2494, 2497, 2503, 2507, 2509, 2510, 2519,
- 2524, 2527, 2530, 2534, 2544, 2546, 2548, 2554, 2555, 2561,
- 2563, 2565, 2575, 2579, 2602, 2610, 2613, 2616, 2620, 2622,
- 2625, 2631, 2635, 2641, 2649, 2654, 2662, 2672, 2674, 2677,
+ 880, 884, 885, 886, 890, 891, 894, 895, 900, 902,
+ 903, 904, 908, 910, 912, 913, 931, 940, 975, 977,
+ 978, 981, 984, 1008, 1012, 1014, 1015, 1018, 1020, 1021,
+ 1072, 1120, 1154, 1155, 1160, 1162, 1217, 1231, 1232, 1329,
+ 1369, 1370, 1376, 1417, 1418, 1421, 1423, 1425, 1470, 1471,
+ 1472, 1473, 1475, 1476, 1478, 1479, 1488, 1519, 1523, 1536,
+ 1542, 1545, 1547, 1548, 1550, 1552, 1563, 1564, 1566, 1568,
+ 1600, 1601, 1611, 1632, 1642, 1646, 1648, 1649, 1748, 1749,
+ 1750, 1757, 1758, 1759, 1765, 1767, 1769, 1770, 1774, 1776,
+ 1786, 1789, 1791, 1792, 1807, 1808, 1809, 1810, 1840, 1869,
+ 1958, 1969, 1984, 1994, 2027, 2036, 2038, 2039, 2042, 2045,
+ 2046, 2048, 2070, 2074, 2075, 2084, 2085, 2088, 2089, 2096,
+ 2112, 2137, 2142, 2144, 2208, 2230, 2259, 2274, 2275, 2307,
+ 2308, 2362, 2363, 2364, 2365, 2366, 2369, 2377, 2381, 2382,
+ 2384, 2385, 2392, 2402, 2404, 2406, 2416, 2417, 2418, 2433,
+ 2434, 2437, 2447, 2451, 2474, 2482, 2486, 2492, 2493, 2494,
+ 2497, 2503, 2507, 2509, 2510, 2519, 2524, 2527, 2530, 2534,
+ 2544, 2546, 2548, 2554, 2555, 2556, 2557, 2558, 2561, 2563,
+ 2565, 2575, 2579, 2602, 2610, 2613, 2616, 2620, 2622, 2625,
+ 2631, 2635, 2641, 2649, 2654, 2662, 2672, 2674, 2677, 2678,
2689, 2691, 2693, 2703, 2707, 2730, 2738, 2741, 2748, 2749,
2750, 2753, 2759, 2761, 2763, 2765, 2768, 2784, 2786, 2790,
- 2800, 2801, 2817, 2818, 2821, 2831, 2835, 2858, 2866, 2869,
- 2876, 2877, 2878, 2879, 2880, 2881, 2887, 2891, 2893, 2902,
- 2903, 2908, 2911, 2914, 2918, 2928, 2929, 2930, 2946, 2947,
- 2949, 2958, 2962, 2969, 2972, 2974, 2979, 2984, 2990, 3006,
- 3008, 3009, 3014, 3018, 3021, 3024, 3031, 3046, 3056, 3059,
- 3065, 3066, 3073, 3077, 3086, 3090, 3114, 3125, 3133, 3134,
- 3137, 3142, 3146, 3157, 3160, 3168, 3170, 3174, 3192, 3199,
- 3202, 3205, 3214, 3218, 3242, 3253, 3260, 3261, 3262, 3263,
- 3264, 3270, 3271, 3274, 3276, 3285, 3294, 3296, 3298, 3302,
- 3313, 3330, 3333, 3342, 3346, 3389, 3390, 3393, 3398, 3402,
- 3405, 3406, 3415, 3424, 3426, 3430, 3440, 3449, 3450, 3458,
- 3461, 3482, 3507, 3517, 3520, 3530, 3535, 3538, 3542, 3544,
- 3570, 3572, 3585, 3633, 3634, 3636, 3647, 3648, 3654, 3655,
- 3663, 3664, 3674, 3713, 3716, 3719, 3722, 3725, 3732, 3737,
- 3745, 3749, 3751, 3754, 3757, 3761, 3762, 3764, 3771, 3773,
- 3776, 3782, 3784, 3792, 3804, 3840, 3841, 3844, 3859, 3860,
- 3861, 3864, 3866, 3872, 3882, 3892, 3893, 3894, 3895, 3896,
- 3897, 3898, 3899, 3900, 3901, 3902, 3904, 3913, 3953, 3967,
- 3968, 3973, 3974, 3976, 3981, 3993, 4030, 4038, 4039, 4046,
- 4048, 4053, 4057, 4096, 4139, 4141, 4145, 4146, 4152, 4153,
- 4155, 4157, 4159, 4160, 4170, 4176, 4182, 4184, 4186, 4190,
- 4193, 4194, 4197, 4199, 4206, 4209, 4213, 4226, 4227, 4229,
- 4231, 4237, 4238, 4239, 4240, 4250, 4253, 4254, 4256, 4295,
- 4301, 4304, 4347, 4348, 4349, 4682, 4688, 4696, 4698, 4704,
- 4746, 4752, 4786, 4792, 4800, 4802, 4808, 4824, 4882, 4888,
- 4957, 4960, 4969, 4992, 5008, 5024, 5120, 5121, 5741, 5743,
- 5760, 5761, 5787, 5788, 5792, 5867, 5870, 5888, 5902, 5906,
+ 2800, 2801, 2809, 2810, 2817, 2818, 2821, 2831, 2835, 2858,
+ 2866, 2869, 2876, 2877, 2878, 2879, 2880, 2881, 2887, 2891,
+ 2893, 2902, 2903, 2908, 2911, 2914, 2918, 2928, 2929, 2930,
+ 2946, 2947, 2949, 2958, 2962, 2969, 2972, 2974, 2979, 2984,
+ 2990, 3006, 3008, 3009, 3014, 3018, 3021, 3024, 3031, 3046,
+ 3056, 3059, 3065, 3066, 3072, 3073, 3076, 3077, 3086, 3090,
+ 3114, 3133, 3134, 3137, 3142, 3146, 3157, 3160, 3168, 3170,
+ 3174, 3191, 3192, 3199, 3200, 3201, 3202, 3204, 3205, 3214,
+ 3218, 3242, 3253, 3260, 3261, 3262, 3263, 3264, 3270, 3271,
+ 3274, 3276, 3285, 3294, 3296, 3298, 3302, 3313, 3328, 3330,
+ 3333, 3342, 3346, 3387, 3389, 3390, 3393, 3398, 3402, 3405,
+ 3406, 3407, 3412, 3415, 3416, 3423, 3426, 3430, 3440, 3449,
+ 3450, 3458, 3461, 3482, 3507, 3517, 3520, 3530, 3535, 3538,
+ 3542, 3544, 3558, 3570, 3572, 3585, 3633, 3634, 3636, 3647,
+ 3648, 3654, 3655, 3663, 3664, 3674, 3713, 3716, 3718, 3724,
+ 3749, 3751, 3761, 3762, 3764, 3773, 3776, 3782, 3784, 3792,
+ 3804, 3840, 3841, 3844, 3859, 3860, 3861, 3864, 3866, 3872,
+ 3882, 3892, 3893, 3894, 3895, 3896, 3897, 3898, 3899, 3900,
+ 3901, 3902, 3904, 3913, 3953, 3967, 3968, 3973, 3974, 3976,
+ 3981, 3993, 4030, 4038, 4039, 4046, 4048, 4053, 4057, 4096,
+ 4139, 4141, 4145, 4146, 4152, 4153, 4155, 4157, 4159, 4160,
+ 4170, 4176, 4182, 4184, 4186, 4190, 4193, 4194, 4197, 4199,
+ 4206, 4209, 4213, 4226, 4227, 4229, 4231, 4237, 4238, 4239,
+ 4240, 4250, 4253, 4254, 4256, 4295, 4301, 4304, 4347, 4348,
+ 4349, 4352, 4682, 4688, 4696, 4698, 4704, 4746, 4752, 4786,
+ 4792, 4800, 4802, 4808, 4824, 4882, 4888, 4957, 4960, 4969,
+ 4992, 5008, 5024, 5112, 5120, 5121, 5741, 5742, 5743, 5760,
+ 5761, 5787, 5788, 5792, 5867, 5870, 5873, 5888, 5902, 5906,
5920, 5938, 5941, 5952, 5970, 5984, 5998, 6002, 6016, 6068,
6070, 6071, 6078, 6086, 6087, 6089, 6100, 6103, 6104, 6107,
6108, 6109, 6112, 6128, 6144, 6150, 6151, 6155, 6158, 6160,
- 6176, 6211, 6212, 6272, 6313, 6314, 6320, 6400, 6432, 6435,
- 6439, 6441, 6448, 6450, 6451, 6457, 6464, 6468, 6470, 6480,
- 6512, 6528, 6576, 6593, 6600, 6608, 6618, 6622, 6656, 6679,
- 6681, 6686, 6688, 6741, 6742, 6743, 6744, 6752, 6753, 6754,
- 6755, 6757, 6765, 6771, 6783, 6784, 6800, 6816, 6823, 6824,
- 6912, 6916, 6917, 6964, 6965, 6966, 6971, 6972, 6973, 6978,
- 6979, 6981, 6992, 7002, 7009, 7019, 7028, 7040, 7042, 7043,
- 7073, 7074, 7078, 7080, 7082, 7083, 7084, 7086, 7088, 7098,
- 7142, 7143, 7144, 7146, 7149, 7150, 7151, 7154, 7164, 7168,
- 7204, 7212, 7220, 7222, 7227, 7232, 7245, 7248, 7258, 7288,
- 7294, 7360, 7376, 7379, 7380, 7393, 7394, 7401, 7405, 7406,
- 7410, 7412, 7413, 7424, 7468, 7531, 7544, 7545, 7579, 7616,
- 7676, 7680, 7830, 7838, 7936, 7944, 7952, 7960, 7968, 7976,
- 7984, 7992, 8000, 8008, 8016, 8025, 8027, 8029, 8031, 8033,
- 8040, 8048, 8064, 8072, 8080, 8088, 8096, 8104, 8112, 8118,
- 8120, 8124, 8125, 8126, 8127, 8130, 8134, 8136, 8140, 8141,
- 8144, 8150, 8152, 8157, 8160, 8168, 8173, 8178, 8182, 8184,
- 8188, 8189, 8192, 8203, 8208, 8214, 8216, 8217, 8218, 8219,
- 8221, 8222, 8223, 8224, 8232, 8233, 8234, 8239, 8240, 8249,
- 8250, 8251, 8255, 8257, 8260, 8261, 8262, 8263, 8274, 8275,
- 8276, 8277, 8287, 8288, 8298, 8304, 8305, 8308, 8314, 8317,
- 8318, 8319, 8320, 8330, 8333, 8334, 8336, 8352, 8400, 8413,
- 8417, 8418, 8421, 8448, 8450, 8451, 8455, 8456, 8458, 8459,
- 8462, 8464, 8467, 8468, 8469, 8470, 8472, 8473, 8478, 8484,
- 8485, 8486, 8487, 8488, 8489, 8490, 8494, 8495, 8496, 8500,
- 8501, 8505, 8506, 8508, 8510, 8512, 8517, 8519, 8522, 8523,
- 8524, 8526, 8527, 8528, 8544, 8579, 8581, 8585, 8592, 8597,
- 8602, 8604, 8608, 8609, 8611, 8612, 8614, 8615, 8622, 8623,
- 8654, 8656, 8658, 8659, 8660, 8661, 8692, 8960, 8968, 8972,
- 8992, 8994, 9001, 9002, 9003, 9084, 9085, 9115, 9140, 9180,
- 9186, 9216, 9280, 9312, 9372, 9450, 9472, 9655, 9656, 9665,
- 9666, 9720, 9728, 9839, 9840, 9985, 10088, 10089, 10090, 10091,
- 10092, 10093, 10094, 10095, 10096, 10097, 10098, 10099, 10100, 10101,
- 10102, 10132, 10176, 10181, 10182, 10183, 10214, 10215, 10216, 10217,
- 10218, 10219, 10220, 10221, 10222, 10223, 10224, 10240, 10496, 10627,
- 10628, 10629, 10630, 10631, 10632, 10633, 10634, 10635, 10636, 10637,
- 10638, 10639, 10640, 10641, 10642, 10643, 10644, 10645, 10646, 10647,
- 10648, 10649, 10712, 10713, 10714, 10715, 10716, 10748, 10749, 10750,
- 11008, 11056, 11077, 11079, 11088, 11264, 11312, 11360, 11363, 11365,
- 11367, 11374, 11377, 11378, 11380, 11381, 11383, 11388, 11390, 11393,
- 11394, 11492, 11493, 11499, 11503, 11506, 11513, 11517, 11518, 11520,
- 11559, 11565, 11568, 11631, 11632, 11647, 11648, 11680, 11688, 11696,
- 11704, 11712, 11720, 11728, 11736, 11744, 11776, 11778, 11779, 11780,
- 11781, 11782, 11785, 11786, 11787, 11788, 11789, 11790, 11799, 11800,
- 11802, 11803, 11804, 11805, 11806, 11808, 11809, 11810, 11811, 11812,
- 11813, 11814, 11815, 11816, 11817, 11818, 11823, 11824, 11834, 11904,
- 11931, 12032, 12272, 12288, 12289, 12292, 12293, 12294, 12295, 12296,
- 12297, 12298, 12299, 12300, 12301, 12302, 12303, 12304, 12305, 12306,
- 12308, 12309, 12310, 12311, 12312, 12313, 12314, 12315, 12316, 12317,
- 12318, 12320, 12321, 12330, 12334, 12336, 12337, 12342, 12344, 12347,
- 12348, 12349, 12350, 12353, 12441, 12443, 12445, 12447, 12448, 12449,
- 12539, 12540, 12543, 12549, 12593, 12688, 12690, 12694, 12704, 12736,
- 12784, 12800, 12832, 12842, 12872, 12880, 12881, 12896, 12928, 12938,
- 12977, 12992, 13056, 13312, 19893, 19904, 19968, 40908, 40960, 40981,
- 40982, 42128, 42192, 42232, 42238, 42240, 42508, 42509, 42512, 42528,
- 42538, 42560, 42606, 42607, 42608, 42611, 42612, 42622, 42623, 42624,
- 42655, 42656, 42726, 42736, 42738, 42752, 42775, 42784, 42786, 42800,
- 42802, 42864, 42865, 42873, 42878, 42888, 42889, 42891, 42896, 42912,
- 43000, 43002, 43003, 43010, 43011, 43014, 43015, 43019, 43020, 43043,
- 43045, 43047, 43048, 43056, 43062, 43064, 43065, 43072, 43124, 43136,
- 43138, 43188, 43204, 43214, 43216, 43232, 43250, 43256, 43259, 43264,
- 43274, 43302, 43310, 43312, 43335, 43346, 43359, 43360, 43392, 43395,
- 43396, 43443, 43444, 43446, 43450, 43452, 43453, 43457, 43471, 43472,
- 43486, 43520, 43561, 43567, 43569, 43571, 43573, 43584, 43587, 43588,
- 43596, 43597, 43600, 43612, 43616, 43632, 43633, 43639, 43642, 43643,
- 43648, 43696, 43697, 43698, 43701, 43703, 43705, 43710, 43712, 43713,
- 43714, 43739, 43741, 43742, 43744, 43755, 43756, 43758, 43760, 43762,
- 43763, 43765, 43766, 43777, 43785, 43793, 43808, 43816, 43968, 44003,
- 44005, 44006, 44008, 44009, 44011, 44012, 44013, 44016, 44032, 55203,
- 55216, 55243, 55296, 56191, 56319, 57343, 57344, 63743, 63744, 64112,
- 64256, 64275, 64285, 64286, 64287, 64297, 64298, 64312, 64318, 64320,
- 64323, 64326, 64434, 64467, 64830, 64831, 64848, 64914, 65008, 65020,
- 65021, 65024, 65040, 65047, 65048, 65049, 65056, 65072, 65073, 65075,
- 65077, 65078, 65079, 65080, 65081, 65082, 65083, 65084, 65085, 65086,
- 65087, 65088, 65089, 65090, 65091, 65092, 65093, 65095, 65096, 65097,
- 65101, 65104, 65108, 65112, 65113, 65114, 65115, 65116, 65117, 65118,
- 65119, 65122, 65123, 65124, 65128, 65129, 65130, 65136, 65142, 65279,
- 65281, 65284, 65285, 65288, 65289, 65290, 65291, 65292, 65293, 65294,
- 65296, 65306, 65308, 65311, 65313, 65339, 65340, 65341, 65342, 65343,
- 65344, 65345, 65371, 65372, 65373, 65374, 65375, 65376, 65377, 65378,
- 65379, 65380, 65382, 65392, 65393, 65438, 65440, 65474, 65482, 65490,
- 65498, 65504, 65506, 65507, 65508, 65509, 65512, 65513, 65517, 65529,
- 65532, 0, 13, 40, 60, 63, 80, 128, 256, 263,
- 311, 320, 373, 377, 394, 400, 464, 509, 640, 672,
- 768, 800, 816, 833, 834, 842, 896, 927, 928, 968,
- 976, 977, 1024, 1064, 1104, 1184, 2048, 2056, 2058, 2103,
- 2108, 2111, 2135, 2136, 2304, 2326, 2335, 2336, 2367, 2432,
- 2494, 2560, 2561, 2565, 2572, 2576, 2581, 2585, 2616, 2623,
- 2624, 2640, 2656, 2685, 2687, 2816, 2873, 2880, 2904, 2912,
- 2936, 3072, 3680, 4096, 4097, 4098, 4099, 4152, 4167, 4178,
- 4198, 4224, 4226, 4227, 4272, 4275, 4279, 4281, 4283, 4285,
- 4286, 4304, 4336, 4352, 4355, 4391, 4396, 4397, 4406, 4416,
- 4480, 4482, 4483, 4531, 4534, 4543, 4545, 4549, 4560, 5760,
- 5803, 5804, 5805, 5806, 5808, 5814, 5815, 5824, 8192, 9216,
- 9328, 12288, 26624, 28416, 28496, 28497, 28559, 28563, 45056, 53248,
- 53504, 53545, 53605, 53607, 53610, 53613, 53619, 53627, 53635, 53637,
- 53644, 53674, 53678, 53760, 53826, 53829, 54016, 54112, 54272, 54298,
- 54324, 54350, 54358, 54376, 54402, 54428, 54430, 54434, 54437, 54441,
- 54446, 54454, 54459, 54461, 54469, 54480, 54506, 54532, 54535, 54541,
- 54550, 54558, 54584, 54587, 54592, 54598, 54602, 54610, 54636, 54662,
- 54688, 54714, 54740, 54766, 54792, 54818, 54844, 54870, 54896, 54922,
- 54952, 54977, 54978, 55003, 55004, 55010, 55035, 55036, 55061, 55062,
- 55068, 55093, 55094, 55119, 55120, 55126, 55151, 55152, 55177, 55178,
- 55184, 55209, 55210, 55235, 55236, 55242, 55246, 60928, 60933, 60961,
- 60964, 60967, 60969, 60980, 60985, 60987, 60994, 60999, 61001, 61003,
- 61005, 61009, 61012, 61015, 61017, 61019, 61021, 61023, 61025, 61028,
- 61031, 61036, 61044, 61049, 61054, 61056, 61067, 61089, 61093, 61099,
- 61168, 61440, 61488, 61600, 61617, 61633, 61649, 61696, 61712, 61744,
- 61808, 61926, 61968, 62016, 62032, 62208, 62256, 62263, 62336, 62368,
- 62406, 62432, 62464, 62528, 62530, 62713, 62720, 62784, 62800, 62971,
- 63045, 63104, 63232, 0, 42710, 42752, 46900, 46912, 47133, 63488,
- 1, 32, 256, 0, 65533,
+ 6176, 6211, 6212, 6272, 6277, 6279, 6313, 6314, 6320, 6400,
+ 6432, 6435, 6439, 6441, 6448, 6450, 6451, 6457, 6464, 6468,
+ 6470, 6480, 6512, 6528, 6576, 6608, 6618, 6622, 6656, 6679,
+ 6681, 6683, 6686, 6688, 6741, 6742, 6743, 6744, 6752, 6753,
+ 6754, 6755, 6757, 6765, 6771, 6783, 6784, 6800, 6816, 6823,
+ 6824, 6832, 6846, 6912, 6916, 6917, 6964, 6965, 6966, 6971,
+ 6972, 6973, 6978, 6979, 6981, 6992, 7002, 7009, 7019, 7028,
+ 7040, 7042, 7043, 7073, 7074, 7078, 7080, 7082, 7083, 7086,
+ 7088, 7098, 7142, 7143, 7144, 7146, 7149, 7150, 7151, 7154,
+ 7164, 7168, 7204, 7212, 7220, 7222, 7227, 7232, 7245, 7248,
+ 7258, 7288, 7294, 7296, 7312, 7357, 7360, 7376, 7379, 7380,
+ 7393, 7394, 7401, 7405, 7406, 7412, 7413, 7415, 7416, 7418,
+ 7424, 7468, 7531, 7544, 7545, 7579, 7616, 7675, 7680, 7830,
+ 7838, 7936, 7944, 7952, 7960, 7968, 7976, 7984, 7992, 8000,
+ 8008, 8016, 8025, 8027, 8029, 8031, 8033, 8040, 8048, 8064,
+ 8072, 8080, 8088, 8096, 8104, 8112, 8118, 8120, 8124, 8125,
+ 8126, 8127, 8130, 8134, 8136, 8140, 8141, 8144, 8150, 8152,
+ 8157, 8160, 8168, 8173, 8178, 8182, 8184, 8188, 8189, 8192,
+ 8203, 8208, 8214, 8216, 8217, 8218, 8219, 8221, 8222, 8223,
+ 8224, 8232, 8233, 8234, 8239, 8240, 8249, 8250, 8251, 8255,
+ 8257, 8260, 8261, 8262, 8263, 8274, 8275, 8276, 8277, 8287,
+ 8288, 8294, 8304, 8305, 8308, 8314, 8317, 8318, 8319, 8320,
+ 8330, 8333, 8334, 8336, 8352, 8400, 8413, 8417, 8418, 8421,
+ 8448, 8450, 8451, 8455, 8456, 8458, 8459, 8462, 8464, 8467,
+ 8468, 8469, 8470, 8472, 8473, 8478, 8484, 8485, 8486, 8487,
+ 8488, 8489, 8490, 8494, 8495, 8496, 8500, 8501, 8505, 8506,
+ 8508, 8510, 8512, 8517, 8519, 8522, 8523, 8524, 8526, 8527,
+ 8528, 8544, 8579, 8581, 8585, 8586, 8592, 8597, 8602, 8604,
+ 8608, 8609, 8611, 8612, 8614, 8615, 8622, 8623, 8654, 8656,
+ 8658, 8659, 8660, 8661, 8692, 8960, 8968, 8969, 8970, 8971,
+ 8972, 8992, 8994, 9001, 9002, 9003, 9084, 9085, 9115, 9140,
+ 9180, 9186, 9280, 9312, 9372, 9450, 9472, 9655, 9656, 9665,
+ 9666, 9720, 9728, 9839, 9840, 10088, 10089, 10090, 10091, 10092,
+ 10093, 10094, 10095, 10096, 10097, 10098, 10099, 10100, 10101, 10102,
+ 10132, 10176, 10181, 10182, 10183, 10214, 10215, 10216, 10217, 10218,
+ 10219, 10220, 10221, 10222, 10223, 10224, 10240, 10496, 10627, 10628,
+ 10629, 10630, 10631, 10632, 10633, 10634, 10635, 10636, 10637, 10638,
+ 10639, 10640, 10641, 10642, 10643, 10644, 10645, 10646, 10647, 10648,
+ 10649, 10712, 10713, 10714, 10715, 10716, 10748, 10749, 10750, 11008,
+ 11056, 11077, 11079, 11085, 11126, 11160, 11264, 11312, 11360, 11363,
+ 11365, 11367, 11374, 11377, 11378, 11380, 11381, 11383, 11388, 11390,
+ 11393, 11394, 11492, 11493, 11499, 11503, 11506, 11513, 11517, 11518,
+ 11520, 11559, 11565, 11568, 11631, 11632, 11647, 11648, 11680, 11688,
+ 11696, 11704, 11712, 11720, 11728, 11736, 11744, 11776, 11778, 11779,
+ 11780, 11781, 11782, 11785, 11786, 11787, 11788, 11789, 11790, 11799,
+ 11800, 11802, 11803, 11804, 11805, 11806, 11808, 11809, 11810, 11811,
+ 11812, 11813, 11814, 11815, 11816, 11817, 11818, 11823, 11824, 11834,
+ 11836, 11840, 11841, 11842, 11843, 11904, 11931, 12032, 12272, 12288,
+ 12289, 12292, 12293, 12294, 12295, 12296, 12297, 12298, 12299, 12300,
+ 12301, 12302, 12303, 12304, 12305, 12306, 12308, 12309, 12310, 12311,
+ 12312, 12313, 12314, 12315, 12316, 12317, 12318, 12320, 12321, 12330,
+ 12334, 12336, 12337, 12342, 12344, 12347, 12348, 12349, 12350, 12353,
+ 12441, 12443, 12445, 12447, 12448, 12449, 12539, 12540, 12543, 12549,
+ 12593, 12688, 12690, 12694, 12704, 12736, 12784, 12800, 12832, 12842,
+ 12872, 12880, 12881, 12896, 12928, 12938, 12977, 12992, 13312, 19893,
+ 19904, 19968, 40943, 40960, 40981, 40982, 42128, 42192, 42232, 42238,
+ 42240, 42508, 42509, 42512, 42528, 42538, 42560, 42606, 42607, 42608,
+ 42611, 42612, 42622, 42623, 42624, 42652, 42654, 42656, 42726, 42736,
+ 42738, 42752, 42775, 42784, 42786, 42800, 42802, 42864, 42865, 42873,
+ 42878, 42888, 42889, 42891, 42895, 42896, 42900, 42902, 42923, 42927,
+ 42928, 42933, 42934, 42946, 42949, 42999, 43000, 43002, 43003, 43010,
+ 43011, 43014, 43015, 43019, 43020, 43043, 43045, 43047, 43048, 43056,
+ 43062, 43064, 43065, 43072, 43124, 43136, 43138, 43188, 43204, 43214,
+ 43216, 43232, 43250, 43256, 43259, 43260, 43261, 43263, 43264, 43274,
+ 43302, 43310, 43312, 43335, 43346, 43359, 43360, 43392, 43395, 43396,
+ 43443, 43444, 43446, 43450, 43452, 43454, 43457, 43471, 43472, 43486,
+ 43488, 43493, 43494, 43495, 43504, 43514, 43520, 43561, 43567, 43569,
+ 43571, 43573, 43584, 43587, 43588, 43596, 43597, 43600, 43612, 43616,
+ 43632, 43633, 43639, 43642, 43643, 43644, 43645, 43646, 43696, 43697,
+ 43698, 43701, 43703, 43705, 43710, 43712, 43713, 43714, 43739, 43741,
+ 43742, 43744, 43755, 43756, 43758, 43760, 43762, 43763, 43765, 43766,
+ 43777, 43785, 43793, 43808, 43816, 43824, 43867, 43868, 43872, 43888,
+ 43968, 44003, 44005, 44006, 44008, 44009, 44011, 44012, 44013, 44016,
+ 44032, 55203, 55216, 55243, 55296, 56191, 56319, 57343, 57344, 63743,
+ 63744, 64112, 64256, 64275, 64285, 64286, 64287, 64297, 64298, 64312,
+ 64318, 64320, 64323, 64326, 64434, 64467, 64830, 64831, 64848, 64914,
+ 65008, 65020, 65021, 65024, 65040, 65047, 65048, 65049, 65056, 65072,
+ 65073, 65075, 65077, 65078, 65079, 65080, 65081, 65082, 65083, 65084,
+ 65085, 65086, 65087, 65088, 65089, 65090, 65091, 65092, 65093, 65095,
+ 65096, 65097, 65101, 65104, 65108, 65112, 65113, 65114, 65115, 65116,
+ 65117, 65118, 65119, 65122, 65123, 65124, 65128, 65129, 65130, 65136,
+ 65142, 65279, 65281, 65284, 65285, 65288, 65289, 65290, 65291, 65292,
+ 65293, 65294, 65296, 65306, 65308, 65311, 65313, 65339, 65340, 65341,
+ 65342, 65343, 65344, 65345, 65371, 65372, 65373, 65374, 65375, 65376,
+ 65377, 65378, 65379, 65380, 65382, 65392, 65393, 65438, 65440, 65474,
+ 65482, 65490, 65498, 65504, 65506, 65507, 65508, 65509, 65512, 65513,
+ 65517, 65529, 65532, 0, 13, 40, 60, 63, 80, 128,
+ 256, 263, 311, 320, 373, 377, 394, 396, 400, 416,
+ 464, 509, 640, 672, 736, 737, 768, 800, 813, 833,
+ 834, 842, 848, 886, 896, 927, 928, 968, 976, 977,
+ 1024, 1064, 1104, 1184, 1200, 1240, 1280, 1328, 1391, 1536,
+ 1856, 1888, 2048, 2056, 2058, 2103, 2108, 2111, 2135, 2136,
+ 2144, 2167, 2169, 2176, 2215, 2272, 2292, 2299, 2304, 2326,
+ 2335, 2336, 2367, 2432, 2492, 2494, 2496, 2514, 2560, 2561,
+ 2565, 2572, 2576, 2581, 2585, 2616, 2623, 2624, 2640, 2656,
+ 2685, 2687, 2688, 2717, 2752, 2760, 2761, 2789, 2795, 2800,
+ 2816, 2873, 2880, 2904, 2912, 2936, 2944, 2969, 2985, 3072,
+ 3200, 3264, 3322, 3328, 3364, 3376, 3680, 3840, 3869, 3879,
+ 3888, 3910, 3921, 3925, 4064, 4096, 4097, 4098, 4099, 4152,
+ 4167, 4178, 4198, 4223, 4226, 4227, 4272, 4275, 4279, 4281,
+ 4283, 4285, 4286, 4301, 4304, 4336, 4352, 4355, 4391, 4396,
+ 4397, 4406, 4416, 4420, 4421, 4432, 4467, 4468, 4470, 4480,
+ 4482, 4483, 4531, 4534, 4543, 4545, 4549, 4553, 4557, 4560,
+ 4570, 4571, 4572, 4573, 4577, 4608, 4627, 4652, 4655, 4658,
+ 4660, 4661, 4662, 4664, 4670, 4736, 4744, 4746, 4751, 4767,
+ 4777, 4784, 4831, 4832, 4835, 4848, 4864, 4866, 4869, 4879,
+ 4883, 4906, 4914, 4917, 4923, 4925, 4926, 4928, 4929, 4935,
+ 4939, 4944, 4951, 4957, 4962, 4966, 4976, 5120, 5173, 5176,
+ 5184, 5186, 5189, 5190, 5191, 5195, 5200, 5211, 5213, 5214,
+ 5215, 5248, 5296, 5299, 5305, 5306, 5307, 5311, 5313, 5314,
+ 5316, 5318, 5319, 5328, 5504, 5551, 5554, 5560, 5564, 5566,
+ 5567, 5569, 5592, 5596, 5632, 5680, 5683, 5691, 5693, 5694,
+ 5695, 5697, 5700, 5712, 5728, 5760, 5803, 5804, 5805, 5806,
+ 5808, 5814, 5815, 5816, 5824, 5888, 5917, 5920, 5922, 5926,
+ 5927, 5936, 5946, 5948, 5951, 6144, 6188, 6191, 6200, 6201,
+ 6203, 6304, 6336, 6368, 6378, 6399, 6560, 6570, 6609, 6612,
+ 6618, 6620, 6624, 6625, 6626, 6627, 6628, 6656, 6657, 6667,
+ 6707, 6713, 6714, 6715, 6719, 6727, 6736, 6737, 6743, 6745,
+ 6748, 6794, 6807, 6808, 6810, 6813, 6814, 6848, 7168, 7178,
+ 7215, 7216, 7224, 7230, 7231, 7232, 7233, 7248, 7258, 7280,
+ 7282, 7314, 7337, 7338, 7345, 7346, 7348, 7349, 7424, 7432,
+ 7435, 7473, 7482, 7484, 7487, 7494, 7495, 7504, 7520, 7527,
+ 7530, 7562, 7568, 7571, 7573, 7574, 7575, 7576, 7584, 7904,
+ 7923, 7925, 7927, 8128, 8149, 8157, 8161, 8191, 8192, 9216,
+ 9328, 9344, 12288, 13360, 17408, 26624, 27200, 27232, 27246, 27344,
+ 27376, 27381, 27392, 27440, 27447, 27452, 27456, 27460, 27461, 27472,
+ 27483, 27491, 27517, 28224, 28256, 28288, 28311, 28416, 28495, 28496,
+ 28497, 28559, 28563, 28640, 28642, 28643, 28672, 34807, 34816, 45056,
+ 45392, 45412, 45424, 48128, 48240, 48256, 48272, 48284, 48285, 48287,
+ 48288, 53248, 53504, 53545, 53605, 53607, 53610, 53613, 53619, 53627,
+ 53635, 53637, 53644, 53674, 53678, 53760, 53826, 53829, 53984, 54016,
+ 54112, 54272, 54298, 54324, 54350, 54358, 54376, 54402, 54428, 54430,
+ 54434, 54437, 54441, 54446, 54454, 54459, 54461, 54469, 54480, 54506,
+ 54532, 54535, 54541, 54550, 54558, 54584, 54587, 54592, 54598, 54602,
+ 54610, 54636, 54662, 54688, 54714, 54740, 54766, 54792, 54818, 54844,
+ 54870, 54896, 54922, 54952, 54977, 54978, 55003, 55004, 55010, 55035,
+ 55036, 55061, 55062, 55068, 55093, 55094, 55119, 55120, 55126, 55151,
+ 55152, 55177, 55178, 55184, 55209, 55210, 55235, 55236, 55242, 55246,
+ 55296, 55808, 55863, 55867, 55917, 55925, 55926, 55940, 55941, 55943,
+ 55963, 55969, 57344, 57352, 57371, 57379, 57382, 57600, 57648, 57655,
+ 57664, 57678, 57679, 58048, 58092, 58096, 58111, 59392, 59591, 59600,
+ 59648, 59682, 59716, 59723, 59728, 59742, 60529, 60588, 60589, 60592,
+ 60593, 60673, 60718, 60719, 60928, 60933, 60961, 60964, 60967, 60969,
+ 60980, 60985, 60987, 60994, 60999, 61001, 61003, 61005, 61009, 61012,
+ 61015, 61017, 61019, 61021, 61023, 61025, 61028, 61031, 61036, 61044,
+ 61049, 61054, 61056, 61067, 61089, 61093, 61099, 61168, 61440, 61488,
+ 61600, 61617, 61633, 61649, 61696, 61712, 61808, 61926, 61968, 62016,
+ 62032, 62048, 62208, 62459, 62464, 63200, 63216, 63232, 63360, 63456,
+ 63488, 63504, 63568, 63584, 63632, 63744, 63757, 63859, 63866, 63909,
+ 63918, 63949, 64096, 64112, 64120, 64128, 64144, 0, 42710, 42752,
+ 46900, 46912, 47133, 47136, 52897, 52912, 60384, 63488, 1, 32,
+ 256, 0, 65533,
};
-static u16 aFts5UnicodeData[] = {
+static const u16 aFts5UnicodeData[] = {
1025, 61, 117, 55, 117, 54, 50, 53, 57, 53,
49, 85, 333, 85, 121, 85, 841, 54, 53, 50,
56, 48, 56, 837, 54, 57, 50, 57, 1057, 61,
@@ -223399,169 +224350,211 @@ static u16 aFts5UnicodeData[] = {
41, 40, 37, 126, 73, 37, 1886, 197, 73, 37,
73, 69, 126, 105, 37, 286, 2181, 39, 869, 582,
152, 390, 472, 166, 248, 38, 56, 38, 568, 3596,
- 158, 38, 56, 94, 38, 101, 53, 88, 41, 53,
- 105, 41, 73, 37, 553, 297, 1125, 94, 37, 105,
- 101, 798, 133, 94, 57, 126, 94, 37, 1641, 1541,
- 1118, 58, 172, 75, 1790, 478, 37, 2846, 1225, 38,
- 213, 1253, 53, 49, 55, 1452, 49, 44, 53, 76,
- 53, 76, 53, 44, 871, 103, 85, 162, 121, 85,
- 55, 85, 90, 364, 53, 85, 1031, 38, 327, 684,
- 333, 149, 71, 44, 3175, 53, 39, 236, 34, 58,
- 204, 70, 76, 58, 140, 71, 333, 103, 90, 39,
- 469, 34, 39, 44, 967, 876, 2855, 364, 39, 333,
- 1063, 300, 70, 58, 117, 38, 711, 140, 38, 300,
- 38, 108, 38, 172, 501, 807, 108, 53, 39, 359,
- 876, 108, 42, 1735, 44, 42, 44, 39, 106, 268,
- 138, 44, 74, 39, 236, 327, 76, 85, 333, 53,
- 38, 199, 231, 44, 74, 263, 71, 711, 231, 39,
- 135, 44, 39, 106, 140, 74, 74, 44, 39, 42,
- 71, 103, 76, 333, 71, 87, 207, 58, 55, 76,
- 42, 199, 71, 711, 231, 71, 71, 71, 44, 106,
- 76, 76, 108, 44, 135, 39, 333, 76, 103, 44,
+ 158, 38, 56, 94, 38, 101, 53, 41, 88, 41,
+ 53, 105, 41, 73, 37, 553, 297, 1125, 94, 37,
+ 105, 101, 798, 133, 94, 57, 126, 94, 37, 1641,
+ 1541, 1118, 58, 172, 75, 1790, 478, 37, 3102, 1225,
+ 38, 213, 1317, 53, 49, 90, 55, 1452, 49, 44,
+ 53, 76, 53, 76, 53, 44, 871, 135, 85, 194,
+ 121, 85, 55, 85, 90, 364, 53, 34, 85, 1031,
+ 38, 327, 684, 333, 149, 71, 44, 3175, 53, 39,
+ 236, 34, 58, 204, 70, 76, 58, 140, 71, 333,
+ 103, 90, 39, 469, 34, 39, 44, 967, 876, 2855,
+ 364, 39, 333, 1063, 300, 70, 58, 117, 38, 44,
+ 87, 711, 140, 38, 300, 38, 108, 38, 172, 501,
+ 807, 108, 53, 359, 679, 263, 492, 34, 1036, 42,
+ 1735, 44, 42, 44, 39, 106, 268, 138, 44, 74,
+ 39, 236, 327, 76, 85, 333, 53, 38, 487, 44,
+ 74, 263, 71, 711, 231, 39, 135, 44, 39, 106,
+ 140, 74, 74, 44, 39, 42, 71, 103, 76, 333,
+ 71, 87, 207, 58, 55, 39, 53, 44, 76, 42,
+ 199, 71, 711, 231, 71, 71, 71, 44, 106, 76,
+ 76, 108, 44, 135, 39, 333, 76, 103, 44, 53,
76, 42, 295, 103, 711, 231, 71, 167, 44, 39,
106, 172, 76, 42, 74, 44, 39, 71, 76, 333,
- 53, 55, 44, 74, 263, 71, 711, 231, 71, 167,
- 44, 39, 42, 44, 42, 140, 74, 74, 44, 44,
- 42, 71, 103, 76, 333, 58, 39, 207, 44, 39,
- 199, 103, 135, 71, 39, 71, 71, 103, 391, 74,
- 44, 74, 106, 106, 44, 39, 42, 333, 111, 218,
- 55, 58, 106, 263, 103, 743, 327, 167, 39, 108,
- 138, 108, 140, 76, 71, 71, 76, 333, 239, 58,
- 74, 263, 103, 743, 327, 167, 44, 39, 42, 44,
- 170, 44, 74, 74, 76, 74, 39, 71, 76, 333,
- 71, 74, 263, 103, 1319, 39, 106, 140, 106, 106,
- 44, 39, 42, 71, 76, 333, 207, 58, 199, 74,
- 583, 775, 295, 39, 231, 44, 106, 108, 44, 266,
- 74, 53, 1543, 44, 71, 236, 55, 199, 38, 268,
- 53, 333, 85, 71, 39, 71, 39, 39, 135, 231,
- 103, 39, 39, 71, 135, 44, 71, 204, 76, 39,
- 167, 38, 204, 333, 135, 39, 122, 501, 58, 53,
- 122, 76, 218, 333, 335, 58, 44, 58, 44, 58,
- 44, 54, 50, 54, 50, 74, 263, 1159, 460, 42,
- 172, 53, 76, 167, 364, 1164, 282, 44, 218, 90,
- 181, 154, 85, 1383, 74, 140, 42, 204, 42, 76,
- 74, 76, 39, 333, 213, 199, 74, 76, 135, 108,
- 39, 106, 71, 234, 103, 140, 423, 44, 74, 76,
- 202, 44, 39, 42, 333, 106, 44, 90, 1225, 41,
- 41, 1383, 53, 38, 10631, 135, 231, 39, 135, 1319,
- 135, 1063, 135, 231, 39, 135, 487, 1831, 135, 2151,
- 108, 309, 655, 519, 346, 2727, 49, 19847, 85, 551,
- 61, 839, 54, 50, 2407, 117, 110, 423, 135, 108,
+ 53, 55, 39, 204, 44, 74, 263, 71, 711, 231,
+ 71, 167, 44, 39, 42, 44, 42, 140, 74, 74,
+ 44, 44, 42, 71, 103, 76, 333, 58, 39, 207,
+ 44, 39, 199, 103, 135, 71, 39, 71, 71, 103,
+ 391, 74, 44, 74, 106, 106, 44, 39, 42, 333,
+ 111, 218, 55, 58, 44, 106, 44, 263, 103, 743,
+ 519, 39, 108, 138, 108, 140, 76, 103, 71, 76,
+ 333, 53, 239, 58, 39, 44, 74, 53, 263, 103,
+ 743, 327, 167, 44, 39, 42, 44, 170, 44, 74,
+ 74, 76, 74, 39, 71, 76, 333, 71, 76, 74,
+ 263, 103, 1319, 76, 39, 106, 140, 106, 106, 44,
+ 39, 58, 103, 42, 239, 103, 76, 333, 303, 58,
+ 199, 74, 583, 775, 295, 39, 231, 44, 106, 108,
+ 44, 266, 333, 74, 53, 1543, 44, 71, 236, 55,
+ 199, 38, 268, 53, 333, 85, 71, 39, 167, 775,
+ 39, 327, 44, 71, 300, 39, 167, 38, 204, 333,
+ 135, 39, 122, 501, 58, 53, 122, 76, 218, 333,
+ 335, 58, 44, 58, 44, 58, 44, 54, 50, 54,
+ 50, 74, 263, 1159, 460, 42, 172, 53, 76, 167,
+ 364, 1164, 282, 44, 218, 90, 181, 154, 85, 1383,
+ 74, 140, 42, 204, 42, 76, 74, 76, 39, 333,
+ 213, 199, 74, 76, 135, 108, 39, 106, 71, 234,
+ 103, 140, 423, 44, 74, 76, 202, 44, 39, 42,
+ 333, 106, 44, 90, 1225, 41, 41, 1381, 53, 38,
+ 101, 10535, 135, 231, 39, 135, 1319, 135, 1063, 135,
+ 231, 39, 135, 487, 1831, 135, 2151, 108, 309, 655,
+ 519, 346, 2761, 197, 49, 19847, 58, 53, 551, 61,
+ 839, 54, 50, 2407, 117, 110, 263, 423, 135, 108,
583, 108, 85, 583, 76, 423, 103, 76, 1671, 76,
42, 236, 266, 44, 74, 364, 117, 38, 117, 55,
- 39, 44, 333, 335, 213, 49, 149, 108, 61, 333,
- 1127, 38, 1671, 1319, 44, 39, 2247, 935, 108, 138,
- 76, 106, 74, 44, 202, 108, 58, 85, 333, 967,
- 167, 1415, 554, 231, 74, 333, 47, 1114, 743, 76,
- 106, 85, 1703, 42, 44, 42, 236, 44, 42, 44,
- 74, 268, 202, 332, 44, 333, 333, 245, 38, 213,
- 140, 42, 1511, 44, 42, 172, 42, 44, 170, 44,
- 74, 231, 333, 245, 346, 300, 314, 76, 42, 967,
- 42, 140, 74, 76, 42, 44, 74, 71, 333, 1415,
- 44, 42, 76, 106, 44, 42, 108, 74, 149, 1159,
- 266, 268, 74, 76, 181, 333, 103, 333, 967, 198,
- 85, 277, 108, 53, 428, 42, 236, 135, 44, 135,
- 74, 44, 71, 1413, 2022, 421, 38, 1093, 1190, 1260,
- 140, 4830, 261, 3166, 261, 265, 197, 201, 261, 265,
- 261, 265, 197, 201, 261, 41, 41, 41, 94, 229,
- 265, 453, 261, 264, 261, 264, 261, 264, 165, 69,
- 137, 40, 56, 37, 120, 101, 69, 137, 40, 120,
- 133, 69, 137, 120, 261, 169, 120, 101, 69, 137,
- 40, 88, 381, 162, 209, 85, 52, 51, 54, 84,
- 51, 54, 52, 277, 59, 60, 162, 61, 309, 52,
- 51, 149, 80, 117, 57, 54, 50, 373, 57, 53,
- 48, 341, 61, 162, 194, 47, 38, 207, 121, 54,
- 50, 38, 335, 121, 54, 50, 422, 855, 428, 139,
- 44, 107, 396, 90, 41, 154, 41, 90, 37, 105,
- 69, 105, 37, 58, 41, 90, 57, 169, 218, 41,
- 58, 41, 58, 41, 58, 137, 58, 37, 137, 37,
- 135, 37, 90, 69, 73, 185, 94, 101, 58, 57,
- 90, 37, 58, 527, 1134, 94, 142, 47, 185, 186,
- 89, 154, 57, 90, 57, 90, 57, 250, 57, 1018,
- 89, 90, 57, 58, 57, 1018, 8601, 282, 153, 666,
- 89, 250, 54, 50, 2618, 57, 986, 825, 1306, 217,
- 602, 1274, 378, 1935, 2522, 719, 5882, 57, 314, 57,
- 1754, 281, 3578, 57, 4634, 3322, 54, 50, 54, 50,
+ 39, 44, 333, 335, 213, 49, 149, 108, 34, 333,
+ 1127, 38, 1703, 167, 76, 1095, 44, 39, 2247, 999,
+ 108, 138, 76, 106, 74, 44, 202, 108, 58, 85,
+ 333, 967, 167, 1415, 839, 333, 47, 1114, 743, 76,
+ 74, 44, 85, 1703, 42, 44, 42, 236, 44, 42,
+ 44, 74, 268, 202, 332, 44, 333, 333, 245, 38,
+ 213, 460, 43, 140, 42, 1511, 44, 42, 172, 42,
+ 44, 170, 44, 74, 231, 333, 245, 346, 300, 314,
+ 76, 42, 967, 42, 140, 74, 76, 42, 108, 71,
+ 333, 1415, 44, 42, 76, 106, 44, 42, 108, 74,
+ 149, 1159, 266, 268, 74, 76, 181, 333, 103, 333,
+ 967, 198, 85, 293, 1385, 105, 277, 108, 53, 428,
+ 42, 236, 135, 44, 199, 44, 71, 42, 76, 39,
+ 1413, 2022, 421, 38, 1093, 1190, 1868, 172, 4830, 261,
+ 3166, 261, 265, 197, 201, 261, 265, 261, 265, 197,
+ 201, 261, 41, 41, 41, 94, 229, 265, 453, 261,
+ 264, 261, 264, 261, 264, 165, 69, 137, 40, 56,
+ 37, 120, 101, 69, 137, 40, 120, 133, 69, 137,
+ 120, 261, 169, 120, 101, 69, 137, 40, 88, 381,
+ 162, 209, 85, 52, 51, 54, 84, 51, 54, 52,
+ 277, 59, 60, 162, 61, 309, 52, 51, 149, 80,
+ 117, 57, 54, 50, 373, 57, 53, 48, 341, 61,
+ 162, 322, 47, 38, 207, 121, 54, 50, 38, 335,
+ 121, 54, 50, 422, 1047, 428, 139, 44, 107, 396,
+ 90, 41, 154, 41, 90, 37, 105, 69, 105, 37,
+ 58, 41, 90, 57, 169, 218, 41, 58, 41, 58,
+ 41, 58, 137, 58, 37, 137, 37, 135, 37, 90,
+ 69, 73, 185, 94, 101, 58, 57, 90, 37, 58,
+ 527, 1134, 94, 142, 47, 90, 185, 186, 89, 154,
+ 57, 90, 57, 90, 57, 250, 57, 1018, 89, 90,
+ 57, 58, 57, 1018, 8601, 282, 54, 50, 54, 50,
+ 666, 89, 250, 54, 50, 2618, 57, 986, 825, 1306,
+ 217, 2234, 378, 1935, 2522, 719, 5882, 57, 314, 57,
+ 1754, 281, 3578, 57, 7962, 54, 50, 54, 50, 54,
+ 50, 54, 50, 54, 50, 54, 50, 54, 50, 975,
+ 1434, 185, 54, 50, 1017, 54, 50, 54, 50, 54,
+ 50, 54, 50, 54, 50, 537, 8218, 4217, 54, 50,
54, 50, 54, 50, 54, 50, 54, 50, 54, 50,
- 975, 1434, 185, 54, 50, 1017, 54, 50, 54, 50,
- 54, 50, 54, 50, 54, 50, 537, 8218, 4217, 54,
- 50, 54, 50, 54, 50, 54, 50, 54, 50, 54,
- 50, 54, 50, 54, 50, 54, 50, 54, 50, 54,
- 50, 2041, 54, 50, 54, 50, 1049, 54, 50, 8281,
- 1562, 697, 90, 217, 346, 1513, 1509, 126, 73, 69,
- 254, 105, 37, 94, 37, 94, 165, 70, 105, 37,
- 3166, 37, 218, 158, 108, 94, 149, 47, 85, 1221,
- 37, 37, 1799, 38, 53, 44, 743, 231, 231, 231,
- 231, 231, 231, 231, 231, 1036, 85, 52, 51, 52,
- 51, 117, 52, 51, 53, 52, 51, 309, 49, 85,
- 49, 53, 52, 51, 85, 52, 51, 54, 50, 54,
- 50, 54, 50, 54, 50, 181, 38, 341, 81, 858,
- 2874, 6874, 410, 61, 117, 58, 38, 39, 46, 54,
- 50, 54, 50, 54, 50, 54, 50, 54, 50, 90,
- 54, 50, 54, 50, 54, 50, 54, 50, 49, 54,
- 82, 58, 302, 140, 74, 49, 166, 90, 110, 38,
- 39, 53, 90, 2759, 76, 88, 70, 39, 49, 2887,
- 53, 102, 39, 1319, 3015, 90, 143, 346, 871, 1178,
- 519, 1018, 335, 986, 271, 58, 495, 1050, 335, 1274,
- 495, 2042, 8218, 39, 39, 2074, 39, 39, 679, 38,
- 36583, 1786, 1287, 198, 85, 8583, 38, 117, 519, 333,
- 71, 1502, 39, 44, 107, 53, 332, 53, 38, 798,
- 44, 2247, 334, 76, 213, 760, 294, 88, 478, 69,
- 2014, 38, 261, 190, 350, 38, 88, 158, 158, 382,
- 70, 37, 231, 44, 103, 44, 135, 44, 743, 74,
- 76, 42, 154, 207, 90, 55, 58, 1671, 149, 74,
- 1607, 522, 44, 85, 333, 588, 199, 117, 39, 333,
- 903, 268, 85, 743, 364, 74, 53, 935, 108, 42,
- 1511, 44, 74, 140, 74, 44, 138, 437, 38, 333,
- 85, 1319, 204, 74, 76, 74, 76, 103, 44, 263,
- 44, 42, 333, 149, 519, 38, 199, 122, 39, 42,
- 1543, 44, 39, 108, 71, 76, 167, 76, 39, 44,
- 39, 71, 38, 85, 359, 42, 76, 74, 85, 39,
- 70, 42, 44, 199, 199, 199, 231, 231, 1127, 74,
- 44, 74, 44, 74, 53, 42, 44, 333, 39, 39,
- 743, 1575, 36, 68, 68, 36, 63, 63, 11719, 3399,
- 229, 165, 39, 44, 327, 57, 423, 167, 39, 71,
- 71, 3463, 536, 11623, 54, 50, 2055, 1735, 391, 55,
- 58, 524, 245, 54, 50, 53, 236, 53, 81, 80,
54, 50, 54, 50, 54, 50, 54, 50, 54, 50,
- 54, 50, 54, 50, 54, 50, 85, 54, 50, 149,
- 112, 117, 149, 49, 54, 50, 54, 50, 54, 50,
- 117, 57, 49, 121, 53, 55, 85, 167, 4327, 34,
- 117, 55, 117, 54, 50, 53, 57, 53, 49, 85,
- 333, 85, 121, 85, 841, 54, 53, 50, 56, 48,
- 56, 837, 54, 57, 50, 57, 54, 50, 53, 54,
- 50, 85, 327, 38, 1447, 70, 999, 199, 199, 199,
- 103, 87, 57, 56, 58, 87, 58, 153, 90, 98,
- 90, 391, 839, 615, 71, 487, 455, 3943, 117, 1455,
- 314, 1710, 143, 570, 47, 410, 1466, 44, 935, 1575,
- 999, 143, 551, 46, 263, 46, 967, 53, 1159, 263,
- 53, 174, 1289, 1285, 2503, 333, 199, 39, 1415, 71,
- 39, 743, 53, 271, 711, 207, 53, 839, 53, 1799,
- 71, 39, 108, 76, 140, 135, 103, 871, 108, 44,
- 271, 309, 935, 79, 53, 1735, 245, 711, 271, 615,
- 271, 2343, 1007, 42, 44, 42, 1703, 492, 245, 655,
- 333, 76, 42, 1447, 106, 140, 74, 76, 85, 34,
- 149, 807, 333, 108, 1159, 172, 42, 268, 333, 149,
- 76, 42, 1543, 106, 300, 74, 135, 149, 333, 1383,
- 44, 42, 44, 74, 204, 42, 44, 333, 28135, 3182,
- 149, 34279, 18215, 2215, 39, 1482, 140, 422, 71, 7898,
- 1274, 1946, 74, 108, 122, 202, 258, 268, 90, 236,
- 986, 140, 1562, 2138, 108, 58, 2810, 591, 841, 837,
- 841, 229, 581, 841, 837, 41, 73, 41, 73, 137,
- 265, 133, 37, 229, 357, 841, 837, 73, 137, 265,
- 233, 837, 73, 137, 169, 41, 233, 837, 841, 837,
- 841, 837, 841, 837, 841, 837, 841, 837, 841, 901,
- 809, 57, 805, 57, 197, 809, 57, 805, 57, 197,
- 809, 57, 805, 57, 197, 809, 57, 805, 57, 197,
- 809, 57, 805, 57, 197, 94, 1613, 135, 871, 71,
- 39, 39, 327, 135, 39, 39, 39, 39, 39, 39,
- 103, 71, 39, 39, 39, 39, 39, 39, 71, 39,
- 135, 231, 135, 135, 39, 327, 551, 103, 167, 551,
- 89, 1434, 3226, 506, 474, 506, 506, 367, 1018, 1946,
- 1402, 954, 1402, 314, 90, 1082, 218, 2266, 666, 1210,
- 186, 570, 2042, 58, 5850, 154, 2010, 154, 794, 2266,
- 378, 2266, 3738, 39, 39, 39, 39, 39, 39, 17351,
- 34, 3074, 7692, 63, 63,
+ 2041, 54, 50, 54, 50, 1049, 54, 50, 8281, 1562,
+ 697, 90, 217, 1274, 1050, 3354, 1513, 1509, 126, 73,
+ 69, 254, 105, 37, 94, 37, 94, 165, 70, 105,
+ 37, 3166, 37, 218, 158, 108, 94, 149, 47, 85,
+ 1221, 37, 37, 1799, 38, 53, 44, 743, 231, 231,
+ 231, 231, 231, 231, 231, 231, 1036, 85, 52, 51,
+ 52, 51, 117, 52, 51, 53, 52, 51, 309, 49,
+ 85, 49, 53, 52, 51, 85, 52, 51, 54, 50,
+ 54, 50, 54, 50, 54, 50, 181, 38, 341, 81,
+ 149, 49, 53, 54, 437, 858, 2874, 6874, 410, 61,
+ 117, 58, 38, 39, 46, 54, 50, 54, 50, 54,
+ 50, 54, 50, 54, 50, 90, 54, 50, 54, 50,
+ 54, 50, 54, 50, 49, 54, 82, 58, 302, 140,
+ 74, 49, 166, 90, 110, 38, 39, 53, 90, 2759,
+ 76, 88, 70, 39, 49, 2887, 53, 102, 39, 1383,
+ 3015, 90, 143, 346, 871, 1178, 519, 1018, 335, 986,
+ 271, 58, 495, 1050, 335, 1274, 495, 10266, 39, 39,
+ 2074, 39, 39, 679, 38, 36583, 1786, 1287, 198, 85,
+ 8583, 38, 117, 519, 333, 71, 1502, 39, 44, 107,
+ 53, 332, 53, 38, 926, 70, 76, 2247, 334, 76,
+ 213, 760, 294, 88, 478, 69, 2014, 38, 261, 190,
+ 350, 38, 88, 158, 39, 158, 69, 702, 137, 37,
+ 169, 37, 350, 126, 73, 39, 70, 37, 231, 44,
+ 103, 44, 135, 44, 743, 74, 76, 42, 154, 207,
+ 90, 55, 58, 1671, 149, 74, 1607, 522, 76, 85,
+ 333, 588, 199, 117, 39, 53, 71, 44, 333, 903,
+ 268, 85, 743, 364, 74, 53, 935, 108, 42, 1511,
+ 44, 74, 140, 74, 76, 106, 437, 38, 333, 85,
+ 167, 44, 38, 295, 333, 167, 1319, 204, 74, 76,
+ 74, 76, 103, 44, 263, 44, 42, 333, 149, 519,
+ 38, 199, 122, 39, 42, 44, 42, 1607, 44, 39,
+ 108, 71, 76, 167, 76, 39, 44, 39, 71, 38,
+ 85, 359, 42, 76, 74, 85, 39, 70, 42, 44,
+ 199, 199, 199, 231, 231, 1381, 56, 134, 261, 2565,
+ 1127, 74, 44, 74, 44, 74, 53, 42, 44, 333,
+ 39, 39, 743, 1575, 36, 68, 68, 36, 63, 63,
+ 11719, 3399, 229, 165, 39, 44, 327, 57, 423, 167,
+ 39, 71, 71, 3463, 536, 11623, 50, 54, 2055, 1735,
+ 391, 55, 58, 524, 245, 54, 50, 53, 524, 53,
+ 81, 80, 54, 50, 54, 50, 54, 50, 54, 50,
+ 54, 50, 54, 50, 54, 50, 54, 50, 85, 54,
+ 50, 149, 112, 117, 149, 49, 54, 50, 54, 50,
+ 54, 50, 117, 57, 49, 121, 53, 55, 85, 167,
+ 4327, 34, 117, 55, 117, 54, 50, 53, 57, 53,
+ 49, 85, 333, 85, 121, 85, 841, 54, 53, 50,
+ 56, 48, 56, 837, 54, 57, 50, 57, 54, 50,
+ 53, 54, 50, 85, 327, 38, 1447, 70, 999, 199,
+ 199, 199, 103, 87, 57, 56, 58, 87, 58, 153,
+ 90, 98, 90, 391, 839, 615, 71, 487, 455, 3943,
+ 117, 1455, 314, 1710, 143, 570, 79, 122, 410, 58,
+ 1466, 44, 935, 1575, 44, 879, 1031, 143, 647, 46,
+ 263, 46, 1223, 172, 967, 53, 1159, 263, 53, 174,
+ 1289, 1285, 2503, 333, 1161, 1157, 1287, 1671, 53, 9959,
+ 711, 263, 199, 39, 1415, 71, 39, 743, 53, 271,
+ 743, 90, 239, 999, 303, 615, 71, 175, 711, 207,
+ 53, 839, 53, 1799, 79, 71, 527, 1487, 39, 108,
+ 76, 140, 135, 103, 935, 108, 44, 303, 309, 935,
+ 79, 53, 935, 111, 263, 58, 903, 76, 175, 245,
+ 1735, 245, 711, 271, 615, 271, 583, 149, 239, 2343,
+ 1641, 1637, 207, 1159, 140, 333, 1007, 935, 335, 39,
+ 711, 364, 143, 181, 743, 42, 44, 42, 1703, 492,
+ 245, 655, 333, 108, 42, 1447, 106, 140, 74, 76,
+ 85, 34, 149, 34, 807, 333, 108, 1159, 172, 42,
+ 268, 333, 149, 39, 74, 1127, 44, 85, 39, 76,
+ 42, 1543, 106, 300, 74, 135, 149, 140, 53, 333,
+ 39, 53, 39, 117, 655, 583, 807, 106, 108, 74,
+ 44, 42, 76, 213, 44, 231, 39, 135, 487, 327,
+ 53, 1511, 44, 106, 268, 333, 76, 74, 263, 71,
+ 711, 231, 71, 167, 76, 39, 74, 44, 138, 74,
+ 106, 39, 42, 167, 74, 236, 172, 1703, 106, 268,
+ 74, 108, 42, 44, 135, 181, 333, 53, 53, 44,
+ 39, 1543, 106, 204, 42, 44, 138, 76, 42, 76,
+ 71, 53, 39, 333, 1511, 106, 140, 138, 76, 42,
+ 76, 757, 135, 76, 1543, 106, 268, 74, 44, 42,
+ 76, 117, 39, 333, 437, 1383, 44, 42, 44, 74,
+ 204, 42, 44, 39, 333, 871, 108, 74, 140, 42,
+ 172, 333, 79, 117, 58, 1415, 106, 300, 42, 76,
+ 53, 1033, 1029, 333, 303, 39, 263, 1255, 106, 140,
+ 76, 138, 44, 39, 53, 39, 42, 39, 332, 1287,
+ 204, 42, 39, 140, 277, 44, 39, 204, 74, 108,
+ 1479, 428, 42, 76, 117, 39, 181, 1831, 295, 1191,
+ 42, 236, 204, 42, 44, 39, 181, 333, 623, 85,
+ 967, 716, 42, 236, 42, 76, 42, 76, 231, 71,
+ 1223, 204, 44, 76, 236, 39, 44, 333, 199, 71,
+ 1031, 170, 76, 74, 44, 42, 44, 39, 333, 615,
+ 76, 74, 85, 687, 282, 151, 570, 53, 29511, 3566,
+ 181, 6279, 34279, 290, 18663, 18215, 999, 333, 85, 967,
+ 172, 53, 1543, 236, 181, 154, 134, 53, 58, 333,
+ 239, 679, 615, 1033, 1029, 751, 149, 2407, 44, 39,
+ 1770, 140, 422, 70, 53, 38, 39, 39, 24167, 9191,
+ 103, 135, 12679, 3431, 423, 295, 327, 58, 76, 53,
+ 130, 7898, 1274, 1946, 74, 108, 122, 202, 258, 268,
+ 90, 236, 986, 140, 1914, 2138, 108, 58, 655, 2810,
+ 815, 841, 837, 841, 229, 581, 841, 837, 41, 73,
+ 41, 73, 137, 265, 133, 37, 229, 357, 841, 837,
+ 73, 137, 265, 233, 837, 73, 137, 169, 41, 233,
+ 837, 841, 837, 841, 837, 841, 837, 841, 837, 841,
+ 837, 841, 901, 809, 57, 805, 57, 197, 809, 57,
+ 805, 57, 197, 809, 57, 805, 57, 197, 809, 57,
+ 805, 57, 197, 809, 57, 805, 57, 197, 94, 1613,
+ 16410, 1772, 154, 1612, 282, 44, 474, 44, 90, 181,
+ 172, 492, 236, 556, 236, 76, 172, 1447, 236, 230,
+ 333, 39, 58, 1415, 140, 333, 55, 6311, 303, 236,
+ 1097, 1093, 236, 38, 333, 85, 1903, 58, 111, 55,
+ 143, 1455, 58, 495, 135, 871, 71, 39, 39, 327,
+ 135, 39, 39, 39, 39, 39, 39, 103, 71, 39,
+ 39, 39, 39, 39, 39, 71, 39, 135, 231, 135,
+ 135, 39, 327, 551, 103, 167, 551, 89, 1434, 3226,
+ 506, 506, 506, 1210, 431, 3002, 1978, 954, 1434, 314,
+ 90, 218, 8058, 184, 23258, 442, 378, 3738, 2874, 410,
+ 410, 1818, 346, 1306, 986, 410, 3258, 154, 1338, 218,
+ 954, 4346, 474, 154, 122, 122, 218, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 17351, 34, 3074,
+ 7692, 63, 63,
};
static int sqlite3Fts5UnicodeCategory(u32 iCode) {
@@ -223608,6 +224601,7 @@ static void sqlite3Fts5UnicodeAscii(u8 *
}
}
+
/*
** 2015 May 30
**
@@ -224127,7 +225121,7 @@ static int fts5VocabInitVtab(
sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */
char **pzErr /* Write any error message here */
){
- const char *azSchema[] = {
+ const char *const azSchema[] = {
"CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA ")",
"CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")",
"CREATE TABlE vocab(" FTS5_VOCAB_INST_SCHEMA ")"
@@ -224143,12 +225137,12 @@ static int fts5VocabInitVtab(
*pzErr = sqlite3_mprintf("wrong number of vtable arguments");
rc = SQLITE_ERROR;
}else{
- int nByte; /* Bytes of space to allocate */
+ size_t nByte; /* Bytes of space to allocate */
const char *zDb = bDb ? argv[3] : argv[1];
const char *zTab = bDb ? argv[4] : argv[3];
const char *zType = bDb ? argv[5] : argv[4];
- int nDb = (int)strlen(zDb)+1;
- int nTab = (int)strlen(zTab)+1;
+ size_t nDb = strlen(zDb)+1;
+ size_t nTab = strlen(zTab)+1;
int eType = 0;
rc = fts5VocabTableType(zType, pzErr, &eType);
@@ -224319,7 +225313,7 @@ static int fts5VocabOpenMethod(
}
if( rc==SQLITE_OK ){
- int nByte = pFts5->pConfig->nCol * sizeof(i64)*2 + sizeof(Fts5VocabCursor);
+ size_t nByte = pFts5->pConfig->nCol * sizeof(i64)*2 + sizeof(Fts5VocabCursor);
pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte);
}
@@ -224978,7 +225972,7 @@ static int stmtBestIndex(
** This following structure defines all the methods for the
** stmt virtual table.
*/
-static sqlite3_module stmtModule = {
+static const sqlite3_module stmtModule = {
0, /* iVersion */
0, /* xCreate */
stmtConnect, /* xConnect */
@@ -225035,7 +226029,7 @@ SQLITE_API int sqlite3_stmt_init(
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
/************** End of stmt.c ************************************************/
-#if __LINE__!=225038
+#if __LINE__!=226032
#undef SQLITE_SOURCE_ID
#define SQLITE_SOURCE_ID "2019-10-04 15:03:17 c20a35336432025445f9f7e289d0cc3e4003fb17f45a4ce74c6269c407c6alt2"
#endif
--- origsrc/sqlite-autoconf-3300000/sqlite3.h 2019-10-04 18:28:13.000000000 +0200
+++ src/sqlite-autoconf-3300000/sqlite3.h 2019-10-08 13:42:19.054893000 +0200
@@ -2033,6 +2033,8 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */
#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */
+#define SQLITE_CONFIG_MALLOC2 98 /* sqlite3_mem_methods2* */
+#define SQLITE_CONFIG_GETMALLOC2 99 /* sqlite3_mem_methods2* */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -2417,7 +2419,9 @@ SQLITE_API void sqlite3_set_last_insert_
** <li> the [data_version pragma]
** </ul>
*/
-SQLITE_API int sqlite3_changes(sqlite3*);
+SQLITE_API sqlite3_uint64 sqlite3_changes(sqlite3*);
+#define sqlite3_changes(db) ((int)(sqlite3_changes)(db))
+#define sqlite3_changes64(db) ((sqlite3_changes)(db))
/*
** CAPI3REF: Total Number Of Rows Modified
@@ -2454,7 +2458,9 @@ SQLITE_API int sqlite3_changes(sqlite3*)
** <li> the [SQLITE_FCNTL_DATA_VERSION] [file control]
** </ul>
*/
-SQLITE_API int sqlite3_total_changes(sqlite3*);
+SQLITE_API sqlite3_uint64 sqlite3_total_changes(sqlite3*);
+#define sqlite3_total_changes(db) ((int)(sqlite3_total_changes)(db))
+#define sqlite3_total_changes64(db) ((sqlite3_total_changes)(db))
/*
** CAPI3REF: Interrupt A Long-Running Query
@@ -4166,7 +4172,7 @@ typedef struct sqlite3_context sqlite3_c
** See also: [sqlite3_bind_parameter_count()],
** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()].
*/
-SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
+SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, unsigned int n, void(*)(void*));
SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
void(*)(void*));
SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
@@ -4744,8 +4750,8 @@ SQLITE_API sqlite3_int64 sqlite3_column_
SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
+SQLITE_API unsigned int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
+SQLITE_API unsigned int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
/*
@@ -4929,6 +4935,8 @@ SQLITE_API int sqlite3_create_function(
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
+/* A macro is more efficient than a wrapped call */
+#define sqlite3_create_function(a,b,c,d,e,f,g,h) sqlite3_create_function_v2(a,b,c,d,e,f,g,h,0)
SQLITE_API int sqlite3_create_function16(
sqlite3 *db,
const void *zFunctionName,
@@ -5023,9 +5031,12 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3
SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);
SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void);
+#define sqlite3_global_recover() SQLITE_OK
SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void);
+#define sqlite3_thread_cleanup() /**/
SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
void*,sqlite3_int64);
+#define sqlite3_memory_alarm(a,b,c) SQLITE_OK
#endif
/*
@@ -5165,8 +5176,8 @@ SQLITE_API const unsigned char *sqlite3_
SQLITE_API const void *sqlite3_value_text16(sqlite3_value*);
SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*);
SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*);
-SQLITE_API int sqlite3_value_bytes(sqlite3_value*);
-SQLITE_API int sqlite3_value_bytes16(sqlite3_value*);
+SQLITE_API unsigned int sqlite3_value_bytes(sqlite3_value*);
+SQLITE_API unsigned int sqlite3_value_bytes16(sqlite3_value*);
SQLITE_API int sqlite3_value_type(sqlite3_value*);
SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
SQLITE_API int sqlite3_value_nochange(sqlite3_value*);
@@ -5478,7 +5489,7 @@ typedef void (*sqlite3_destructor_type)(
** than the one containing the application-defined function that received
** the [sqlite3_context] pointer, the results are undefined.
*/
-SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
+SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, unsigned int, void(*)(void*));
SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*,
sqlite3_uint64,void(*)(void*));
SQLITE_API void sqlite3_result_double(sqlite3_context*, double);
@@ -5503,6 +5514,19 @@ SQLITE_API int sqlite3_result_zeroblob64
/*
+ * If we are not sure the platform is 32-bit, always use sqlite3_????64()
+ * in stead of sqlite3_????() for certain functions, in order to prevent overflow.
+ */
+#if !defined(i386) && !defined(__i386__) && !defined(_M_IX86) && \
+ !defined(_M_ARM) && !defined(__arm__) && !defined(__x86) && \
+ (!defined(__SIZEOF_POINTER__) || (__SIZEOF_POINTER__ != 4))
+# define sqlite3_bind_blob(pStmt, i, zData, nData, xDel) sqlite3_bind_blob64(pStmt, i, zData, nData, xDel)
+# define sqlite3_result_blob(pCtx, z, n, xDel) sqlite3_result_blob64(pCtx, z, n, xDel)
+# define sqlite3_malloc(x) sqlite3_malloc64(x)
+# define sqlite3_realloc(x,y) sqlite3_realloc64(x,y)
+#endif
+
+/*
** CAPI3REF: Setting The Subtype Of An SQL Function
** METHOD: sqlite3_context
**
@@ -5603,6 +5627,8 @@ SQLITE_API int sqlite3_create_collation(
void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*)
);
+/* A macro is more efficient than a wrapped call */
+#define sqlite3_create_collation(a,b,c,d,e) sqlite3_create_collation_v2(a,b,c,d,e,0)
SQLITE_API int sqlite3_create_collation_v2(
sqlite3*,
const char *zName,
@@ -6177,6 +6203,7 @@ SQLITE_API sqlite3_int64 sqlite3_soft_he
*/
SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
+#define sqlite3_soft_heap_limit(N) sqlite3_soft_heap_limit64(N)
/*
** CAPI3REF: Extract Metadata About A Column Of A Table
@@ -6672,6 +6699,8 @@ SQLITE_API int sqlite3_create_module_v2(
void *pClientData, /* Client data for xCreate/xConnect */
void(*xDestroy)(void*) /* Module destructor function */
);
+/* A macro is more efficient than a (possible future) wrapped call */
+#define sqlite3_create_module(a,b,c,d) sqlite3_create_module_v2(a,b,c,d,0);
/*
** CAPI3REF: Remove Unnecessary Virtual Table Implementations
@@ -8686,6 +8715,8 @@ SQLITE_API int sqlite3_wal_autocheckpoin
** complication) of [sqlite3_wal_checkpoint_v2()].
*/
SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
+/* A macro is more efficient than a wrapped call */
+#define sqlite3_wal_checkpoint(a,b) sqlite3_wal_checkpoint_v2(a,b,SQLITE_CHECKPOINT_PASSIVE,0,0);
/*
** CAPI3REF: Checkpoint a database
@@ -11822,7 +11853,7 @@ struct fts5_api {
fts5_api *pApi,
const char *zName,
void *pContext,
- fts5_tokenizer *pTokenizer,
+ const fts5_tokenizer *pTokenizer,
void (*xDestroy)(void*)
);
--- origsrc/sqlite-autoconf-3300000/sqlite3ext.h 2019-10-04 18:28:13.000000000 +0200
+++ src/sqlite-autoconf-3300000/sqlite3ext.h 2019-10-08 13:42:19.059764100 +0200
@@ -32,7 +32,7 @@
struct sqlite3_api_routines {
void * (*aggregate_context)(sqlite3_context*,int nBytes);
int (*aggregate_count)(sqlite3_context*);
- int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
+ int (*bind_blob)(sqlite3_stmt*,int,const void*,unsigned int,void(*)(void*));
int (*bind_double)(sqlite3_stmt*,int,double);
int (*bind_int)(sqlite3_stmt*,int,int);
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
@@ -40,20 +40,20 @@ struct sqlite3_api_routines {
int (*bind_parameter_count)(sqlite3_stmt*);
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
- int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
+ int (*bind_text)(sqlite3_stmt*,int,const char*,int,void(*)(void*));
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
int (*busy_timeout)(sqlite3*,int ms);
- int (*changes)(sqlite3*);
+ sqlite_uint64 (*changes)(sqlite3*);
int (*close)(sqlite3*);
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
int eTextRep,const char*));
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
int eTextRep,const void*));
const void * (*column_blob)(sqlite3_stmt*,int iCol);
- int (*column_bytes)(sqlite3_stmt*,int iCol);
- int (*column_bytes16)(sqlite3_stmt*,int iCol);
+ unsigned int (*column_bytes)(sqlite3_stmt*,int iCol);
+ unsigned int (*column_bytes16)(sqlite3_stmt*,int iCol);
int (*column_count)(sqlite3_stmt*pStmt);
const char * (*column_database_name)(sqlite3_stmt*,int);
const void * (*column_database_name16)(sqlite3_stmt*,int);
@@ -118,7 +118,7 @@ struct sqlite3_api_routines {
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
void *(*realloc)(void*,int);
int (*reset)(sqlite3_stmt*pStmt);
- void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
+ void (*result_blob)(sqlite3_context*,const void*,unsigned int,void(*)(void*));
void (*result_double)(sqlite3_context*,double);
void (*result_error)(sqlite3_context*,const char*,int);
void (*result_error16)(sqlite3_context*,const void*,int);
@@ -139,15 +139,15 @@ struct sqlite3_api_routines {
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
char const**,char const**,int*,int*,int*);
void (*thread_cleanup)(void);
- int (*total_changes)(sqlite3*);
+ sqlite_uint64 (*total_changes)(sqlite3*);
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
sqlite_int64),void*);
void * (*user_data)(sqlite3_context*);
const void * (*value_blob)(sqlite3_value*);
- int (*value_bytes)(sqlite3_value*);
- int (*value_bytes16)(sqlite3_value*);
+ unsigned int (*value_bytes)(sqlite3_value*);
+ unsigned int (*value_bytes16)(sqlite3_value*);
double (*value_double)(sqlite3_value*);
int (*value_int)(sqlite3_value*);
sqlite_int64 (*value_int64)(sqlite3_value*);
@@ -349,10 +349,9 @@ typedef int (*sqlite3_loadext_entry)(
*/
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
-#ifndef SQLITE_OMIT_DEPRECATED
-#define sqlite3_aggregate_count sqlite3_api->aggregate_count
-#endif
+#ifndef sqlite3_bind_blob
#define sqlite3_bind_blob sqlite3_api->bind_blob
+#endif
#define sqlite3_bind_double sqlite3_api->bind_double
#define sqlite3_bind_int sqlite3_api->bind_int
#define sqlite3_bind_int64 sqlite3_api->bind_int64
@@ -360,12 +359,19 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
+#ifndef sqlite3_bind_text
#define sqlite3_bind_text sqlite3_api->bind_text
+#endif
+#ifndef sqlite3_bind_text16
#define sqlite3_bind_text16 sqlite3_api->bind_text16
+#endif
#define sqlite3_bind_value sqlite3_api->bind_value
#define sqlite3_busy_handler sqlite3_api->busy_handler
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
-#define sqlite3_changes sqlite3_api->changes
+#undef sqlite3_changes
+#define sqlite3_changes (int)sqlite3_api->changes
+#undef sqlite3_changes64
+#define sqlite3_changes64 sqlite3_api->changes
#define sqlite3_close sqlite3_api->close
#define sqlite3_collation_needed sqlite3_api->collation_needed
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
@@ -393,11 +399,14 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_commit_hook sqlite3_api->commit_hook
#define sqlite3_complete sqlite3_api->complete
#define sqlite3_complete16 sqlite3_api->complete16
-#define sqlite3_create_collation sqlite3_api->create_collation
+#undef sqlite3_create_collation
+#define sqlite3_create_collation(a,b,c,d,e) sqlite3_create_collation_v2(a,b,c,d,e,0)
#define sqlite3_create_collation16 sqlite3_api->create_collation16
-#define sqlite3_create_function sqlite3_api->create_function
+#undef sqlite3_create_function
+#define sqlite3_create_function(a,b,c,d,e,f,g,h) sqlite3_create_function_v2(a,b,c,d,e,f,g,h,0)
#define sqlite3_create_function16 sqlite3_api->create_function16
-#define sqlite3_create_module sqlite3_api->create_module
+#undef sqlite3_create_module
+#define sqlite3_create_module(a,b,c,d) sqlite3_create_module_v2(a,b,c,d,0)
#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
#define sqlite3_data_count sqlite3_api->data_count
#define sqlite3_db_handle sqlite3_api->db_handle
@@ -407,23 +416,19 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_errmsg sqlite3_api->errmsg
#define sqlite3_errmsg16 sqlite3_api->errmsg16
#define sqlite3_exec sqlite3_api->exec
-#ifndef SQLITE_OMIT_DEPRECATED
-#define sqlite3_expired sqlite3_api->expired
-#endif
#define sqlite3_finalize sqlite3_api->finalize
#define sqlite3_free sqlite3_api->free
#define sqlite3_free_table sqlite3_api->free_table
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
#define sqlite3_get_table sqlite3_api->get_table
-#ifndef SQLITE_OMIT_DEPRECATED
-#define sqlite3_global_recover sqlite3_api->global_recover
-#endif
#define sqlite3_interrupt sqlite3_api->interruptx
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
#define sqlite3_libversion sqlite3_api->libversion
#define sqlite3_libversion_number sqlite3_api->libversion_number
+#ifndef sqlite3_malloc
#define sqlite3_malloc sqlite3_api->malloc
+#endif
#define sqlite3_mprintf sqlite3_api->mprintf
#define sqlite3_open sqlite3_api->open
#define sqlite3_open16 sqlite3_api->open16
@@ -433,19 +438,31 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
#define sqlite3_profile sqlite3_api->profile
#define sqlite3_progress_handler sqlite3_api->progress_handler
+#ifndef sqlite3_realloc
#define sqlite3_realloc sqlite3_api->realloc
+#endif
#define sqlite3_reset sqlite3_api->reset
+#ifndef sqlite3_result_blob
#define sqlite3_result_blob sqlite3_api->result_blob
+#endif
#define sqlite3_result_double sqlite3_api->result_double
#define sqlite3_result_error sqlite3_api->result_error
#define sqlite3_result_error16 sqlite3_api->result_error16
#define sqlite3_result_int sqlite3_api->result_int
#define sqlite3_result_int64 sqlite3_api->result_int64
#define sqlite3_result_null sqlite3_api->result_null
+#ifndef sqlite3_result_text
#define sqlite3_result_text sqlite3_api->result_text
+#endif
+#ifndef sqlite3_result_text16
#define sqlite3_result_text16 sqlite3_api->result_text16
+#endif
+#ifndef sqlite3_result_text16be
#define sqlite3_result_text16be sqlite3_api->result_text16be
+#endif
+#ifndef sqlite3_result_text16le
#define sqlite3_result_text16le sqlite3_api->result_text16le
+#endif
#define sqlite3_result_value sqlite3_api->result_value
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
@@ -453,12 +470,11 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_snprintf sqlite3_api->xsnprintf
#define sqlite3_step sqlite3_api->step
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
-#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
-#define sqlite3_total_changes sqlite3_api->total_changes
+#undef sqlite3_total_changes
+#define sqlite3_total_changes (int)sqlite3_api->total_changes
+#undef sqlite3_total_changes64
+#define sqlite3_total_changes64 sqlite3_api->total_changes
#define sqlite3_trace sqlite3_api->trace
-#ifndef SQLITE_OMIT_DEPRECATED
-#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
-#endif
#define sqlite3_update_hook sqlite3_api->update_hook
#define sqlite3_user_data sqlite3_api->user_data
#define sqlite3_value_blob sqlite3_api->value_blob
@@ -499,12 +515,13 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
#define sqlite3_sleep sqlite3_api->sleep
-#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
#define sqlite3_vfs_find sqlite3_api->vfs_find
#define sqlite3_vfs_register sqlite3_api->vfs_register
#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
#define sqlite3_threadsafe sqlite3_api->xthreadsafe
+#ifndef sqlite3_result_zeroblob
#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
+#endif
#define sqlite3_result_error_code sqlite3_api->result_error_code
#define sqlite3_test_control sqlite3_api->test_control
#define sqlite3_randomness sqlite3_api->randomness
@@ -533,7 +550,8 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_strnicmp sqlite3_api->strnicmp
#define sqlite3_unlock_notify sqlite3_api->unlock_notify
#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
-#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
+#undef sqlite3_wal_checkpoint
+#define sqlite3_wal_checkpoint(a,b) sqlite3_wal_checkpoint_v2(a,b,SQLITE_CHECKPOINT_PASSIVE,0,0)
#define sqlite3_wal_hook sqlite3_api->wal_hook
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
#define sqlite3_vtab_config sqlite3_api->vtab_config
--- origsrc/sqlite-autoconf-3300000/sqlite3rbu.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/sqlite3rbu.c 2019-03-05 13:14:41.021000000 +0100
@@ -0,0 +1,4946 @@
+/*
+** 2014 August 30
+**
+** 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.
+**
+*************************************************************************
+**
+**
+** OVERVIEW
+**
+** The RBU extension requires that the RBU update be packaged as an
+** SQLite database. The tables it expects to find are described in
+** sqlite3rbu.h. Essentially, for each table xyz in the target database
+** that the user wishes to write to, a corresponding data_xyz table is
+** created in the RBU database and populated with one row for each row to
+** update, insert or delete from the target table.
+**
+** The update proceeds in three stages:
+**
+** 1) The database is updated. The modified database pages are written
+** to a *-oal file. A *-oal file is just like a *-wal file, except
+** that it is named "<database>-oal" instead of "<database>-wal".
+** Because regular SQLite clients do not look for file named
+** "<database>-oal", they go on using the original database in
+** rollback mode while the *-oal file is being generated.
+**
+** During this stage RBU does not update the database by writing
+** directly to the target tables. Instead it creates "imposter"
+** tables using the SQLITE_TESTCTRL_IMPOSTER interface that it uses
+** to update each b-tree individually. All updates required by each
+** b-tree are completed before moving on to the next, and all
+** updates are done in sorted key order.
+**
+** 2) The "<database>-oal" file is moved to the equivalent "<database>-wal"
+** location using a call to rename(2). Before doing this the RBU
+** module takes an EXCLUSIVE lock on the database file, ensuring
+** that there are no other active readers.
+**
+** Once the EXCLUSIVE lock is released, any other database readers
+** detect the new *-wal file and read the database in wal mode. At
+** this point they see the new version of the database - including
+** the updates made as part of the RBU update.
+**
+** 3) The new *-wal file is checkpointed. This proceeds in the same way
+** as a regular database checkpoint, except that a single frame is
+** checkpointed each time sqlite3rbu_step() is called. If the RBU
+** handle is closed before the entire *-wal file is checkpointed,
+** the checkpoint progress is saved in the RBU database and the
+** checkpoint can be resumed by another RBU client at some point in
+** the future.
+**
+** POTENTIAL PROBLEMS
+**
+** The rename() call might not be portable. And RBU is not currently
+** syncing the directory after renaming the file.
+**
+** When state is saved, any commit to the *-oal file and the commit to
+** the RBU update database are not atomic. So if the power fails at the
+** wrong moment they might get out of sync. As the main database will be
+** committed before the RBU update database this will likely either just
+** pass unnoticed, or result in SQLITE_CONSTRAINT errors (due to UNIQUE
+** constraint violations).
+**
+** If some client does modify the target database mid RBU update, or some
+** other error occurs, the RBU extension will keep throwing errors. It's
+** not really clear how to get out of this state. The system could just
+** by delete the RBU update database and *-oal file and have the device
+** download the update again and start over.
+**
+** At present, for an UPDATE, both the new.* and old.* records are
+** collected in the rbu_xyz table. And for both UPDATEs and DELETEs all
+** fields are collected. This means we're probably writing a lot more
+** data to disk when saving the state of an ongoing update to the RBU
+** update database than is strictly necessary.
+**
+*/
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "sqlite3.h"
+
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU)
+#include "sqlite3rbu.h"
+
+#if defined(_WIN32_WCE)
+#include "windows.h"
+#endif
+
+/* Maximum number of prepared UPDATE statements held by this module */
+#define SQLITE_RBU_UPDATE_CACHESIZE 16
+
+/* Delta checksums disabled by default. Compile with -DRBU_ENABLE_DELTA_CKSUM
+** to enable checksum verification.
+*/
+#ifndef RBU_ENABLE_DELTA_CKSUM
+# define RBU_ENABLE_DELTA_CKSUM 0
+#endif
+
+/*
+** Swap two objects of type TYPE.
+*/
+#if !defined(SQLITE_AMALGAMATION)
+# define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;}
+#endif
+
+/*
+** The rbu_state table is used to save the state of a partially applied
+** update so that it can be resumed later. The table consists of integer
+** keys mapped to values as follows:
+**
+** RBU_STATE_STAGE:
+** May be set to integer values 1, 2, 4 or 5. As follows:
+** 1: the *-rbu file is currently under construction.
+** 2: the *-rbu file has been constructed, but not yet moved
+** to the *-wal path.
+** 4: the checkpoint is underway.
+** 5: the rbu update has been checkpointed.
+**
+** RBU_STATE_TBL:
+** Only valid if STAGE==1. The target database name of the table
+** currently being written.
+**
+** RBU_STATE_IDX:
+** Only valid if STAGE==1. The target database name of the index
+** currently being written, or NULL if the main table is currently being
+** updated.
+**
+** RBU_STATE_ROW:
+** Only valid if STAGE==1. Number of rows already processed for the current
+** table/index.
+**
+** RBU_STATE_PROGRESS:
+** Trbul number of sqlite3rbu_step() calls made so far as part of this
+** rbu update.
+**
+** RBU_STATE_CKPT:
+** Valid if STAGE==4. The 64-bit checksum associated with the wal-index
+** header created by recovering the *-wal file. This is used to detect
+** cases when another client appends frames to the *-wal file in the
+** middle of an incremental checkpoint (an incremental checkpoint cannot
+** be continued if this happens).
+**
+** RBU_STATE_COOKIE:
+** Valid if STAGE==1. The current change-counter cookie value in the
+** target db file.
+**
+** RBU_STATE_OALSZ:
+** Valid if STAGE==1. The size in bytes of the *-oal file.
+**
+** RBU_STATE_DATATBL:
+** Only valid if STAGE==1. The RBU database name of the table
+** currently being read.
+*/
+#define RBU_STATE_STAGE 1
+#define RBU_STATE_TBL 2
+#define RBU_STATE_IDX 3
+#define RBU_STATE_ROW 4
+#define RBU_STATE_PROGRESS 5
+#define RBU_STATE_CKPT 6
+#define RBU_STATE_COOKIE 7
+#define RBU_STATE_OALSZ 8
+#define RBU_STATE_PHASEONESTEP 9
+#define RBU_STATE_DATATBL 10
+
+#define RBU_STAGE_OAL 1
+#define RBU_STAGE_MOVE 2
+#define RBU_STAGE_CAPTURE 3
+#define RBU_STAGE_CKPT 4
+#define RBU_STAGE_DONE 5
+
+
+#define RBU_CREATE_STATE \
+ "CREATE TABLE IF NOT EXISTS %s.rbu_state(k INTEGER PRIMARY KEY, v)"
+
+typedef struct RbuFrame RbuFrame;
+typedef struct RbuObjIter RbuObjIter;
+typedef struct RbuState RbuState;
+typedef struct rbu_vfs rbu_vfs;
+typedef struct rbu_file rbu_file;
+typedef struct RbuUpdateStmt RbuUpdateStmt;
+
+#if !defined(SQLITE_AMALGAMATION)
+typedef unsigned int u32;
+typedef unsigned short u16;
+typedef unsigned char u8;
+typedef sqlite3_int64 i64;
+#endif
+
+/*
+** These values must match the values defined in wal.c for the equivalent
+** locks. These are not magic numbers as they are part of the SQLite file
+** format.
+*/
+#define WAL_LOCK_WRITE 0
+#define WAL_LOCK_CKPT 1
+#define WAL_LOCK_READ0 3
+
+#define SQLITE_FCNTL_RBUCNT 5149216
+
+/*
+** A structure to store values read from the rbu_state table in memory.
+*/
+struct RbuState {
+ int eStage;
+ char *zTbl;
+ char *zDataTbl;
+ char *zIdx;
+ i64 iWalCksum;
+ int nRow;
+ i64 nProgress;
+ u32 iCookie;
+ i64 iOalSz;
+ i64 nPhaseOneStep;
+};
+
+struct RbuUpdateStmt {
+ char *zMask; /* Copy of update mask used with pUpdate */
+ sqlite3_stmt *pUpdate; /* Last update statement (or NULL) */
+ RbuUpdateStmt *pNext;
+};
+
+/*
+** An iterator of this type is used to iterate through all objects in
+** the target database that require updating. For each such table, the
+** iterator visits, in order:
+**
+** * the table itself,
+** * each index of the table (zero or more points to visit), and
+** * a special "cleanup table" state.
+**
+** abIndexed:
+** If the table has no indexes on it, abIndexed is set to NULL. Otherwise,
+** it points to an array of flags nTblCol elements in size. The flag is
+** set for each column that is either a part of the PK or a part of an
+** index. Or clear otherwise.
+**
+*/
+struct RbuObjIter {
+ sqlite3_stmt *pTblIter; /* Iterate through tables */
+ sqlite3_stmt *pIdxIter; /* Index iterator */
+ int nTblCol; /* Size of azTblCol[] array */
+ char **azTblCol; /* Array of unquoted target column names */
+ char **azTblType; /* Array of target column types */
+ int *aiSrcOrder; /* src table col -> target table col */
+ u8 *abTblPk; /* Array of flags, set on target PK columns */
+ u8 *abNotNull; /* Array of flags, set on NOT NULL columns */
+ u8 *abIndexed; /* Array of flags, set on indexed & PK cols */
+ int eType; /* Table type - an RBU_PK_XXX value */
+
+ /* Output variables. zTbl==0 implies EOF. */
+ int bCleanup; /* True in "cleanup" state */
+ const char *zTbl; /* Name of target db table */
+ const char *zDataTbl; /* Name of rbu db table (or null) */
+ const char *zIdx; /* Name of target db index (or null) */
+ int iTnum; /* Root page of current object */
+ int iPkTnum; /* If eType==EXTERNAL, root of PK index */
+ int bUnique; /* Current index is unique */
+ int nIndex; /* Number of aux. indexes on table zTbl */
+
+ /* Statements created by rbuObjIterPrepareAll() */
+ int nCol; /* Number of columns in current object */
+ sqlite3_stmt *pSelect; /* Source data */
+ sqlite3_stmt *pInsert; /* Statement for INSERT operations */
+ sqlite3_stmt *pDelete; /* Statement for DELETE ops */
+ sqlite3_stmt *pTmpInsert; /* Insert into rbu_tmp_$zDataTbl */
+
+ /* Last UPDATE used (for PK b-tree updates only), or NULL. */
+ RbuUpdateStmt *pRbuUpdate;
+};
+
+/*
+** Values for RbuObjIter.eType
+**
+** 0: Table does not exist (error)
+** 1: Table has an implicit rowid.
+** 2: Table has an explicit IPK column.
+** 3: Table has an external PK index.
+** 4: Table is WITHOUT ROWID.
+** 5: Table is a virtual table.
+*/
+#define RBU_PK_NOTABLE 0
+#define RBU_PK_NONE 1
+#define RBU_PK_IPK 2
+#define RBU_PK_EXTERNAL 3
+#define RBU_PK_WITHOUT_ROWID 4
+#define RBU_PK_VTAB 5
+
+
+/*
+** Within the RBU_STAGE_OAL stage, each call to sqlite3rbu_step() performs
+** one of the following operations.
+*/
+#define RBU_INSERT 1 /* Insert on a main table b-tree */
+#define RBU_DELETE 2 /* Delete a row from a main table b-tree */
+#define RBU_REPLACE 3 /* Delete and then insert a row */
+#define RBU_IDX_DELETE 4 /* Delete a row from an aux. index b-tree */
+#define RBU_IDX_INSERT 5 /* Insert on an aux. index b-tree */
+
+#define RBU_UPDATE 6 /* Update a row in a main table b-tree */
+
+/*
+** A single step of an incremental checkpoint - frame iWalFrame of the wal
+** file should be copied to page iDbPage of the database file.
+*/
+struct RbuFrame {
+ u32 iDbPage;
+ u32 iWalFrame;
+};
+
+/*
+** RBU handle.
+**
+** nPhaseOneStep:
+** If the RBU database contains an rbu_count table, this value is set to
+** a running estimate of the number of b-tree operations required to
+** finish populating the *-oal file. This allows the sqlite3_bp_progress()
+** API to calculate the permyriadage progress of populating the *-oal file
+** using the formula:
+**
+** permyriadage = (10000 * nProgress) / nPhaseOneStep
+**
+** nPhaseOneStep is initialized to the sum of:
+**
+** nRow * (nIndex + 1)
+**
+** for all source tables in the RBU database, where nRow is the number
+** of rows in the source table and nIndex the number of indexes on the
+** corresponding target database table.
+**
+** This estimate is accurate if the RBU update consists entirely of
+** INSERT operations. However, it is inaccurate if:
+**
+** * the RBU update contains any UPDATE operations. If the PK specified
+** for an UPDATE operation does not exist in the target table, then
+** no b-tree operations are required on index b-trees. Or if the
+** specified PK does exist, then (nIndex*2) such operations are
+** required (one delete and one insert on each index b-tree).
+**
+** * the RBU update contains any DELETE operations for which the specified
+** PK does not exist. In this case no operations are required on index
+** b-trees.
+**
+** * the RBU update contains REPLACE operations. These are similar to
+** UPDATE operations.
+**
+** nPhaseOneStep is updated to account for the conditions above during the
+** first pass of each source table. The updated nPhaseOneStep value is
+** stored in the rbu_state table if the RBU update is suspended.
+*/
+struct sqlite3rbu {
+ int eStage; /* Value of RBU_STATE_STAGE field */
+ sqlite3 *dbMain; /* target database handle */
+ sqlite3 *dbRbu; /* rbu database handle */
+ char *zTarget; /* Path to target db */
+ char *zRbu; /* Path to rbu db */
+ char *zState; /* Path to state db (or NULL if zRbu) */
+ char zStateDb[5]; /* Db name for state ("stat" or "main") */
+ int rc; /* Value returned by last rbu_step() call */
+ char *zErrmsg; /* Error message if rc!=SQLITE_OK */
+ int nStep; /* Rows processed for current object */
+ int nProgress; /* Rows processed for all objects */
+ RbuObjIter objiter; /* Iterator for skipping through tbl/idx */
+ const char *zVfsName; /* Name of automatically created rbu vfs */
+ rbu_file *pTargetFd; /* File handle open on target db */
+ int nPagePerSector; /* Pages per sector for pTargetFd */
+ i64 iOalSz;
+ i64 nPhaseOneStep;
+
+ /* The following state variables are used as part of the incremental
+ ** checkpoint stage (eStage==RBU_STAGE_CKPT). See comments surrounding
+ ** function rbuSetupCheckpoint() for details. */
+ u32 iMaxFrame; /* Largest iWalFrame value in aFrame[] */
+ u32 mLock;
+ int nFrame; /* Entries in aFrame[] array */
+ int nFrameAlloc; /* Allocated size of aFrame[] array */
+ RbuFrame *aFrame;
+ int pgsz;
+ u8 *aBuf;
+ i64 iWalCksum;
+ i64 szTemp; /* Current size of all temp files in use */
+ i64 szTempLimit; /* Total size limit for temp files */
+
+ /* Used in RBU vacuum mode only */
+ int nRbu; /* Number of RBU VFS in the stack */
+ rbu_file *pRbuFd; /* Fd for main db of dbRbu */
+};
+
+/*
+** An rbu VFS is implemented using an instance of this structure.
+**
+** Variable pRbu is only non-NULL for automatically created RBU VFS objects.
+** It is NULL for RBU VFS objects created explicitly using
+** sqlite3rbu_create_vfs(). It is used to track the total amount of temp
+** space used by the RBU handle.
+*/
+struct rbu_vfs {
+ sqlite3_vfs base; /* rbu VFS shim methods */
+ sqlite3_vfs *pRealVfs; /* Underlying VFS */
+ sqlite3_mutex *mutex; /* Mutex to protect pMain */
+ sqlite3rbu *pRbu; /* Owner RBU object */
+ rbu_file *pMain; /* List of main db files */
+ rbu_file *pMainRbu; /* List of main db files with pRbu!=0 */
+};
+
+/*
+** Each file opened by an rbu VFS is represented by an instance of
+** the following structure.
+**
+** If this is a temporary file (pRbu!=0 && flags&DELETE_ON_CLOSE), variable
+** "sz" is set to the current size of the database file.
+*/
+struct rbu_file {
+ sqlite3_file base; /* sqlite3_file methods */
+ sqlite3_file *pReal; /* Underlying file handle */
+ rbu_vfs *pRbuVfs; /* Pointer to the rbu_vfs object */
+ sqlite3rbu *pRbu; /* Pointer to rbu object (rbu target only) */
+ i64 sz; /* Size of file in bytes (temp only) */
+
+ int openFlags; /* Flags this file was opened with */
+ u32 iCookie; /* Cookie value for main db files */
+ u8 iWriteVer; /* "write-version" value for main db files */
+ u8 bNolock; /* True to fail EXCLUSIVE locks */
+
+ int nShm; /* Number of entries in apShm[] array */
+ char **apShm; /* Array of mmap'd *-shm regions */
+ char *zDel; /* Delete this when closing file */
+
+ const char *zWal; /* Wal filename for this main db file */
+ rbu_file *pWalFd; /* Wal file descriptor for this main db */
+ rbu_file *pMainNext; /* Next MAIN_DB file */
+ rbu_file *pMainRbuNext; /* Next MAIN_DB file with pRbu!=0 */
+};
+
+/*
+** True for an RBU vacuum handle, or false otherwise.
+*/
+#define rbuIsVacuum(p) ((p)->zTarget==0)
+
+
+/*************************************************************************
+** The following three functions, found below:
+**
+** rbuDeltaGetInt()
+** rbuDeltaChecksum()
+** rbuDeltaApply()
+**
+** are lifted from the fossil source code (http://fossil-scm.org). They
+** are used to implement the scalar SQL function rbu_fossil_delta().
+*/
+
+/*
+** Read bytes from *pz and convert them into a positive integer. When
+** finished, leave *pz pointing to the first character past the end of
+** the integer. The *pLen parameter holds the length of the string
+** in *pz and is decremented once for each character in the integer.
+*/
+static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){
+ static const signed char zValue[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
+ -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36,
+ -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, -1, -1, -1, 63, -1,
+ };
+ unsigned int v = 0;
+ int c;
+ unsigned char *z = (unsigned char*)*pz;
+ unsigned char *zStart = z;
+ while( (c = zValue[0x7f&*(z++)])>=0 ){
+ v = (v<<6) + c;
+ }
+ z--;
+ *pLen -= z - zStart;
+ *pz = (char*)z;
+ return v;
+}
+
+#if RBU_ENABLE_DELTA_CKSUM
+/*
+** Compute a 32-bit checksum on the N-byte buffer. Return the result.
+*/
+static unsigned int rbuDeltaChecksum(const char *zIn, size_t N){
+ const unsigned char *z = (const unsigned char *)zIn;
+ unsigned sum0 = 0;
+ unsigned sum1 = 0;
+ unsigned sum2 = 0;
+ unsigned sum3 = 0;
+ while(N >= 16){
+ sum0 += ((unsigned)z[0] + z[4] + z[8] + z[12]);
+ sum1 += ((unsigned)z[1] + z[5] + z[9] + z[13]);
+ sum2 += ((unsigned)z[2] + z[6] + z[10]+ z[14]);
+ sum3 += ((unsigned)z[3] + z[7] + z[11]+ z[15]);
+ z += 16;
+ N -= 16;
+ }
+ while(N >= 4){
+ sum0 += z[0];
+ sum1 += z[1];
+ sum2 += z[2];
+ sum3 += z[3];
+ z += 4;
+ N -= 4;
+ }
+ sum3 += (sum2 << 8) + (sum1 << 16) + (sum0 << 24);
+ switch(N){
+ case 3: sum3 += (z[2] << 8);
+ case 2: sum3 += (z[1] << 16);
+ case 1: sum3 += (z[0] << 24);
+ default: ;
+ }
+ return sum3;
+}
+#endif
+
+/*
+** Apply a delta.
+**
+** The output buffer should be big enough to hold the whole output
+** file and a NUL terminator at the end. The delta_output_size()
+** routine will determine this size for you.
+**
+** The delta string should be null-terminated. But the delta string
+** may contain embedded NUL characters (if the input and output are
+** binary files) so we also have to pass in the length of the delta in
+** the lenDelta parameter.
+**
+** This function returns the size of the output file in bytes (excluding
+** the final NUL terminator character). Except, if the delta string is
+** malformed or intended for use with a source file other than zSrc,
+** then this routine returns -1.
+**
+** Refer to the delta_create() documentation above for a description
+** of the delta file format.
+*/
+static int rbuDeltaApply(
+ const char *zSrc, /* The source or pattern file */
+ int lenSrc, /* Length of the source file */
+ const char *zDelta, /* Delta to apply to the pattern */
+ int lenDelta, /* Length of the delta */
+ char *zOut /* Write the output into this preallocated buffer */
+){
+ unsigned int limit;
+ unsigned int total = 0;
+#if RBU_ENABLE_DELTA_CKSUM
+ char *zOrigOut = zOut;
+#endif
+
+ limit = rbuDeltaGetInt(&zDelta, &lenDelta);
+ if( *zDelta!='\n' ){
+ /* ERROR: size integer not terminated by "\n" */
+ return -1;
+ }
+ zDelta++; lenDelta--;
+ while( *zDelta && lenDelta>0 ){
+ unsigned int cnt, ofst;
+ cnt = rbuDeltaGetInt(&zDelta, &lenDelta);
+ switch( zDelta[0] ){
+ case '@': {
+ zDelta++; lenDelta--;
+ ofst = rbuDeltaGetInt(&zDelta, &lenDelta);
+ if( lenDelta>0 && zDelta[0]!=',' ){
+ /* ERROR: copy command not terminated by ',' */
+ return -1;
+ }
+ zDelta++; lenDelta--;
+ total += cnt;
+ if( total>limit ){
+ /* ERROR: copy exceeds output file size */
+ return -1;
+ }
+ if( (int)(ofst+cnt) > lenSrc ){
+ /* ERROR: copy extends past end of input */
+ return -1;
+ }
+ memcpy(zOut, &zSrc[ofst], cnt);
+ zOut += cnt;
+ break;
+ }
+ case ':': {
+ zDelta++; lenDelta--;
+ total += cnt;
+ if( total>limit ){
+ /* ERROR: insert command gives an output larger than predicted */
+ return -1;
+ }
+ if( (int)cnt>lenDelta ){
+ /* ERROR: insert count exceeds size of delta */
+ return -1;
+ }
+ memcpy(zOut, zDelta, cnt);
+ zOut += cnt;
+ zDelta += cnt;
+ lenDelta -= cnt;
+ break;
+ }
+ case ';': {
+ zDelta++; lenDelta--;
+ zOut[0] = 0;
+#if RBU_ENABLE_DELTA_CKSUM
+ if( cnt!=rbuDeltaChecksum(zOrigOut, total) ){
+ /* ERROR: bad checksum */
+ return -1;
+ }
+#endif
+ if( total!=limit ){
+ /* ERROR: generated size does not match predicted size */
+ return -1;
+ }
+ return total;
+ }
+ default: {
+ /* ERROR: unknown delta operator */
+ return -1;
+ }
+ }
+ }
+ /* ERROR: unterminated delta */
+ return -1;
+}
+
+static int rbuDeltaOutputSize(const char *zDelta, int lenDelta){
+ int size;
+ size = rbuDeltaGetInt(&zDelta, &lenDelta);
+ if( *zDelta!='\n' ){
+ /* ERROR: size integer not terminated by "\n" */
+ return -1;
+ }
+ return size;
+}
+
+/*
+** End of code taken from fossil.
+*************************************************************************/
+
+/*
+** Implementation of SQL scalar function rbu_fossil_delta().
+**
+** This function applies a fossil delta patch to a blob. Exactly two
+** arguments must be passed to this function. The first is the blob to
+** patch and the second the patch to apply. If no error occurs, this
+** function returns the patched blob.
+*/
+static void rbuFossilDeltaFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *aDelta;
+ int nDelta;
+ const char *aOrig;
+ int nOrig;
+
+ int nOut;
+ int nOut2;
+ char *aOut;
+
+ assert( argc==2 );
+
+ nOrig = sqlite3_value_bytes(argv[0]);
+ aOrig = (const char*)sqlite3_value_blob(argv[0]);
+ nDelta = sqlite3_value_bytes(argv[1]);
+ aDelta = (const char*)sqlite3_value_blob(argv[1]);
+
+ /* Figure out the size of the output */
+ nOut = rbuDeltaOutputSize(aDelta, nDelta);
+ if( nOut<0 ){
+ sqlite3_result_error(context, "corrupt fossil delta", -1);
+ return;
+ }
+
+ aOut = sqlite3_malloc(nOut+1);
+ if( aOut==0 ){
+ sqlite3_result_error_nomem(context);
+ }else{
+ nOut2 = rbuDeltaApply(aOrig, nOrig, aDelta, nDelta, aOut);
+ if( nOut2!=nOut ){
+ sqlite3_free(aOut);
+ sqlite3_result_error(context, "corrupt fossil delta", -1);
+ }else{
+ sqlite3_result_blob(context, aOut, nOut, sqlite3_free);
+ }
+ }
+}
+
+
+/*
+** Prepare the SQL statement in buffer zSql against database handle db.
+** If successful, set *ppStmt to point to the new statement and return
+** SQLITE_OK.
+**
+** Otherwise, if an error does occur, set *ppStmt to NULL and return
+** an SQLite error code. Additionally, set output variable *pzErrmsg to
+** point to a buffer containing an error message. It is the responsibility
+** of the caller to (eventually) free this buffer using sqlite3_free().
+*/
+static int prepareAndCollectError(
+ sqlite3 *db,
+ sqlite3_stmt **ppStmt,
+ char **pzErrmsg,
+ const char *zSql
+){
+ int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
+ if( rc!=SQLITE_OK ){
+ *pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ *ppStmt = 0;
+ }
+ return rc;
+}
+
+/*
+** Reset the SQL statement passed as the first argument. Return a copy
+** of the value returned by sqlite3_reset().
+**
+** If an error has occurred, then set *pzErrmsg to point to a buffer
+** containing an error message. It is the responsibility of the caller
+** to eventually free this buffer using sqlite3_free().
+*/
+static int resetAndCollectError(sqlite3_stmt *pStmt, char **pzErrmsg){
+ int rc = sqlite3_reset(pStmt);
+ if( rc!=SQLITE_OK ){
+ *pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(sqlite3_db_handle(pStmt)));
+ }
+ return rc;
+}
+
+/*
+** Unless it is NULL, argument zSql points to a buffer allocated using
+** sqlite3_malloc containing an SQL statement. This function prepares the SQL
+** statement against database db and frees the buffer. If statement
+** compilation is successful, *ppStmt is set to point to the new statement
+** handle and SQLITE_OK is returned.
+**
+** Otherwise, if an error occurs, *ppStmt is set to NULL and an error code
+** returned. In this case, *pzErrmsg may also be set to point to an error
+** message. It is the responsibility of the caller to free this error message
+** buffer using sqlite3_free().
+**
+** If argument zSql is NULL, this function assumes that an OOM has occurred.
+** In this case SQLITE_NOMEM is returned and *ppStmt set to NULL.
+*/
+static int prepareFreeAndCollectError(
+ sqlite3 *db,
+ sqlite3_stmt **ppStmt,
+ char **pzErrmsg,
+ char *zSql
+){
+ int rc;
+ assert( *pzErrmsg==0 );
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ *ppStmt = 0;
+ }else{
+ rc = prepareAndCollectError(db, ppStmt, pzErrmsg, zSql);
+ sqlite3_free(zSql);
+ }
+ return rc;
+}
+
+/*
+** Free the RbuObjIter.azTblCol[] and RbuObjIter.abTblPk[] arrays allocated
+** by an earlier call to rbuObjIterCacheTableInfo().
+*/
+static void rbuObjIterFreeCols(RbuObjIter *pIter){
+ int i;
+ for(i=0; i<pIter->nTblCol; i++){
+ sqlite3_free(pIter->azTblCol[i]);
+ sqlite3_free(pIter->azTblType[i]);
+ }
+ sqlite3_free(pIter->azTblCol);
+ pIter->azTblCol = 0;
+ pIter->azTblType = 0;
+ pIter->aiSrcOrder = 0;
+ pIter->abTblPk = 0;
+ pIter->abNotNull = 0;
+ pIter->nTblCol = 0;
+ pIter->eType = 0; /* Invalid value */
+}
+
+/*
+** Finalize all statements and free all allocations that are specific to
+** the current object (table/index pair).
+*/
+static void rbuObjIterClearStatements(RbuObjIter *pIter){
+ RbuUpdateStmt *pUp;
+
+ sqlite3_finalize(pIter->pSelect);
+ sqlite3_finalize(pIter->pInsert);
+ sqlite3_finalize(pIter->pDelete);
+ sqlite3_finalize(pIter->pTmpInsert);
+ pUp = pIter->pRbuUpdate;
+ while( pUp ){
+ RbuUpdateStmt *pTmp = pUp->pNext;
+ sqlite3_finalize(pUp->pUpdate);
+ sqlite3_free(pUp);
+ pUp = pTmp;
+ }
+
+ pIter->pSelect = 0;
+ pIter->pInsert = 0;
+ pIter->pDelete = 0;
+ pIter->pRbuUpdate = 0;
+ pIter->pTmpInsert = 0;
+ pIter->nCol = 0;
+}
+
+/*
+** Clean up any resources allocated as part of the iterator object passed
+** as the only argument.
+*/
+static void rbuObjIterFinalize(RbuObjIter *pIter){
+ rbuObjIterClearStatements(pIter);
+ sqlite3_finalize(pIter->pTblIter);
+ sqlite3_finalize(pIter->pIdxIter);
+ rbuObjIterFreeCols(pIter);
+ memset(pIter, 0, sizeof(RbuObjIter));
+}
+
+/*
+** Advance the iterator to the next position.
+**
+** If no error occurs, SQLITE_OK is returned and the iterator is left
+** pointing to the next entry. Otherwise, an error code and message is
+** left in the RBU handle passed as the first argument. A copy of the
+** error code is returned.
+*/
+static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){
+ int rc = p->rc;
+ if( rc==SQLITE_OK ){
+
+ /* Free any SQLite statements used while processing the previous object */
+ rbuObjIterClearStatements(pIter);
+ if( pIter->zIdx==0 ){
+ rc = sqlite3_exec(p->dbMain,
+ "DROP TRIGGER IF EXISTS temp.rbu_insert_tr;"
+ "DROP TRIGGER IF EXISTS temp.rbu_update1_tr;"
+ "DROP TRIGGER IF EXISTS temp.rbu_update2_tr;"
+ "DROP TRIGGER IF EXISTS temp.rbu_delete_tr;"
+ , 0, 0, &p->zErrmsg
+ );
+ }
+
+ if( rc==SQLITE_OK ){
+ if( pIter->bCleanup ){
+ rbuObjIterFreeCols(pIter);
+ pIter->bCleanup = 0;
+ rc = sqlite3_step(pIter->pTblIter);
+ if( rc!=SQLITE_ROW ){
+ rc = resetAndCollectError(pIter->pTblIter, &p->zErrmsg);
+ pIter->zTbl = 0;
+ }else{
+ pIter->zTbl = (const char*)sqlite3_column_text(pIter->pTblIter, 0);
+ pIter->zDataTbl = (const char*)sqlite3_column_text(pIter->pTblIter,1);
+ rc = (pIter->zDataTbl && pIter->zTbl) ? SQLITE_OK : SQLITE_NOMEM;
+ }
+ }else{
+ if( pIter->zIdx==0 ){
+ sqlite3_stmt *pIdx = pIter->pIdxIter;
+ rc = sqlite3_bind_text(pIdx, 1, pIter->zTbl, -1, SQLITE_STATIC);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_step(pIter->pIdxIter);
+ if( rc!=SQLITE_ROW ){
+ rc = resetAndCollectError(pIter->pIdxIter, &p->zErrmsg);
+ pIter->bCleanup = 1;
+ pIter->zIdx = 0;
+ }else{
+ pIter->zIdx = (const char*)sqlite3_column_text(pIter->pIdxIter, 0);
+ pIter->iTnum = sqlite3_column_int(pIter->pIdxIter, 1);
+ pIter->bUnique = sqlite3_column_int(pIter->pIdxIter, 2);
+ rc = pIter->zIdx ? SQLITE_OK : SQLITE_NOMEM;
+ }
+ }
+ }
+ }
+ }
+
+ if( rc!=SQLITE_OK ){
+ rbuObjIterFinalize(pIter);
+ p->rc = rc;
+ }
+ return rc;
+}
+
+
+/*
+** The implementation of the rbu_target_name() SQL function. This function
+** accepts one or two arguments. The first argument is the name of a table -
+** the name of a table in the RBU database. The second, if it is present, is 1
+** for a view or 0 for a table.
+**
+** For a non-vacuum RBU handle, if the table name matches the pattern:
+**
+** data[0-9]_<name>
+**
+** where <name> is any sequence of 1 or more characters, <name> is returned.
+** Otherwise, if the only argument does not match the above pattern, an SQL
+** NULL is returned.
+**
+** "data_t1" -> "t1"
+** "data0123_t2" -> "t2"
+** "dataAB_t3" -> NULL
+**
+** For an rbu vacuum handle, a copy of the first argument is returned if
+** the second argument is either missing or 0 (not a view).
+*/
+static void rbuTargetNameFunc(
+ sqlite3_context *pCtx,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3rbu *p = sqlite3_user_data(pCtx);
+ const char *zIn;
+ assert( argc==1 || argc==2 );
+
+ zIn = (const char*)sqlite3_value_text(argv[0]);
+ if( zIn ){
+ if( rbuIsVacuum(p) ){
+ if( argc==1 || 0==sqlite3_value_int(argv[1]) ){
+ sqlite3_result_text(pCtx, zIn, -1, SQLITE_STATIC);
+ }
+ }else{
+ if( strlen(zIn)>4 && memcmp("data", zIn, 4)==0 ){
+ int i;
+ for(i=4; zIn[i]>='0' && zIn[i]<='9'; i++);
+ if( zIn[i]=='_' && zIn[i+1] ){
+ sqlite3_result_text(pCtx, &zIn[i+1], -1, SQLITE_STATIC);
+ }
+ }
+ }
+ }
+}
+
+/*
+** Initialize the iterator structure passed as the second argument.
+**
+** If no error occurs, SQLITE_OK is returned and the iterator is left
+** pointing to the first entry. Otherwise, an error code and message is
+** left in the RBU handle passed as the first argument. A copy of the
+** error code is returned.
+*/
+static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
+ int rc;
+ memset(pIter, 0, sizeof(RbuObjIter));
+
+ rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg,
+ sqlite3_mprintf(
+ "SELECT rbu_target_name(name, type='view') AS target, name "
+ "FROM sqlite_master "
+ "WHERE type IN ('table', 'view') AND target IS NOT NULL "
+ " %s "
+ "ORDER BY name"
+ , rbuIsVacuum(p) ? "AND rootpage!=0 AND rootpage IS NOT NULL" : ""));
+
+ if( rc==SQLITE_OK ){
+ rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg,
+ "SELECT name, rootpage, sql IS NULL OR substr(8, 6)=='UNIQUE' "
+ " FROM main.sqlite_master "
+ " WHERE type='index' AND tbl_name = ?"
+ );
+ }
+
+ pIter->bCleanup = 1;
+ p->rc = rc;
+ return rbuObjIterNext(p, pIter);
+}
+
+/*
+** This is a wrapper around "sqlite3_mprintf(zFmt, ...)". If an OOM occurs,
+** an error code is stored in the RBU handle passed as the first argument.
+**
+** If an error has already occurred (p->rc is already set to something other
+** than SQLITE_OK), then this function returns NULL without modifying the
+** stored error code. In this case it still calls sqlite3_free() on any
+** printf() parameters associated with %z conversions.
+*/
+static char *rbuMPrintf(sqlite3rbu *p, const char *zFmt, ...){
+ char *zSql = 0;
+ va_list ap;
+ va_start(ap, zFmt);
+ zSql = sqlite3_vmprintf(zFmt, ap);
+ if( p->rc==SQLITE_OK ){
+ if( zSql==0 ) p->rc = SQLITE_NOMEM;
+ }else{
+ sqlite3_free(zSql);
+ zSql = 0;
+ }
+ va_end(ap);
+ return zSql;
+}
+
+/*
+** Argument zFmt is a sqlite3_mprintf() style format string. The trailing
+** arguments are the usual subsitution values. This function performs
+** the printf() style substitutions and executes the result as an SQL
+** statement on the RBU handles database.
+**
+** If an error occurs, an error code and error message is stored in the
+** RBU handle. If an error has already occurred when this function is
+** called, it is a no-op.
+*/
+static int rbuMPrintfExec(sqlite3rbu *p, sqlite3 *db, const char *zFmt, ...){
+ va_list ap;
+ char *zSql;
+ va_start(ap, zFmt);
+ zSql = sqlite3_vmprintf(zFmt, ap);
+ if( p->rc==SQLITE_OK ){
+ if( zSql==0 ){
+ p->rc = SQLITE_NOMEM;
+ }else{
+ p->rc = sqlite3_exec(db, zSql, 0, 0, &p->zErrmsg);
+ }
+ }
+ sqlite3_free(zSql);
+ va_end(ap);
+ return p->rc;
+}
+
+/*
+** Attempt to allocate and return a pointer to a zeroed block of nByte
+** bytes.
+**
+** If an error (i.e. an OOM condition) occurs, return NULL and leave an
+** error code in the rbu handle passed as the first argument. Or, if an
+** error has already occurred when this function is called, return NULL
+** immediately without attempting the allocation or modifying the stored
+** error code.
+*/
+static void *rbuMalloc(sqlite3rbu *p, int nByte){
+ void *pRet = 0;
+ if( p->rc==SQLITE_OK ){
+ assert( nByte>0 );
+ pRet = sqlite3_malloc(nByte);
+ if( pRet==0 ){
+ p->rc = SQLITE_NOMEM;
+ }else{
+ memset(pRet, 0, nByte);
+ }
+ }
+ return pRet;
+}
+
+
+/*
+** Allocate and zero the pIter->azTblCol[] and abTblPk[] arrays so that
+** there is room for at least nCol elements. If an OOM occurs, store an
+** error code in the RBU handle passed as the first argument.
+*/
+static void rbuAllocateIterArrays(sqlite3rbu *p, RbuObjIter *pIter, int nCol){
+ int nByte = (2*sizeof(char*) + sizeof(int) + 3*sizeof(u8)) * nCol;
+ char **azNew;
+
+ azNew = (char**)rbuMalloc(p, nByte);
+ if( azNew ){
+ pIter->azTblCol = azNew;
+ pIter->azTblType = &azNew[nCol];
+ pIter->aiSrcOrder = (int*)&pIter->azTblType[nCol];
+ pIter->abTblPk = (u8*)&pIter->aiSrcOrder[nCol];
+ pIter->abNotNull = (u8*)&pIter->abTblPk[nCol];
+ pIter->abIndexed = (u8*)&pIter->abNotNull[nCol];
+ }
+}
+
+/*
+** The first argument must be a nul-terminated string. This function
+** returns a copy of the string in memory obtained from sqlite3_malloc().
+** It is the responsibility of the caller to eventually free this memory
+** using sqlite3_free().
+**
+** If an OOM condition is encountered when attempting to allocate memory,
+** output variable (*pRc) is set to SQLITE_NOMEM before returning. Otherwise,
+** if the allocation succeeds, (*pRc) is left unchanged.
+*/
+static char *rbuStrndup(const char *zStr, int *pRc){
+ char *zRet = 0;
+
+ assert( *pRc==SQLITE_OK );
+ if( zStr ){
+ size_t nCopy = strlen(zStr) + 1;
+ zRet = (char*)sqlite3_malloc(nCopy);
+ if( zRet ){
+ memcpy(zRet, zStr, nCopy);
+ }else{
+ *pRc = SQLITE_NOMEM;
+ }
+ }
+
+ return zRet;
+}
+
+/*
+** Finalize the statement passed as the second argument.
+**
+** If the sqlite3_finalize() call indicates that an error occurs, and the
+** rbu handle error code is not already set, set the error code and error
+** message accordingly.
+*/
+static void rbuFinalize(sqlite3rbu *p, sqlite3_stmt *pStmt){
+ sqlite3 *db = sqlite3_db_handle(pStmt);
+ int rc = sqlite3_finalize(pStmt);
+ if( p->rc==SQLITE_OK && rc!=SQLITE_OK ){
+ p->rc = rc;
+ p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ }
+}
+
+/* Determine the type of a table.
+**
+** peType is of type (int*), a pointer to an output parameter of type
+** (int). This call sets the output parameter as follows, depending
+** on the type of the table specified by parameters dbName and zTbl.
+**
+** RBU_PK_NOTABLE: No such table.
+** RBU_PK_NONE: Table has an implicit rowid.
+** RBU_PK_IPK: Table has an explicit IPK column.
+** RBU_PK_EXTERNAL: Table has an external PK index.
+** RBU_PK_WITHOUT_ROWID: Table is WITHOUT ROWID.
+** RBU_PK_VTAB: Table is a virtual table.
+**
+** Argument *piPk is also of type (int*), and also points to an output
+** parameter. Unless the table has an external primary key index
+** (i.e. unless *peType is set to 3), then *piPk is set to zero. Or,
+** if the table does have an external primary key index, then *piPk
+** is set to the root page number of the primary key index before
+** returning.
+**
+** ALGORITHM:
+**
+** if( no entry exists in sqlite_master ){
+** return RBU_PK_NOTABLE
+** }else if( sql for the entry starts with "CREATE VIRTUAL" ){
+** return RBU_PK_VTAB
+** }else if( "PRAGMA index_list()" for the table contains a "pk" index ){
+** if( the index that is the pk exists in sqlite_master ){
+** *piPK = rootpage of that index.
+** return RBU_PK_EXTERNAL
+** }else{
+** return RBU_PK_WITHOUT_ROWID
+** }
+** }else if( "PRAGMA table_info()" lists one or more "pk" columns ){
+** return RBU_PK_IPK
+** }else{
+** return RBU_PK_NONE
+** }
+*/
+static void rbuTableType(
+ sqlite3rbu *p,
+ const char *zTab,
+ int *peType,
+ int *piTnum,
+ int *piPk
+){
+ /*
+ ** 0) SELECT count(*) FROM sqlite_master where name=%Q AND IsVirtual(%Q)
+ ** 1) PRAGMA index_list = ?
+ ** 2) SELECT count(*) FROM sqlite_master where name=%Q
+ ** 3) PRAGMA table_info = ?
+ */
+ sqlite3_stmt *aStmt[4] = {0, 0, 0, 0};
+
+ *peType = RBU_PK_NOTABLE;
+ *piPk = 0;
+
+ assert( p->rc==SQLITE_OK );
+ p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[0], &p->zErrmsg,
+ sqlite3_mprintf(
+ "SELECT (sql LIKE 'create virtual%%'), rootpage"
+ " FROM sqlite_master"
+ " WHERE name=%Q", zTab
+ ));
+ if( p->rc!=SQLITE_OK || sqlite3_step(aStmt[0])!=SQLITE_ROW ){
+ /* Either an error, or no such table. */
+ goto rbuTableType_end;
+ }
+ if( sqlite3_column_int(aStmt[0], 0) ){
+ *peType = RBU_PK_VTAB; /* virtual table */
+ goto rbuTableType_end;
+ }
+ *piTnum = sqlite3_column_int(aStmt[0], 1);
+
+ p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[1], &p->zErrmsg,
+ sqlite3_mprintf("PRAGMA index_list=%Q",zTab)
+ );
+ if( p->rc ) goto rbuTableType_end;
+ while( sqlite3_step(aStmt[1])==SQLITE_ROW ){
+ const u8 *zOrig = sqlite3_column_text(aStmt[1], 3);
+ const u8 *zIdx = sqlite3_column_text(aStmt[1], 1);
+ if( zOrig && zIdx && zOrig[0]=='p' ){
+ p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[2], &p->zErrmsg,
+ sqlite3_mprintf(
+ "SELECT rootpage FROM sqlite_master WHERE name = %Q", zIdx
+ ));
+ if( p->rc==SQLITE_OK ){
+ if( sqlite3_step(aStmt[2])==SQLITE_ROW ){
+ *piPk = sqlite3_column_int(aStmt[2], 0);
+ *peType = RBU_PK_EXTERNAL;
+ }else{
+ *peType = RBU_PK_WITHOUT_ROWID;
+ }
+ }
+ goto rbuTableType_end;
+ }
+ }
+
+ p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[3], &p->zErrmsg,
+ sqlite3_mprintf("PRAGMA table_info=%Q",zTab)
+ );
+ if( p->rc==SQLITE_OK ){
+ while( sqlite3_step(aStmt[3])==SQLITE_ROW ){
+ if( sqlite3_column_int(aStmt[3],5)>0 ){
+ *peType = RBU_PK_IPK; /* explicit IPK column */
+ goto rbuTableType_end;
+ }
+ }
+ *peType = RBU_PK_NONE;
+ }
+
+rbuTableType_end: {
+ unsigned int i;
+ for(i=0; i<sizeof(aStmt)/sizeof(aStmt[0]); i++){
+ rbuFinalize(p, aStmt[i]);
+ }
+ }
+}
+
+/*
+** This is a helper function for rbuObjIterCacheTableInfo(). It populates
+** the pIter->abIndexed[] array.
+*/
+static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
+ sqlite3_stmt *pList = 0;
+ int bIndex = 0;
+
+ if( p->rc==SQLITE_OK ){
+ memcpy(pIter->abIndexed, pIter->abTblPk, sizeof(u8)*pIter->nTblCol);
+ p->rc = prepareFreeAndCollectError(p->dbMain, &pList, &p->zErrmsg,
+ sqlite3_mprintf("PRAGMA main.index_list = %Q", pIter->zTbl)
+ );
+ }
+
+ pIter->nIndex = 0;
+ while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){
+ const char *zIdx = (const char*)sqlite3_column_text(pList, 1);
+ sqlite3_stmt *pXInfo = 0;
+ if( zIdx==0 ) break;
+ p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg,
+ sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx)
+ );
+ while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){
+ int iCid = sqlite3_column_int(pXInfo, 1);
+ if( iCid>=0 ) pIter->abIndexed[iCid] = 1;
+ }
+ rbuFinalize(p, pXInfo);
+ bIndex = 1;
+ pIter->nIndex++;
+ }
+
+ if( pIter->eType==RBU_PK_WITHOUT_ROWID ){
+ /* "PRAGMA index_list" includes the main PK b-tree */
+ pIter->nIndex--;
+ }
+
+ rbuFinalize(p, pList);
+ if( bIndex==0 ) pIter->abIndexed = 0;
+}
+
+
+/*
+** If they are not already populated, populate the pIter->azTblCol[],
+** pIter->abTblPk[], pIter->nTblCol and pIter->bRowid variables according to
+** the table (not index) that the iterator currently points to.
+**
+** Return SQLITE_OK if successful, or an SQLite error code otherwise. If
+** an error does occur, an error code and error message are also left in
+** the RBU handle.
+*/
+static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
+ if( pIter->azTblCol==0 ){
+ sqlite3_stmt *pStmt = 0;
+ int nCol = 0;
+ int i; /* for() loop iterator variable */
+ int bRbuRowid = 0; /* If input table has column "rbu_rowid" */
+ int iOrder = 0;
+ int iTnum = 0;
+
+ /* Figure out the type of table this step will deal with. */
+ assert( pIter->eType==0 );
+ rbuTableType(p, pIter->zTbl, &pIter->eType, &iTnum, &pIter->iPkTnum);
+ if( p->rc==SQLITE_OK && pIter->eType==RBU_PK_NOTABLE ){
+ p->rc = SQLITE_ERROR;
+ p->zErrmsg = sqlite3_mprintf("no such table: %s", pIter->zTbl);
+ }
+ if( p->rc ) return p->rc;
+ if( pIter->zIdx==0 ) pIter->iTnum = iTnum;
+
+ assert( pIter->eType==RBU_PK_NONE || pIter->eType==RBU_PK_IPK
+ || pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_WITHOUT_ROWID
+ || pIter->eType==RBU_PK_VTAB
+ );
+
+ /* Populate the azTblCol[] and nTblCol variables based on the columns
+ ** of the input table. Ignore any input table columns that begin with
+ ** "rbu_". */
+ p->rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
+ sqlite3_mprintf("SELECT * FROM '%q'", pIter->zDataTbl)
+ );
+ if( p->rc==SQLITE_OK ){
+ nCol = sqlite3_column_count(pStmt);
+ rbuAllocateIterArrays(p, pIter, nCol);
+ }
+ for(i=0; p->rc==SQLITE_OK && i<nCol; i++){
+ const char *zName = (const char*)sqlite3_column_name(pStmt, i);
+ if( sqlite3_strnicmp("rbu_", zName, 4) ){
+ char *zCopy = rbuStrndup(zName, &p->rc);
+ pIter->aiSrcOrder[pIter->nTblCol] = pIter->nTblCol;
+ pIter->azTblCol[pIter->nTblCol++] = zCopy;
+ }
+ else if( 0==sqlite3_stricmp("rbu_rowid", zName) ){
+ bRbuRowid = 1;
+ }
+ }
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+
+ if( p->rc==SQLITE_OK
+ && rbuIsVacuum(p)==0
+ && bRbuRowid!=(pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE)
+ ){
+ p->rc = SQLITE_ERROR;
+ p->zErrmsg = sqlite3_mprintf(
+ "table %q %s rbu_rowid column", pIter->zDataTbl,
+ (bRbuRowid ? "may not have" : "requires")
+ );
+ }
+
+ /* Check that all non-HIDDEN columns in the destination table are also
+ ** present in the input table. Populate the abTblPk[], azTblType[] and
+ ** aiTblOrder[] arrays at the same time. */
+ if( p->rc==SQLITE_OK ){
+ p->rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &p->zErrmsg,
+ sqlite3_mprintf("PRAGMA table_info(%Q)", pIter->zTbl)
+ );
+ }
+ while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ const char *zName = (const char*)sqlite3_column_text(pStmt, 1);
+ if( zName==0 ) break; /* An OOM - finalize() below returns S_NOMEM */
+ for(i=iOrder; i<pIter->nTblCol; i++){
+ if( 0==strcmp(zName, pIter->azTblCol[i]) ) break;
+ }
+ if( i==pIter->nTblCol ){
+ p->rc = SQLITE_ERROR;
+ p->zErrmsg = sqlite3_mprintf("column missing from %q: %s",
+ pIter->zDataTbl, zName
+ );
+ }else{
+ int iPk = sqlite3_column_int(pStmt, 5);
+ int bNotNull = sqlite3_column_int(pStmt, 3);
+ const char *zType = (const char*)sqlite3_column_text(pStmt, 2);
+
+ if( i!=iOrder ){
+ SWAP(int, pIter->aiSrcOrder[i], pIter->aiSrcOrder[iOrder]);
+ SWAP(char*, pIter->azTblCol[i], pIter->azTblCol[iOrder]);
+ }
+
+ pIter->azTblType[iOrder] = rbuStrndup(zType, &p->rc);
+ pIter->abTblPk[iOrder] = (iPk!=0);
+ pIter->abNotNull[iOrder] = (u8)bNotNull || (iPk!=0);
+ iOrder++;
+ }
+ }
+
+ rbuFinalize(p, pStmt);
+ rbuObjIterCacheIndexedCols(p, pIter);
+ assert( pIter->eType!=RBU_PK_VTAB || pIter->abIndexed==0 );
+ assert( pIter->eType!=RBU_PK_VTAB || pIter->nIndex==0 );
+ }
+
+ return p->rc;
+}
+
+/*
+** This function constructs and returns a pointer to a nul-terminated
+** string containing some SQL clause or list based on one or more of the
+** column names currently stored in the pIter->azTblCol[] array.
+*/
+static char *rbuObjIterGetCollist(
+ sqlite3rbu *p, /* RBU object */
+ RbuObjIter *pIter /* Object iterator for column names */
+){
+ char *zList = 0;
+ const char *zSep = "";
+ int i;
+ for(i=0; i<pIter->nTblCol; i++){
+ const char *z = pIter->azTblCol[i];
+ zList = rbuMPrintf(p, "%z%s\"%w\"", zList, zSep, z);
+ zSep = ", ";
+ }
+ return zList;
+}
+
+/*
+** This function is used to create a SELECT list (the list of SQL
+** expressions that follows a SELECT keyword) for a SELECT statement
+** used to read from an data_xxx or rbu_tmp_xxx table while updating the
+** index object currently indicated by the iterator object passed as the
+** second argument. A "PRAGMA index_xinfo = <idxname>" statement is used
+** to obtain the required information.
+**
+** If the index is of the following form:
+**
+** CREATE INDEX i1 ON t1(c, b COLLATE nocase);
+**
+** and "t1" is a table with an explicit INTEGER PRIMARY KEY column
+** "ipk", the returned string is:
+**
+** "`c` COLLATE 'BINARY', `b` COLLATE 'NOCASE', `ipk` COLLATE 'BINARY'"
+**
+** As well as the returned string, three other malloc'd strings are
+** returned via output parameters. As follows:
+**
+** pzImposterCols: ...
+** pzImposterPk: ...
+** pzWhere: ...
+*/
+static char *rbuObjIterGetIndexCols(
+ sqlite3rbu *p, /* RBU object */
+ RbuObjIter *pIter, /* Object iterator for column names */
+ char **pzImposterCols, /* OUT: Columns for imposter table */
+ char **pzImposterPk, /* OUT: Imposter PK clause */
+ char **pzWhere, /* OUT: WHERE clause */
+ int *pnBind /* OUT: Trbul number of columns */
+){
+ int rc = p->rc; /* Error code */
+ int rc2; /* sqlite3_finalize() return code */
+ char *zRet = 0; /* String to return */
+ char *zImpCols = 0; /* String to return via *pzImposterCols */
+ char *zImpPK = 0; /* String to return via *pzImposterPK */
+ char *zWhere = 0; /* String to return via *pzWhere */
+ int nBind = 0; /* Value to return via *pnBind */
+ const char *zCom = ""; /* Set to ", " later on */
+ const char *zAnd = ""; /* Set to " AND " later on */
+ sqlite3_stmt *pXInfo = 0; /* PRAGMA index_xinfo = ? */
+
+ if( rc==SQLITE_OK ){
+ assert( p->zErrmsg==0 );
+ rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg,
+ sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", pIter->zIdx)
+ );
+ }
+
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){
+ int iCid = sqlite3_column_int(pXInfo, 1);
+ int bDesc = sqlite3_column_int(pXInfo, 3);
+ const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4);
+ const char *zCol;
+ const char *zType;
+
+ if( iCid<0 ){
+ /* An integer primary key. If the table has an explicit IPK, use
+ ** its name. Otherwise, use "rbu_rowid". */
+ if( pIter->eType==RBU_PK_IPK ){
+ int i;
+ for(i=0; pIter->abTblPk[i]==0; i++);
+ assert( i<pIter->nTblCol );
+ zCol = pIter->azTblCol[i];
+ }else if( rbuIsVacuum(p) ){
+ zCol = "_rowid_";
+ }else{
+ zCol = "rbu_rowid";
+ }
+ zType = "INTEGER";
+ }else{
+ zCol = pIter->azTblCol[iCid];
+ zType = pIter->azTblType[iCid];
+ }
+
+ zRet = sqlite3_mprintf("%z%s\"%w\" COLLATE %Q", zRet, zCom, zCol, zCollate);
+ if( pIter->bUnique==0 || sqlite3_column_int(pXInfo, 5) ){
+ const char *zOrder = (bDesc ? " DESC" : "");
+ zImpPK = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\"%s",
+ zImpPK, zCom, nBind, zCol, zOrder
+ );
+ }
+ zImpCols = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\" %s COLLATE %Q",
+ zImpCols, zCom, nBind, zCol, zType, zCollate
+ );
+ zWhere = sqlite3_mprintf(
+ "%z%s\"rbu_imp_%d%w\" IS ?", zWhere, zAnd, nBind, zCol
+ );
+ if( zRet==0 || zImpPK==0 || zImpCols==0 || zWhere==0 ) rc = SQLITE_NOMEM;
+ zCom = ", ";
+ zAnd = " AND ";
+ nBind++;
+ }
+
+ rc2 = sqlite3_finalize(pXInfo);
+ if( rc==SQLITE_OK ) rc = rc2;
+
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(zRet);
+ sqlite3_free(zImpCols);
+ sqlite3_free(zImpPK);
+ sqlite3_free(zWhere);
+ zRet = 0;
+ zImpCols = 0;
+ zImpPK = 0;
+ zWhere = 0;
+ p->rc = rc;
+ }
+
+ *pzImposterCols = zImpCols;
+ *pzImposterPk = zImpPK;
+ *pzWhere = zWhere;
+ *pnBind = nBind;
+ return zRet;
+}
+
+/*
+** Assuming the current table columns are "a", "b" and "c", and the zObj
+** paramter is passed "old", return a string of the form:
+**
+** "old.a, old.b, old.b"
+**
+** With the column names escaped.
+**
+** For tables with implicit rowids - RBU_PK_EXTERNAL and RBU_PK_NONE, append
+** the text ", old._rowid_" to the returned value.
+*/
+static char *rbuObjIterGetOldlist(
+ sqlite3rbu *p,
+ RbuObjIter *pIter,
+ const char *zObj
+){
+ char *zList = 0;
+ if( p->rc==SQLITE_OK && pIter->abIndexed ){
+ const char *zS = "";
+ int i;
+ for(i=0; i<pIter->nTblCol; i++){
+ if( pIter->abIndexed[i] ){
+ const char *zCol = pIter->azTblCol[i];
+ zList = sqlite3_mprintf("%z%s%s.\"%w\"", zList, zS, zObj, zCol);
+ }else{
+ zList = sqlite3_mprintf("%z%sNULL", zList, zS);
+ }
+ zS = ", ";
+ if( zList==0 ){
+ p->rc = SQLITE_NOMEM;
+ break;
+ }
+ }
+
+ /* For a table with implicit rowids, append "old._rowid_" to the list. */
+ if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
+ zList = rbuMPrintf(p, "%z, %s._rowid_", zList, zObj);
+ }
+ }
+ return zList;
+}
+
+/*
+** Return an expression that can be used in a WHERE clause to match the
+** primary key of the current table. For example, if the table is:
+**
+** CREATE TABLE t1(a, b, c, PRIMARY KEY(b, c));
+**
+** Return the string:
+**
+** "b = ?1 AND c = ?2"
+*/
+static char *rbuObjIterGetWhere(
+ sqlite3rbu *p,
+ RbuObjIter *pIter
+){
+ char *zList = 0;
+ if( pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE ){
+ zList = rbuMPrintf(p, "_rowid_ = ?%d", pIter->nTblCol+1);
+ }else if( pIter->eType==RBU_PK_EXTERNAL ){
+ const char *zSep = "";
+ int i;
+ for(i=0; i<pIter->nTblCol; i++){
+ if( pIter->abTblPk[i] ){
+ zList = rbuMPrintf(p, "%z%sc%d=?%d", zList, zSep, i, i+1);
+ zSep = " AND ";
+ }
+ }
+ zList = rbuMPrintf(p,
+ "_rowid_ = (SELECT id FROM rbu_imposter2 WHERE %z)", zList
+ );
+
+ }else{
+ const char *zSep = "";
+ int i;
+ for(i=0; i<pIter->nTblCol; i++){
+ if( pIter->abTblPk[i] ){
+ const char *zCol = pIter->azTblCol[i];
+ zList = rbuMPrintf(p, "%z%s\"%w\"=?%d", zList, zSep, zCol, i+1);
+ zSep = " AND ";
+ }
+ }
+ }
+ return zList;
+}
+
+/*
+** The SELECT statement iterating through the keys for the current object
+** (p->objiter.pSelect) currently points to a valid row. However, there
+** is something wrong with the rbu_control value in the rbu_control value
+** stored in the (p->nCol+1)'th column. Set the error code and error message
+** of the RBU handle to something reflecting this.
+*/
+static void rbuBadControlError(sqlite3rbu *p){
+ p->rc = SQLITE_ERROR;
+ p->zErrmsg = sqlite3_mprintf("invalid rbu_control value");
+}
+
+
+/*
+** Return a nul-terminated string containing the comma separated list of
+** assignments that should be included following the "SET" keyword of
+** an UPDATE statement used to update the table object that the iterator
+** passed as the second argument currently points to if the rbu_control
+** column of the data_xxx table entry is set to zMask.
+**
+** The memory for the returned string is obtained from sqlite3_malloc().
+** It is the responsibility of the caller to eventually free it using
+** sqlite3_free().
+**
+** If an OOM error is encountered when allocating space for the new
+** string, an error code is left in the rbu handle passed as the first
+** argument and NULL is returned. Or, if an error has already occurred
+** when this function is called, NULL is returned immediately, without
+** attempting the allocation or modifying the stored error code.
+*/
+static char *rbuObjIterGetSetlist(
+ sqlite3rbu *p,
+ RbuObjIter *pIter,
+ const char *zMask
+){
+ char *zList = 0;
+ if( p->rc==SQLITE_OK ){
+ int i;
+
+ if( (int)strlen(zMask)!=pIter->nTblCol ){
+ rbuBadControlError(p);
+ }else{
+ const char *zSep = "";
+ for(i=0; i<pIter->nTblCol; i++){
+ char c = zMask[pIter->aiSrcOrder[i]];
+ if( c=='x' ){
+ zList = rbuMPrintf(p, "%z%s\"%w\"=?%d",
+ zList, zSep, pIter->azTblCol[i], i+1
+ );
+ zSep = ", ";
+ }
+ else if( c=='d' ){
+ zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_delta(\"%w\", ?%d)",
+ zList, zSep, pIter->azTblCol[i], pIter->azTblCol[i], i+1
+ );
+ zSep = ", ";
+ }
+ else if( c=='f' ){
+ zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_fossil_delta(\"%w\", ?%d)",
+ zList, zSep, pIter->azTblCol[i], pIter->azTblCol[i], i+1
+ );
+ zSep = ", ";
+ }
+ }
+ }
+ }
+ return zList;
+}
+
+/*
+** Return a nul-terminated string consisting of nByte comma separated
+** "?" expressions. For example, if nByte is 3, return a pointer to
+** a buffer containing the string "?,?,?".
+**
+** The memory for the returned string is obtained from sqlite3_malloc().
+** It is the responsibility of the caller to eventually free it using
+** sqlite3_free().
+**
+** If an OOM error is encountered when allocating space for the new
+** string, an error code is left in the rbu handle passed as the first
+** argument and NULL is returned. Or, if an error has already occurred
+** when this function is called, NULL is returned immediately, without
+** attempting the allocation or modifying the stored error code.
+*/
+static char *rbuObjIterGetBindlist(sqlite3rbu *p, int nBind){
+ char *zRet = 0;
+ int nByte = nBind*2 + 1;
+
+ zRet = (char*)rbuMalloc(p, nByte);
+ if( zRet ){
+ int i;
+ for(i=0; i<nBind; i++){
+ zRet[i*2] = '?';
+ zRet[i*2+1] = (i+1==nBind) ? '\0' : ',';
+ }
+ }
+ return zRet;
+}
+
+/*
+** The iterator currently points to a table (not index) of type
+** RBU_PK_WITHOUT_ROWID. This function creates the PRIMARY KEY
+** declaration for the corresponding imposter table. For example,
+** if the iterator points to a table created as:
+**
+** CREATE TABLE t1(a, b, c, PRIMARY KEY(b, a DESC)) WITHOUT ROWID
+**
+** this function returns:
+**
+** PRIMARY KEY("b", "a" DESC)
+*/
+static char *rbuWithoutRowidPK(sqlite3rbu *p, RbuObjIter *pIter){
+ char *z = 0;
+ assert( pIter->zIdx==0 );
+ if( p->rc==SQLITE_OK ){
+ const char *zSep = "PRIMARY KEY(";
+ sqlite3_stmt *pXList = 0; /* PRAGMA index_list = (pIter->zTbl) */
+ sqlite3_stmt *pXInfo = 0; /* PRAGMA index_xinfo = <pk-index> */
+
+ p->rc = prepareFreeAndCollectError(p->dbMain, &pXList, &p->zErrmsg,
+ sqlite3_mprintf("PRAGMA main.index_list = %Q", pIter->zTbl)
+ );
+ while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXList) ){
+ const char *zOrig = (const char*)sqlite3_column_text(pXList,3);
+ if( zOrig && strcmp(zOrig, "pk")==0 ){
+ const char *zIdx = (const char*)sqlite3_column_text(pXList,1);
+ if( zIdx ){
+ p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg,
+ sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx)
+ );
+ }
+ break;
+ }
+ }
+ rbuFinalize(p, pXList);
+
+ while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){
+ if( sqlite3_column_int(pXInfo, 5) ){
+ /* int iCid = sqlite3_column_int(pXInfo, 0); */
+ const char *zCol = (const char*)sqlite3_column_text(pXInfo, 2);
+ const char *zDesc = sqlite3_column_int(pXInfo, 3) ? " DESC" : "";
+ z = rbuMPrintf(p, "%z%s\"%w\"%s", z, zSep, zCol, zDesc);
+ zSep = ", ";
+ }
+ }
+ z = rbuMPrintf(p, "%z)", z);
+ rbuFinalize(p, pXInfo);
+ }
+ return z;
+}
+
+/*
+** This function creates the second imposter table used when writing to
+** a table b-tree where the table has an external primary key. If the
+** iterator passed as the second argument does not currently point to
+** a table (not index) with an external primary key, this function is a
+** no-op.
+**
+** Assuming the iterator does point to a table with an external PK, this
+** function creates a WITHOUT ROWID imposter table named "rbu_imposter2"
+** used to access that PK index. For example, if the target table is
+** declared as follows:
+**
+** CREATE TABLE t1(a, b TEXT, c REAL, PRIMARY KEY(b, c));
+**
+** then the imposter table schema is:
+**
+** CREATE TABLE rbu_imposter2(c1 TEXT, c2 REAL, id INTEGER) WITHOUT ROWID;
+**
+*/
+static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){
+ if( p->rc==SQLITE_OK && pIter->eType==RBU_PK_EXTERNAL ){
+ int tnum = pIter->iPkTnum; /* Root page of PK index */
+ sqlite3_stmt *pQuery = 0; /* SELECT name ... WHERE rootpage = $tnum */
+ const char *zIdx = 0; /* Name of PK index */
+ sqlite3_stmt *pXInfo = 0; /* PRAGMA main.index_xinfo = $zIdx */
+ const char *zComma = "";
+ char *zCols = 0; /* Used to build up list of table cols */
+ char *zPk = 0; /* Used to build up table PK declaration */
+
+ /* Figure out the name of the primary key index for the current table.
+ ** This is needed for the argument to "PRAGMA index_xinfo". Set
+ ** zIdx to point to a nul-terminated string containing this name. */
+ p->rc = prepareAndCollectError(p->dbMain, &pQuery, &p->zErrmsg,
+ "SELECT name FROM sqlite_master WHERE rootpage = ?"
+ );
+ if( p->rc==SQLITE_OK ){
+ sqlite3_bind_int(pQuery, 1, tnum);
+ if( SQLITE_ROW==sqlite3_step(pQuery) ){
+ zIdx = (const char*)sqlite3_column_text(pQuery, 0);
+ }
+ }
+ if( zIdx ){
+ p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg,
+ sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx)
+ );
+ }
+ rbuFinalize(p, pQuery);
+
+ while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){
+ int bKey = sqlite3_column_int(pXInfo, 5);
+ if( bKey ){
+ int iCid = sqlite3_column_int(pXInfo, 1);
+ int bDesc = sqlite3_column_int(pXInfo, 3);
+ const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4);
+ zCols = rbuMPrintf(p, "%z%sc%d %s COLLATE %Q", zCols, zComma,
+ iCid, pIter->azTblType[iCid], zCollate
+ );
+ zPk = rbuMPrintf(p, "%z%sc%d%s", zPk, zComma, iCid, bDesc?" DESC":"");
+ zComma = ", ";
+ }
+ }
+ zCols = rbuMPrintf(p, "%z, id INTEGER", zCols);
+ rbuFinalize(p, pXInfo);
+
+ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1, tnum);
+ rbuMPrintfExec(p, p->dbMain,
+ "CREATE TABLE rbu_imposter2(%z, PRIMARY KEY(%z)) WITHOUT ROWID",
+ zCols, zPk
+ );
+ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 0);
+ }
+}
+
+/*
+** If an error has already occurred when this function is called, it
+** immediately returns zero (without doing any work). Or, if an error
+** occurs during the execution of this function, it sets the error code
+** in the sqlite3rbu object indicated by the first argument and returns
+** zero.
+**
+** The iterator passed as the second argument is guaranteed to point to
+** a table (not an index) when this function is called. This function
+** attempts to create any imposter table required to write to the main
+** table b-tree of the table before returning. Non-zero is returned if
+** an imposter table are created, or zero otherwise.
+**
+** An imposter table is required in all cases except RBU_PK_VTAB. Only
+** virtual tables are written to directly. The imposter table has the
+** same schema as the actual target table (less any UNIQUE constraints).
+** More precisely, the "same schema" means the same columns, types,
+** collation sequences. For tables that do not have an external PRIMARY
+** KEY, it also means the same PRIMARY KEY declaration.
+*/
+static void rbuCreateImposterTable(sqlite3rbu *p, RbuObjIter *pIter){
+ if( p->rc==SQLITE_OK && pIter->eType!=RBU_PK_VTAB ){
+ int tnum = pIter->iTnum;
+ const char *zComma = "";
+ char *zSql = 0;
+ int iCol;
+ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 1);
+
+ for(iCol=0; p->rc==SQLITE_OK && iCol<pIter->nTblCol; iCol++){
+ const char *zPk = "";
+ const char *zCol = pIter->azTblCol[iCol];
+ const char *zColl = 0;
+
+ p->rc = sqlite3_table_column_metadata(
+ p->dbMain, "main", pIter->zTbl, zCol, 0, &zColl, 0, 0, 0
+ );
+
+ if( pIter->eType==RBU_PK_IPK && pIter->abTblPk[iCol] ){
+ /* If the target table column is an "INTEGER PRIMARY KEY", add
+ ** "PRIMARY KEY" to the imposter table column declaration. */
+ zPk = "PRIMARY KEY ";
+ }
+ zSql = rbuMPrintf(p, "%z%s\"%w\" %s %sCOLLATE %Q%s",
+ zSql, zComma, zCol, pIter->azTblType[iCol], zPk, zColl,
+ (pIter->abNotNull[iCol] ? " NOT NULL" : "")
+ );
+ zComma = ", ";
+ }
+
+ if( pIter->eType==RBU_PK_WITHOUT_ROWID ){
+ char *zPk = rbuWithoutRowidPK(p, pIter);
+ if( zPk ){
+ zSql = rbuMPrintf(p, "%z, %z", zSql, zPk);
+ }
+ }
+
+ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1, tnum);
+ rbuMPrintfExec(p, p->dbMain, "CREATE TABLE \"rbu_imp_%w\"(%z)%s",
+ pIter->zTbl, zSql,
+ (pIter->eType==RBU_PK_WITHOUT_ROWID ? " WITHOUT ROWID" : "")
+ );
+ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 0);
+ }
+}
+
+/*
+** Prepare a statement used to insert rows into the "rbu_tmp_xxx" table.
+** Specifically a statement of the form:
+**
+** INSERT INTO rbu_tmp_xxx VALUES(?, ?, ? ...);
+**
+** The number of bound variables is equal to the number of columns in
+** the target table, plus one (for the rbu_control column), plus one more
+** (for the rbu_rowid column) if the target table is an implicit IPK or
+** virtual table.
+*/
+static void rbuObjIterPrepareTmpInsert(
+ sqlite3rbu *p,
+ RbuObjIter *pIter,
+ const char *zCollist,
+ const char *zRbuRowid
+){
+ int bRbuRowid = (pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE);
+ char *zBind = rbuObjIterGetBindlist(p, pIter->nTblCol + 1 + bRbuRowid);
+ if( zBind ){
+ assert( pIter->pTmpInsert==0 );
+ p->rc = prepareFreeAndCollectError(
+ p->dbRbu, &pIter->pTmpInsert, &p->zErrmsg, sqlite3_mprintf(
+ "INSERT INTO %s.'rbu_tmp_%q'(rbu_control,%s%s) VALUES(%z)",
+ p->zStateDb, pIter->zDataTbl, zCollist, zRbuRowid, zBind
+ ));
+ }
+}
+
+static void rbuTmpInsertFunc(
+ sqlite3_context *pCtx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ sqlite3rbu *p = sqlite3_user_data(pCtx);
+ int rc = SQLITE_OK;
+ int i;
+
+ assert( sqlite3_value_int(apVal[0])!=0
+ || p->objiter.eType==RBU_PK_EXTERNAL
+ || p->objiter.eType==RBU_PK_NONE
+ );
+ if( sqlite3_value_int(apVal[0])!=0 ){
+ p->nPhaseOneStep += p->objiter.nIndex;
+ }
+
+ for(i=0; rc==SQLITE_OK && i<nVal; i++){
+ rc = sqlite3_bind_value(p->objiter.pTmpInsert, i+1, apVal[i]);
+ }
+ if( rc==SQLITE_OK ){
+ sqlite3_step(p->objiter.pTmpInsert);
+ rc = sqlite3_reset(p->objiter.pTmpInsert);
+ }
+
+ if( rc!=SQLITE_OK ){
+ sqlite3_result_error_code(pCtx, rc);
+ }
+}
+
+/*
+** Ensure that the SQLite statement handles required to update the
+** target database object currently indicated by the iterator passed
+** as the second argument are available.
+*/
+static int rbuObjIterPrepareAll(
+ sqlite3rbu *p,
+ RbuObjIter *pIter,
+ int nOffset /* Add "LIMIT -1 OFFSET $nOffset" to SELECT */
+){
+ assert( pIter->bCleanup==0 );
+ if( pIter->pSelect==0 && rbuObjIterCacheTableInfo(p, pIter)==SQLITE_OK ){
+ const int tnum = pIter->iTnum;
+ char *zCollist = 0; /* List of indexed columns */
+ char **pz = &p->zErrmsg;
+ const char *zIdx = pIter->zIdx;
+ char *zLimit = 0;
+
+ if( nOffset ){
+ zLimit = sqlite3_mprintf(" LIMIT -1 OFFSET %d", nOffset);
+ if( !zLimit ) p->rc = SQLITE_NOMEM;
+ }
+
+ if( zIdx ){
+ const char *zTbl = pIter->zTbl;
+ char *zImposterCols = 0; /* Columns for imposter table */
+ char *zImposterPK = 0; /* Primary key declaration for imposter */
+ char *zWhere = 0; /* WHERE clause on PK columns */
+ char *zBind = 0;
+ int nBind = 0;
+
+ assert( pIter->eType!=RBU_PK_VTAB );
+ zCollist = rbuObjIterGetIndexCols(
+ p, pIter, &zImposterCols, &zImposterPK, &zWhere, &nBind
+ );
+ zBind = rbuObjIterGetBindlist(p, nBind);
+
+ /* Create the imposter table used to write to this index. */
+ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 1);
+ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1,tnum);
+ rbuMPrintfExec(p, p->dbMain,
+ "CREATE TABLE \"rbu_imp_%w\"( %s, PRIMARY KEY( %s ) ) WITHOUT ROWID",
+ zTbl, zImposterCols, zImposterPK
+ );
+ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 0);
+
+ /* Create the statement to insert index entries */
+ pIter->nCol = nBind;
+ if( p->rc==SQLITE_OK ){
+ p->rc = prepareFreeAndCollectError(
+ p->dbMain, &pIter->pInsert, &p->zErrmsg,
+ sqlite3_mprintf("INSERT INTO \"rbu_imp_%w\" VALUES(%s)", zTbl, zBind)
+ );
+ }
+
+ /* And to delete index entries */
+ if( rbuIsVacuum(p)==0 && p->rc==SQLITE_OK ){
+ p->rc = prepareFreeAndCollectError(
+ p->dbMain, &pIter->pDelete, &p->zErrmsg,
+ sqlite3_mprintf("DELETE FROM \"rbu_imp_%w\" WHERE %s", zTbl, zWhere)
+ );
+ }
+
+ /* Create the SELECT statement to read keys in sorted order */
+ if( p->rc==SQLITE_OK ){
+ char *zSql;
+ if( rbuIsVacuum(p) ){
+ zSql = sqlite3_mprintf(
+ "SELECT %s, 0 AS rbu_control FROM '%q' ORDER BY %s%s",
+ zCollist,
+ pIter->zDataTbl,
+ zCollist, zLimit
+ );
+ }else
+
+ if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
+ zSql = sqlite3_mprintf(
+ "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' ORDER BY %s%s",
+ zCollist, p->zStateDb, pIter->zDataTbl,
+ zCollist, zLimit
+ );
+ }else{
+ zSql = sqlite3_mprintf(
+ "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' "
+ "UNION ALL "
+ "SELECT %s, rbu_control FROM '%q' "
+ "WHERE typeof(rbu_control)='integer' AND rbu_control!=1 "
+ "ORDER BY %s%s",
+ zCollist, p->zStateDb, pIter->zDataTbl,
+ zCollist, pIter->zDataTbl,
+ zCollist, zLimit
+ );
+ }
+ p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, zSql);
+ }
+
+ sqlite3_free(zImposterCols);
+ sqlite3_free(zImposterPK);
+ sqlite3_free(zWhere);
+ sqlite3_free(zBind);
+ }else{
+ int bRbuRowid = (pIter->eType==RBU_PK_VTAB)
+ ||(pIter->eType==RBU_PK_NONE)
+ ||(pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p));
+ const char *zTbl = pIter->zTbl; /* Table this step applies to */
+ const char *zWrite; /* Imposter table name */
+
+ char *zBindings = rbuObjIterGetBindlist(p, pIter->nTblCol + bRbuRowid);
+ char *zWhere = rbuObjIterGetWhere(p, pIter);
+ char *zOldlist = rbuObjIterGetOldlist(p, pIter, "old");
+ char *zNewlist = rbuObjIterGetOldlist(p, pIter, "new");
+
+ zCollist = rbuObjIterGetCollist(p, pIter);
+ pIter->nCol = pIter->nTblCol;
+
+ /* Create the imposter table or tables (if required). */
+ rbuCreateImposterTable(p, pIter);
+ rbuCreateImposterTable2(p, pIter);
+ zWrite = (pIter->eType==RBU_PK_VTAB ? "" : "rbu_imp_");
+
+ /* Create the INSERT statement to write to the target PK b-tree */
+ if( p->rc==SQLITE_OK ){
+ p->rc = prepareFreeAndCollectError(p->dbMain, &pIter->pInsert, pz,
+ sqlite3_mprintf(
+ "INSERT INTO \"%s%w\"(%s%s) VALUES(%s)",
+ zWrite, zTbl, zCollist, (bRbuRowid ? ", _rowid_" : ""), zBindings
+ )
+ );
+ }
+
+ /* Create the DELETE statement to write to the target PK b-tree.
+ ** Because it only performs INSERT operations, this is not required for
+ ** an rbu vacuum handle. */
+ if( rbuIsVacuum(p)==0 && p->rc==SQLITE_OK ){
+ p->rc = prepareFreeAndCollectError(p->dbMain, &pIter->pDelete, pz,
+ sqlite3_mprintf(
+ "DELETE FROM \"%s%w\" WHERE %s", zWrite, zTbl, zWhere
+ )
+ );
+ }
+
+ if( rbuIsVacuum(p)==0 && pIter->abIndexed ){
+ const char *zRbuRowid = "";
+ if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
+ zRbuRowid = ", rbu_rowid";
+ }
+
+ /* Create the rbu_tmp_xxx table and the triggers to populate it. */
+ rbuMPrintfExec(p, p->dbRbu,
+ "CREATE TABLE IF NOT EXISTS %s.'rbu_tmp_%q' AS "
+ "SELECT *%s FROM '%q' WHERE 0;"
+ , p->zStateDb, pIter->zDataTbl
+ , (pIter->eType==RBU_PK_EXTERNAL ? ", 0 AS rbu_rowid" : "")
+ , pIter->zDataTbl
+ );
+
+ rbuMPrintfExec(p, p->dbMain,
+ "CREATE TEMP TRIGGER rbu_delete_tr BEFORE DELETE ON \"%s%w\" "
+ "BEGIN "
+ " SELECT rbu_tmp_insert(3, %s);"
+ "END;"
+
+ "CREATE TEMP TRIGGER rbu_update1_tr BEFORE UPDATE ON \"%s%w\" "
+ "BEGIN "
+ " SELECT rbu_tmp_insert(3, %s);"
+ "END;"
+
+ "CREATE TEMP TRIGGER rbu_update2_tr AFTER UPDATE ON \"%s%w\" "
+ "BEGIN "
+ " SELECT rbu_tmp_insert(4, %s);"
+ "END;",
+ zWrite, zTbl, zOldlist,
+ zWrite, zTbl, zOldlist,
+ zWrite, zTbl, zNewlist
+ );
+
+ if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
+ rbuMPrintfExec(p, p->dbMain,
+ "CREATE TEMP TRIGGER rbu_insert_tr AFTER INSERT ON \"%s%w\" "
+ "BEGIN "
+ " SELECT rbu_tmp_insert(0, %s);"
+ "END;",
+ zWrite, zTbl, zNewlist
+ );
+ }
+
+ rbuObjIterPrepareTmpInsert(p, pIter, zCollist, zRbuRowid);
+ }
+
+ /* Create the SELECT statement to read keys from data_xxx */
+ if( p->rc==SQLITE_OK ){
+ const char *zRbuRowid = "";
+ if( bRbuRowid ){
+ zRbuRowid = rbuIsVacuum(p) ? ",_rowid_ " : ",rbu_rowid";
+ }
+ p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz,
+ sqlite3_mprintf(
+ "SELECT %s,%s rbu_control%s FROM '%q'%s",
+ zCollist,
+ (rbuIsVacuum(p) ? "0 AS " : ""),
+ zRbuRowid,
+ pIter->zDataTbl, zLimit
+ )
+ );
+ }
+
+ sqlite3_free(zWhere);
+ sqlite3_free(zOldlist);
+ sqlite3_free(zNewlist);
+ sqlite3_free(zBindings);
+ }
+ sqlite3_free(zCollist);
+ sqlite3_free(zLimit);
+ }
+
+ return p->rc;
+}
+
+/*
+** Set output variable *ppStmt to point to an UPDATE statement that may
+** be used to update the imposter table for the main table b-tree of the
+** table object that pIter currently points to, assuming that the
+** rbu_control column of the data_xyz table contains zMask.
+**
+** If the zMask string does not specify any columns to update, then this
+** is not an error. Output variable *ppStmt is set to NULL in this case.
+*/
+static int rbuGetUpdateStmt(
+ sqlite3rbu *p, /* RBU handle */
+ RbuObjIter *pIter, /* Object iterator */
+ const char *zMask, /* rbu_control value ('x.x.') */
+ sqlite3_stmt **ppStmt /* OUT: UPDATE statement handle */
+){
+ RbuUpdateStmt **pp;
+ RbuUpdateStmt *pUp = 0;
+ int nUp = 0;
+
+ /* In case an error occurs */
+ *ppStmt = 0;
+
+ /* Search for an existing statement. If one is found, shift it to the front
+ ** of the LRU queue and return immediately. Otherwise, leave nUp pointing
+ ** to the number of statements currently in the cache and pUp to the
+ ** last object in the list. */
+ for(pp=&pIter->pRbuUpdate; *pp; pp=&((*pp)->pNext)){
+ pUp = *pp;
+ if( strcmp(pUp->zMask, zMask)==0 ){
+ *pp = pUp->pNext;
+ pUp->pNext = pIter->pRbuUpdate;
+ pIter->pRbuUpdate = pUp;
+ *ppStmt = pUp->pUpdate;
+ return SQLITE_OK;
+ }
+ nUp++;
+ }
+ assert( pUp==0 || pUp->pNext==0 );
+
+ if( nUp>=SQLITE_RBU_UPDATE_CACHESIZE ){
+ for(pp=&pIter->pRbuUpdate; *pp!=pUp; pp=&((*pp)->pNext));
+ *pp = 0;
+ sqlite3_finalize(pUp->pUpdate);
+ pUp->pUpdate = 0;
+ }else{
+ pUp = (RbuUpdateStmt*)rbuMalloc(p, sizeof(RbuUpdateStmt)+pIter->nTblCol+1);
+ }
+
+ if( pUp ){
+ char *zWhere = rbuObjIterGetWhere(p, pIter);
+ char *zSet = rbuObjIterGetSetlist(p, pIter, zMask);
+ char *zUpdate = 0;
+
+ pUp->zMask = (char*)&pUp[1];
+ memcpy(pUp->zMask, zMask, pIter->nTblCol);
+ pUp->pNext = pIter->pRbuUpdate;
+ pIter->pRbuUpdate = pUp;
+
+ if( zSet ){
+ const char *zPrefix = "";
+
+ if( pIter->eType!=RBU_PK_VTAB ) zPrefix = "rbu_imp_";
+ zUpdate = sqlite3_mprintf("UPDATE \"%s%w\" SET %s WHERE %s",
+ zPrefix, pIter->zTbl, zSet, zWhere
+ );
+ p->rc = prepareFreeAndCollectError(
+ p->dbMain, &pUp->pUpdate, &p->zErrmsg, zUpdate
+ );
+ *ppStmt = pUp->pUpdate;
+ }
+ sqlite3_free(zWhere);
+ sqlite3_free(zSet);
+ }
+
+ return p->rc;
+}
+
+static sqlite3 *rbuOpenDbhandle(
+ sqlite3rbu *p,
+ const char *zName,
+ int bUseVfs
+){
+ sqlite3 *db = 0;
+ if( p->rc==SQLITE_OK ){
+ const int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_URI;
+ p->rc = sqlite3_open_v2(zName, &db, flags, bUseVfs ? p->zVfsName : 0);
+ if( p->rc ){
+ p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ sqlite3_close(db);
+ db = 0;
+ }
+ }
+ return db;
+}
+
+/*
+** Free an RbuState object allocated by rbuLoadState().
+*/
+static void rbuFreeState(RbuState *p){
+ if( p ){
+ sqlite3_free(p->zTbl);
+ sqlite3_free(p->zDataTbl);
+ sqlite3_free(p->zIdx);
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Allocate an RbuState object and load the contents of the rbu_state
+** table into it. Return a pointer to the new object. It is the
+** responsibility of the caller to eventually free the object using
+** sqlite3_free().
+**
+** If an error occurs, leave an error code and message in the rbu handle
+** and return NULL.
+*/
+static RbuState *rbuLoadState(sqlite3rbu *p){
+ RbuState *pRet = 0;
+ sqlite3_stmt *pStmt = 0;
+ int rc;
+ int rc2;
+
+ pRet = (RbuState*)rbuMalloc(p, sizeof(RbuState));
+ if( pRet==0 ) return 0;
+
+ rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
+ sqlite3_mprintf("SELECT k, v FROM %s.rbu_state", p->zStateDb)
+ );
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ switch( sqlite3_column_int(pStmt, 0) ){
+ case RBU_STATE_STAGE:
+ pRet->eStage = sqlite3_column_int(pStmt, 1);
+ if( pRet->eStage!=RBU_STAGE_OAL
+ && pRet->eStage!=RBU_STAGE_MOVE
+ && pRet->eStage!=RBU_STAGE_CKPT
+ ){
+ p->rc = SQLITE_CORRUPT;
+ }
+ break;
+
+ case RBU_STATE_TBL:
+ pRet->zTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
+ break;
+
+ case RBU_STATE_IDX:
+ pRet->zIdx = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
+ break;
+
+ case RBU_STATE_ROW:
+ pRet->nRow = sqlite3_column_int(pStmt, 1);
+ break;
+
+ case RBU_STATE_PROGRESS:
+ pRet->nProgress = sqlite3_column_int64(pStmt, 1);
+ break;
+
+ case RBU_STATE_CKPT:
+ pRet->iWalCksum = sqlite3_column_int64(pStmt, 1);
+ break;
+
+ case RBU_STATE_COOKIE:
+ pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1);
+ break;
+
+ case RBU_STATE_OALSZ:
+ pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1);
+ break;
+
+ case RBU_STATE_PHASEONESTEP:
+ pRet->nPhaseOneStep = sqlite3_column_int64(pStmt, 1);
+ break;
+
+ case RBU_STATE_DATATBL:
+ pRet->zDataTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
+ break;
+
+ default:
+ rc = SQLITE_CORRUPT;
+ break;
+ }
+ }
+ rc2 = sqlite3_finalize(pStmt);
+ if( rc==SQLITE_OK ) rc = rc2;
+
+ p->rc = rc;
+ return pRet;
+}
+
+
+/*
+** Open the database handle and attach the RBU database as "rbu". If an
+** error occurs, leave an error code and message in the RBU handle.
+*/
+static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
+ assert( p->rc || (p->dbMain==0 && p->dbRbu==0) );
+ assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 );
+
+ /* Open the RBU database */
+ p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1);
+
+ if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
+ sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p);
+ if( p->zState==0 ){
+ const char *zFile = sqlite3_db_filename(p->dbRbu, "main");
+ p->zState = rbuMPrintf(p, "file://%s-vacuum?modeof=%s", zFile, zFile);
+ }
+ }
+
+ /* If using separate RBU and state databases, attach the state database to
+ ** the RBU db handle now. */
+ if( p->zState ){
+ rbuMPrintfExec(p, p->dbRbu, "ATTACH %Q AS stat", p->zState);
+ memcpy(p->zStateDb, "stat", 4);
+ }else{
+ memcpy(p->zStateDb, "main", 4);
+ }
+
+#if 0
+ if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
+ p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, 0);
+ }
+#endif
+
+ /* If it has not already been created, create the rbu_state table */
+ rbuMPrintfExec(p, p->dbRbu, RBU_CREATE_STATE, p->zStateDb);
+
+#if 0
+ if( rbuIsVacuum(p) ){
+ if( p->rc==SQLITE_OK ){
+ int rc2;
+ int bOk = 0;
+ sqlite3_stmt *pCnt = 0;
+ p->rc = prepareAndCollectError(p->dbRbu, &pCnt, &p->zErrmsg,
+ "SELECT count(*) FROM stat.sqlite_master"
+ );
+ if( p->rc==SQLITE_OK
+ && sqlite3_step(pCnt)==SQLITE_ROW
+ && 1==sqlite3_column_int(pCnt, 0)
+ ){
+ bOk = 1;
+ }
+ rc2 = sqlite3_finalize(pCnt);
+ if( p->rc==SQLITE_OK ) p->rc = rc2;
+
+ if( p->rc==SQLITE_OK && bOk==0 ){
+ p->rc = SQLITE_ERROR;
+ p->zErrmsg = sqlite3_mprintf("invalid state database");
+ }
+
+ if( p->rc==SQLITE_OK ){
+ p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0);
+ }
+ }
+ }
+#endif
+
+ if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
+ int bOpen = 0;
+ int rc;
+ p->nRbu = 0;
+ p->pRbuFd = 0;
+ rc = sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p);
+ if( rc!=SQLITE_NOTFOUND ) p->rc = rc;
+ if( p->eStage>=RBU_STAGE_MOVE ){
+ bOpen = 1;
+ }else{
+ RbuState *pState = rbuLoadState(p);
+ if( pState ){
+ bOpen = (pState->eStage>=RBU_STAGE_MOVE);
+ rbuFreeState(pState);
+ }
+ }
+ if( bOpen ) p->dbMain = rbuOpenDbhandle(p, p->zRbu, p->nRbu<=1);
+ }
+
+ p->eStage = 0;
+ if( p->rc==SQLITE_OK && p->dbMain==0 ){
+ if( !rbuIsVacuum(p) ){
+ p->dbMain = rbuOpenDbhandle(p, p->zTarget, 1);
+ }else if( p->pRbuFd->pWalFd ){
+ if( pbRetry ){
+ p->pRbuFd->bNolock = 0;
+ sqlite3_close(p->dbRbu);
+ sqlite3_close(p->dbMain);
+ p->dbMain = 0;
+ p->dbRbu = 0;
+ *pbRetry = 1;
+ return;
+ }
+ p->rc = SQLITE_ERROR;
+ p->zErrmsg = sqlite3_mprintf("cannot vacuum wal mode database");
+ }else{
+ char *zTarget;
+ char *zExtra = 0;
+ if( strlen(p->zRbu)>=5 && 0==memcmp("file:", p->zRbu, 5) ){
+ zExtra = &p->zRbu[5];
+ while( *zExtra ){
+ if( *zExtra++=='?' ) break;
+ }
+ if( *zExtra=='\0' ) zExtra = 0;
+ }
+
+ zTarget = sqlite3_mprintf("file:%s-vactmp?rbu_memory=1%s%s",
+ sqlite3_db_filename(p->dbRbu, "main"),
+ (zExtra==0 ? "" : "&"), (zExtra==0 ? "" : zExtra)
+ );
+
+ if( zTarget==0 ){
+ p->rc = SQLITE_NOMEM;
+ return;
+ }
+ p->dbMain = rbuOpenDbhandle(p, zTarget, p->nRbu<=1);
+ sqlite3_free(zTarget);
+ }
+ }
+
+ if( p->rc==SQLITE_OK ){
+ p->rc = sqlite3_create_function(p->dbMain,
+ "rbu_tmp_insert", -1, SQLITE_UTF8, (void*)p, rbuTmpInsertFunc, 0, 0
+ );
+ }
+
+ if( p->rc==SQLITE_OK ){
+ p->rc = sqlite3_create_function(p->dbMain,
+ "rbu_fossil_delta", 2, SQLITE_UTF8, 0, rbuFossilDeltaFunc, 0, 0
+ );
+ }
+
+ if( p->rc==SQLITE_OK ){
+ p->rc = sqlite3_create_function(p->dbRbu,
+ "rbu_target_name", -1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0
+ );
+ }
+
+ if( p->rc==SQLITE_OK ){
+ p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p);
+ }
+ rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlite_master");
+
+ /* Mark the database file just opened as an RBU target database. If
+ ** this call returns SQLITE_NOTFOUND, then the RBU vfs is not in use.
+ ** This is an error. */
+ if( p->rc==SQLITE_OK ){
+ p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p);
+ }
+
+ if( p->rc==SQLITE_NOTFOUND ){
+ p->rc = SQLITE_ERROR;
+ p->zErrmsg = sqlite3_mprintf("rbu vfs not found");
+ }
+}
+
+/*
+** This routine is a copy of the sqlite3FileSuffix3() routine from the core.
+** It is a no-op unless SQLITE_ENABLE_8_3_NAMES is defined.
+**
+** If SQLITE_ENABLE_8_3_NAMES is set at compile-time and if the database
+** filename in zBaseFilename is a URI with the "8_3_names=1" parameter and
+** if filename in z[] has a suffix (a.k.a. "extension") that is longer than
+** three characters, then shorten the suffix on z[] to be the last three
+** characters of the original suffix.
+**
+** If SQLITE_ENABLE_8_3_NAMES is set to 2 at compile-time, then always
+** do the suffix shortening regardless of URI parameter.
+**
+** Examples:
+**
+** test.db-journal => test.nal
+** test.db-wal => test.wal
+** test.db-shm => test.shm
+** test.db-mj7f3319fa => test.9fa
+*/
+static void rbuFileSuffix3(const char *zBase, char *z){
+#ifdef SQLITE_ENABLE_8_3_NAMES
+#if SQLITE_ENABLE_8_3_NAMES<2
+ if( sqlite3_uri_boolean(zBase, "8_3_names", 0) )
+#endif
+ {
+ int i, sz;
+ sz = (int)strlen(z)&0xffffff;
+ for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
+ if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4);
+ }
+#endif
+}
+
+/*
+** Return the current wal-index header checksum for the target database
+** as a 64-bit integer.
+**
+** The checksum is store in the first page of xShmMap memory as an 8-byte
+** blob starting at byte offset 40.
+*/
+static i64 rbuShmChecksum(sqlite3rbu *p){
+ i64 iRet = 0;
+ if( p->rc==SQLITE_OK ){
+ sqlite3_file *pDb = p->pTargetFd->pReal;
+ u32 volatile *ptr;
+ p->rc = pDb->pMethods->xShmMap(pDb, 0, 32*1024, 0, (void volatile**)&ptr);
+ if( p->rc==SQLITE_OK ){
+ iRet = ((i64)ptr[10] << 32) + ptr[11];
+ }
+ }
+ return iRet;
+}
+
+/*
+** This function is called as part of initializing or reinitializing an
+** incremental checkpoint.
+**
+** It populates the sqlite3rbu.aFrame[] array with the set of
+** (wal frame -> db page) copy operations required to checkpoint the
+** current wal file, and obtains the set of shm locks required to safely
+** perform the copy operations directly on the file-system.
+**
+** If argument pState is not NULL, then the incremental checkpoint is
+** being resumed. In this case, if the checksum of the wal-index-header
+** following recovery is not the same as the checksum saved in the RbuState
+** object, then the rbu handle is set to DONE state. This occurs if some
+** other client appends a transaction to the wal file in the middle of
+** an incremental checkpoint.
+*/
+static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
+
+ /* If pState is NULL, then the wal file may not have been opened and
+ ** recovered. Running a read-statement here to ensure that doing so
+ ** does not interfere with the "capture" process below. */
+ if( pState==0 ){
+ p->eStage = 0;
+ if( p->rc==SQLITE_OK ){
+ p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlite_master", 0, 0, 0);
+ }
+ }
+
+ /* Assuming no error has occurred, run a "restart" checkpoint with the
+ ** sqlite3rbu.eStage variable set to CAPTURE. This turns on the following
+ ** special behaviour in the rbu VFS:
+ **
+ ** * If the exclusive shm WRITER or READ0 lock cannot be obtained,
+ ** the checkpoint fails with SQLITE_BUSY (normally SQLite would
+ ** proceed with running a passive checkpoint instead of failing).
+ **
+ ** * Attempts to read from the *-wal file or write to the database file
+ ** do not perform any IO. Instead, the frame/page combinations that
+ ** would be read/written are recorded in the sqlite3rbu.aFrame[]
+ ** array.
+ **
+ ** * Calls to xShmLock(UNLOCK) to release the exclusive shm WRITER,
+ ** READ0 and CHECKPOINT locks taken as part of the checkpoint are
+ ** no-ops. These locks will not be released until the connection
+ ** is closed.
+ **
+ ** * Attempting to xSync() the database file causes an SQLITE_INTERNAL
+ ** error.
+ **
+ ** As a result, unless an error (i.e. OOM or SQLITE_BUSY) occurs, the
+ ** checkpoint below fails with SQLITE_INTERNAL, and leaves the aFrame[]
+ ** array populated with a set of (frame -> page) mappings. Because the
+ ** WRITER, CHECKPOINT and READ0 locks are still held, it is safe to copy
+ ** data from the wal file into the database file according to the
+ ** contents of aFrame[].
+ */
+ if( p->rc==SQLITE_OK ){
+ int rc2;
+ p->eStage = RBU_STAGE_CAPTURE;
+ rc2 = sqlite3_exec(p->dbMain, "PRAGMA main.wal_checkpoint=restart", 0, 0,0);
+ if( rc2!=SQLITE_INTERNAL ) p->rc = rc2;
+ }
+
+ if( p->rc==SQLITE_OK && p->nFrame>0 ){
+ p->eStage = RBU_STAGE_CKPT;
+ p->nStep = (pState ? pState->nRow : 0);
+ p->aBuf = rbuMalloc(p, p->pgsz);
+ p->iWalCksum = rbuShmChecksum(p);
+ }
+
+ if( p->rc==SQLITE_OK ){
+ if( p->nFrame==0 || (pState && pState->iWalCksum!=p->iWalCksum) ){
+ p->rc = SQLITE_DONE;
+ p->eStage = RBU_STAGE_DONE;
+ }else{
+ int nSectorSize;
+ sqlite3_file *pDb = p->pTargetFd->pReal;
+ sqlite3_file *pWal = p->pTargetFd->pWalFd->pReal;
+ assert( p->nPagePerSector==0 );
+ nSectorSize = pDb->pMethods->xSectorSize(pDb);
+ if( nSectorSize>p->pgsz ){
+ p->nPagePerSector = nSectorSize / p->pgsz;
+ }else{
+ p->nPagePerSector = 1;
+ }
+
+ /* Call xSync() on the wal file. This causes SQLite to sync the
+ ** directory in which the target database and the wal file reside, in
+ ** case it has not been synced since the rename() call in
+ ** rbuMoveOalFile(). */
+ p->rc = pWal->pMethods->xSync(pWal, SQLITE_SYNC_NORMAL);
+ }
+ }
+}
+
+/*
+** Called when iAmt bytes are read from offset iOff of the wal file while
+** the rbu object is in capture mode. Record the frame number of the frame
+** being read in the aFrame[] array.
+*/
+static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){
+ const u32 mReq = (1<<WAL_LOCK_WRITE)|(1<<WAL_LOCK_CKPT)|(1<<WAL_LOCK_READ0);
+ u32 iFrame;
+
+ if( pRbu->mLock!=mReq ){
+ pRbu->rc = SQLITE_BUSY;
+ return SQLITE_INTERNAL;
+ }
+
+ pRbu->pgsz = iAmt;
+ if( pRbu->nFrame==pRbu->nFrameAlloc ){
+ int nNew = (pRbu->nFrameAlloc ? pRbu->nFrameAlloc : 64) * 2;
+ RbuFrame *aNew;
+ aNew = (RbuFrame*)sqlite3_realloc(pRbu->aFrame, nNew * sizeof(RbuFrame));
+ if( aNew==0 ) return SQLITE_NOMEM;
+ pRbu->aFrame = aNew;
+ pRbu->nFrameAlloc = nNew;
+ }
+
+ iFrame = (u32)((iOff-32) / (i64)(iAmt+24)) + 1;
+ if( pRbu->iMaxFrame<iFrame ) pRbu->iMaxFrame = iFrame;
+ pRbu->aFrame[pRbu->nFrame].iWalFrame = iFrame;
+ pRbu->aFrame[pRbu->nFrame].iDbPage = 0;
+ pRbu->nFrame++;
+ return SQLITE_OK;
+}
+
+/*
+** Called when a page of data is written to offset iOff of the database
+** file while the rbu handle is in capture mode. Record the page number
+** of the page being written in the aFrame[] array.
+*/
+static int rbuCaptureDbWrite(sqlite3rbu *pRbu, i64 iOff){
+ pRbu->aFrame[pRbu->nFrame-1].iDbPage = (u32)(iOff / pRbu->pgsz) + 1;
+ return SQLITE_OK;
+}
+
+/*
+** This is called as part of an incremental checkpoint operation. Copy
+** a single frame of data from the wal file into the database file, as
+** indicated by the RbuFrame object.
+*/
+static void rbuCheckpointFrame(sqlite3rbu *p, RbuFrame *pFrame){
+ sqlite3_file *pWal = p->pTargetFd->pWalFd->pReal;
+ sqlite3_file *pDb = p->pTargetFd->pReal;
+ i64 iOff;
+
+ assert( p->rc==SQLITE_OK );
+ iOff = (i64)(pFrame->iWalFrame-1) * (p->pgsz + 24) + 32 + 24;
+ p->rc = pWal->pMethods->xRead(pWal, p->aBuf, p->pgsz, iOff);
+ if( p->rc ) return;
+
+ iOff = (i64)(pFrame->iDbPage-1) * p->pgsz;
+ p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff);
+}
+
+
+/*
+** Take an EXCLUSIVE lock on the database file.
+*/
+static void rbuLockDatabase(sqlite3rbu *p){
+ sqlite3_file *pReal = p->pTargetFd->pReal;
+ assert( p->rc==SQLITE_OK );
+ p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_SHARED);
+ if( p->rc==SQLITE_OK ){
+ p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_EXCLUSIVE);
+ }
+}
+
+#if defined(_WIN32_WCE)
+static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){
+ int nChar;
+ LPWSTR zWideFilename;
+
+ nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
+ if( nChar==0 ){
+ return 0;
+ }
+ zWideFilename = sqlite3_malloc( nChar*sizeof(zWideFilename[0]) );
+ if( zWideFilename==0 ){
+ return 0;
+ }
+ memset(zWideFilename, 0, nChar*sizeof(zWideFilename[0]));
+ nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
+ nChar);
+ if( nChar==0 ){
+ sqlite3_free(zWideFilename);
+ zWideFilename = 0;
+ }
+ return zWideFilename;
+}
+#endif
+
+/*
+** The RBU handle is currently in RBU_STAGE_OAL state, with a SHARED lock
+** on the database file. This proc moves the *-oal file to the *-wal path,
+** then reopens the database file (this time in vanilla, non-oal, WAL mode).
+** If an error occurs, leave an error code and error message in the rbu
+** handle.
+*/
+static void rbuMoveOalFile(sqlite3rbu *p){
+ const char *zBase = sqlite3_db_filename(p->dbMain, "main");
+ const char *zMove = zBase;
+ char *zOal;
+ char *zWal;
+
+ if( rbuIsVacuum(p) ){
+ zMove = sqlite3_db_filename(p->dbRbu, "main");
+ }
+ zOal = sqlite3_mprintf("%s-oal", zMove);
+ zWal = sqlite3_mprintf("%s-wal", zMove);
+
+ assert( p->eStage==RBU_STAGE_MOVE );
+ assert( p->rc==SQLITE_OK && p->zErrmsg==0 );
+ if( zWal==0 || zOal==0 ){
+ p->rc = SQLITE_NOMEM;
+ }else{
+ /* Move the *-oal file to *-wal. At this point connection p->db is
+ ** holding a SHARED lock on the target database file (because it is
+ ** in WAL mode). So no other connection may be writing the db.
+ **
+ ** In order to ensure that there are no database readers, an EXCLUSIVE
+ ** lock is obtained here before the *-oal is moved to *-wal.
+ */
+ rbuLockDatabase(p);
+ if( p->rc==SQLITE_OK ){
+ rbuFileSuffix3(zBase, zWal);
+ rbuFileSuffix3(zBase, zOal);
+
+ /* Re-open the databases. */
+ rbuObjIterFinalize(&p->objiter);
+ sqlite3_close(p->dbRbu);
+ sqlite3_close(p->dbMain);
+ p->dbMain = 0;
+ p->dbRbu = 0;
+
+#if defined(_WIN32_WCE)
+ {
+ LPWSTR zWideOal;
+ LPWSTR zWideWal;
+
+ zWideOal = rbuWinUtf8ToUnicode(zOal);
+ if( zWideOal ){
+ zWideWal = rbuWinUtf8ToUnicode(zWal);
+ if( zWideWal ){
+ if( MoveFileW(zWideOal, zWideWal) ){
+ p->rc = SQLITE_OK;
+ }else{
+ p->rc = SQLITE_IOERR;
+ }
+ sqlite3_free(zWideWal);
+ }else{
+ p->rc = SQLITE_IOERR_NOMEM;
+ }
+ sqlite3_free(zWideOal);
+ }else{
+ p->rc = SQLITE_IOERR_NOMEM;
+ }
+ }
+#else
+ p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK;
+#endif
+
+ if( p->rc==SQLITE_OK ){
+ rbuOpenDatabase(p, 0);
+ rbuSetupCheckpoint(p, 0);
+ }
+ }
+ }
+
+ sqlite3_free(zWal);
+ sqlite3_free(zOal);
+}
+
+/*
+** The SELECT statement iterating through the keys for the current object
+** (p->objiter.pSelect) currently points to a valid row. This function
+** determines the type of operation requested by this row and returns
+** one of the following values to indicate the result:
+**
+** * RBU_INSERT
+** * RBU_DELETE
+** * RBU_IDX_DELETE
+** * RBU_UPDATE
+**
+** If RBU_UPDATE is returned, then output variable *pzMask is set to
+** point to the text value indicating the columns to update.
+**
+** If the rbu_control field contains an invalid value, an error code and
+** message are left in the RBU handle and zero returned.
+*/
+static int rbuStepType(sqlite3rbu *p, const char **pzMask){
+ int iCol = p->objiter.nCol; /* Index of rbu_control column */
+ int res = 0; /* Return value */
+
+ switch( sqlite3_column_type(p->objiter.pSelect, iCol) ){
+ case SQLITE_INTEGER: {
+ int iVal = sqlite3_column_int(p->objiter.pSelect, iCol);
+ switch( iVal ){
+ case 0: res = RBU_INSERT; break;
+ case 1: res = RBU_DELETE; break;
+ case 2: res = RBU_REPLACE; break;
+ case 3: res = RBU_IDX_DELETE; break;
+ case 4: res = RBU_IDX_INSERT; break;
+ }
+ break;
+ }
+
+ case SQLITE_TEXT: {
+ const unsigned char *z = sqlite3_column_text(p->objiter.pSelect, iCol);
+ if( z==0 ){
+ p->rc = SQLITE_NOMEM;
+ }else{
+ *pzMask = (const char*)z;
+ }
+ res = RBU_UPDATE;
+
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if( res==0 ){
+ rbuBadControlError(p);
+ }
+ return res;
+}
+
+#ifdef SQLITE_DEBUG
+/*
+** Assert that column iCol of statement pStmt is named zName.
+*/
+static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){
+ const char *zCol = sqlite3_column_name(pStmt, iCol);
+ assert( 0==sqlite3_stricmp(zName, zCol) );
+}
+#else
+# define assertColumnName(x,y,z)
+#endif
+
+/*
+** Argument eType must be one of RBU_INSERT, RBU_DELETE, RBU_IDX_INSERT or
+** RBU_IDX_DELETE. This function performs the work of a single
+** sqlite3rbu_step() call for the type of operation specified by eType.
+*/
+static void rbuStepOneOp(sqlite3rbu *p, int eType){
+ RbuObjIter *pIter = &p->objiter;
+ sqlite3_value *pVal;
+ sqlite3_stmt *pWriter;
+ int i;
+
+ assert( p->rc==SQLITE_OK );
+ assert( eType!=RBU_DELETE || pIter->zIdx==0 );
+ assert( eType==RBU_DELETE || eType==RBU_IDX_DELETE
+ || eType==RBU_INSERT || eType==RBU_IDX_INSERT
+ );
+
+ /* If this is a delete, decrement nPhaseOneStep by nIndex. If the DELETE
+ ** statement below does actually delete a row, nPhaseOneStep will be
+ ** incremented by the same amount when SQL function rbu_tmp_insert()
+ ** is invoked by the trigger. */
+ if( eType==RBU_DELETE ){
+ p->nPhaseOneStep -= p->objiter.nIndex;
+ }
+
+ if( eType==RBU_IDX_DELETE || eType==RBU_DELETE ){
+ pWriter = pIter->pDelete;
+ }else{
+ pWriter = pIter->pInsert;
+ }
+
+ for(i=0; i<pIter->nCol; i++){
+ /* If this is an INSERT into a table b-tree and the table has an
+ ** explicit INTEGER PRIMARY KEY, check that this is not an attempt
+ ** to write a NULL into the IPK column. That is not permitted. */
+ if( eType==RBU_INSERT
+ && pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i]
+ && sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL
+ ){
+ p->rc = SQLITE_MISMATCH;
+ p->zErrmsg = sqlite3_mprintf("datatype mismatch");
+ return;
+ }
+
+ if( eType==RBU_DELETE && pIter->abTblPk[i]==0 ){
+ continue;
+ }
+
+ pVal = sqlite3_column_value(pIter->pSelect, i);
+ p->rc = sqlite3_bind_value(pWriter, i+1, pVal);
+ if( p->rc ) return;
+ }
+ if( pIter->zIdx==0 ){
+ if( pIter->eType==RBU_PK_VTAB
+ || pIter->eType==RBU_PK_NONE
+ || (pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p))
+ ){
+ /* For a virtual table, or a table with no primary key, the
+ ** SELECT statement is:
+ **
+ ** SELECT <cols>, rbu_control, rbu_rowid FROM ....
+ **
+ ** Hence column_value(pIter->nCol+1).
+ */
+ assertColumnName(pIter->pSelect, pIter->nCol+1,
+ rbuIsVacuum(p) ? "rowid" : "rbu_rowid"
+ );
+ pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
+ p->rc = sqlite3_bind_value(pWriter, pIter->nCol+1, pVal);
+ }
+ }
+ if( p->rc==SQLITE_OK ){
+ sqlite3_step(pWriter);
+ p->rc = resetAndCollectError(pWriter, &p->zErrmsg);
+ }
+}
+
+/*
+** This function does the work for an sqlite3rbu_step() call.
+**
+** The object-iterator (p->objiter) currently points to a valid object,
+** and the input cursor (p->objiter.pSelect) currently points to a valid
+** input row. Perform whatever processing is required and return.
+**
+** If no error occurs, SQLITE_OK is returned. Otherwise, an error code
+** and message is left in the RBU handle and a copy of the error code
+** returned.
+*/
+static int rbuStep(sqlite3rbu *p){
+ RbuObjIter *pIter = &p->objiter;
+ const char *zMask = 0;
+ int eType = rbuStepType(p, &zMask);
+
+ if( eType ){
+ assert( eType==RBU_INSERT || eType==RBU_DELETE
+ || eType==RBU_REPLACE || eType==RBU_IDX_DELETE
+ || eType==RBU_IDX_INSERT || eType==RBU_UPDATE
+ );
+ assert( eType!=RBU_UPDATE || pIter->zIdx==0 );
+
+ if( pIter->zIdx==0 && (eType==RBU_IDX_DELETE || eType==RBU_IDX_INSERT) ){
+ rbuBadControlError(p);
+ }
+ else if( eType==RBU_REPLACE ){
+ if( pIter->zIdx==0 ){
+ p->nPhaseOneStep += p->objiter.nIndex;
+ rbuStepOneOp(p, RBU_DELETE);
+ }
+ if( p->rc==SQLITE_OK ) rbuStepOneOp(p, RBU_INSERT);
+ }
+ else if( eType!=RBU_UPDATE ){
+ rbuStepOneOp(p, eType);
+ }
+ else{
+ sqlite3_value *pVal;
+ sqlite3_stmt *pUpdate = 0;
+ assert( eType==RBU_UPDATE );
+ p->nPhaseOneStep -= p->objiter.nIndex;
+ rbuGetUpdateStmt(p, pIter, zMask, &pUpdate);
+ if( pUpdate ){
+ int i;
+ for(i=0; p->rc==SQLITE_OK && i<pIter->nCol; i++){
+ char c = zMask[pIter->aiSrcOrder[i]];
+ pVal = sqlite3_column_value(pIter->pSelect, i);
+ if( pIter->abTblPk[i] || c!='.' ){
+ p->rc = sqlite3_bind_value(pUpdate, i+1, pVal);
+ }
+ }
+ if( p->rc==SQLITE_OK
+ && (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE)
+ ){
+ /* Bind the rbu_rowid value to column _rowid_ */
+ assertColumnName(pIter->pSelect, pIter->nCol+1, "rbu_rowid");
+ pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
+ p->rc = sqlite3_bind_value(pUpdate, pIter->nCol+1, pVal);
+ }
+ if( p->rc==SQLITE_OK ){
+ sqlite3_step(pUpdate);
+ p->rc = resetAndCollectError(pUpdate, &p->zErrmsg);
+ }
+ }
+ }
+ }
+ return p->rc;
+}
+
+/*
+** Increment the schema cookie of the main database opened by p->dbMain.
+**
+** Or, if this is an RBU vacuum, set the schema cookie of the main db
+** opened by p->dbMain to one more than the schema cookie of the main
+** db opened by p->dbRbu.
+*/
+static void rbuIncrSchemaCookie(sqlite3rbu *p){
+ if( p->rc==SQLITE_OK ){
+ sqlite3 *dbread = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain);
+ int iCookie = 1000000;
+ sqlite3_stmt *pStmt;
+
+ p->rc = prepareAndCollectError(dbread, &pStmt, &p->zErrmsg,
+ "PRAGMA schema_version"
+ );
+ if( p->rc==SQLITE_OK ){
+ /* Coverage: it may be that this sqlite3_step() cannot fail. There
+ ** is already a transaction open, so the prepared statement cannot
+ ** throw an SQLITE_SCHEMA exception. The only database page the
+ ** statement reads is page 1, which is guaranteed to be in the cache.
+ ** And no memory allocations are required. */
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ iCookie = sqlite3_column_int(pStmt, 0);
+ }
+ rbuFinalize(p, pStmt);
+ }
+ if( p->rc==SQLITE_OK ){
+ rbuMPrintfExec(p, p->dbMain, "PRAGMA schema_version = %d", iCookie+1);
+ }
+ }
+}
+
+/*
+** Update the contents of the rbu_state table within the rbu database. The
+** value stored in the RBU_STATE_STAGE column is eStage. All other values
+** are determined by inspecting the rbu handle passed as the first argument.
+*/
+static void rbuSaveState(sqlite3rbu *p, int eStage){
+ if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){
+ sqlite3_stmt *pInsert = 0;
+ rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd);
+ int rc;
+
+ assert( p->zErrmsg==0 );
+ rc = prepareFreeAndCollectError(p->dbRbu, &pInsert, &p->zErrmsg,
+ sqlite3_mprintf(
+ "INSERT OR REPLACE INTO %s.rbu_state(k, v) VALUES "
+ "(%d, %d), "
+ "(%d, %Q), "
+ "(%d, %Q), "
+ "(%d, %d), "
+ "(%d, %d), "
+ "(%d, %lld), "
+ "(%d, %lld), "
+ "(%d, %lld), "
+ "(%d, %lld), "
+ "(%d, %Q) ",
+ p->zStateDb,
+ RBU_STATE_STAGE, eStage,
+ RBU_STATE_TBL, p->objiter.zTbl,
+ RBU_STATE_IDX, p->objiter.zIdx,
+ RBU_STATE_ROW, p->nStep,
+ RBU_STATE_PROGRESS, p->nProgress,
+ RBU_STATE_CKPT, p->iWalCksum,
+ RBU_STATE_COOKIE, (i64)pFd->iCookie,
+ RBU_STATE_OALSZ, p->iOalSz,
+ RBU_STATE_PHASEONESTEP, p->nPhaseOneStep,
+ RBU_STATE_DATATBL, p->objiter.zDataTbl
+ )
+ );
+ assert( pInsert==0 || rc==SQLITE_OK );
+
+ if( rc==SQLITE_OK ){
+ sqlite3_step(pInsert);
+ rc = sqlite3_finalize(pInsert);
+ }
+ if( rc!=SQLITE_OK ) p->rc = rc;
+ }
+}
+
+
+/*
+** The second argument passed to this function is the name of a PRAGMA
+** setting - "page_size", "auto_vacuum", "user_version" or "application_id".
+** This function executes the following on sqlite3rbu.dbRbu:
+**
+** "PRAGMA main.$zPragma"
+**
+** where $zPragma is the string passed as the second argument, then
+** on sqlite3rbu.dbMain:
+**
+** "PRAGMA main.$zPragma = $val"
+**
+** where $val is the value returned by the first PRAGMA invocation.
+**
+** In short, it copies the value of the specified PRAGMA setting from
+** dbRbu to dbMain.
+*/
+static void rbuCopyPragma(sqlite3rbu *p, const char *zPragma){
+ if( p->rc==SQLITE_OK ){
+ sqlite3_stmt *pPragma = 0;
+ p->rc = prepareFreeAndCollectError(p->dbRbu, &pPragma, &p->zErrmsg,
+ sqlite3_mprintf("PRAGMA main.%s", zPragma)
+ );
+ if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPragma) ){
+ p->rc = rbuMPrintfExec(p, p->dbMain, "PRAGMA main.%s = %d",
+ zPragma, sqlite3_column_int(pPragma, 0)
+ );
+ }
+ rbuFinalize(p, pPragma);
+ }
+}
+
+/*
+** The RBU handle passed as the only argument has just been opened and
+** the state database is empty. If this RBU handle was opened for an
+** RBU vacuum operation, create the schema in the target db.
+*/
+static void rbuCreateTargetSchema(sqlite3rbu *p){
+ sqlite3_stmt *pSql = 0;
+ sqlite3_stmt *pInsert = 0;
+
+ assert( rbuIsVacuum(p) );
+ p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=1", 0,0, &p->zErrmsg);
+ if( p->rc==SQLITE_OK ){
+ p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
+ "SELECT sql FROM sqlite_master WHERE sql!='' AND rootpage!=0"
+ " AND name!='sqlite_sequence' "
+ " ORDER BY type DESC"
+ );
+ }
+
+ while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){
+ const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
+ p->rc = sqlite3_exec(p->dbMain, zSql, 0, 0, &p->zErrmsg);
+ }
+ rbuFinalize(p, pSql);
+ if( p->rc!=SQLITE_OK ) return;
+
+ if( p->rc==SQLITE_OK ){
+ p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
+ "SELECT * FROM sqlite_master WHERE rootpage=0 OR rootpage IS NULL"
+ );
+ }
+
+ if( p->rc==SQLITE_OK ){
+ p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg,
+ "INSERT INTO sqlite_master VALUES(?,?,?,?,?)"
+ );
+ }
+
+ while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){
+ int i;
+ for(i=0; i<5; i++){
+ sqlite3_bind_value(pInsert, i+1, sqlite3_column_value(pSql, i));
+ }
+ sqlite3_step(pInsert);
+ p->rc = sqlite3_reset(pInsert);
+ }
+ if( p->rc==SQLITE_OK ){
+ p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=0",0,0,&p->zErrmsg);
+ }
+
+ rbuFinalize(p, pSql);
+ rbuFinalize(p, pInsert);
+}
+
+/*
+** Step the RBU object.
+*/
+int sqlite3rbu_step(sqlite3rbu *p){
+ if( p ){
+ switch( p->eStage ){
+ case RBU_STAGE_OAL: {
+ RbuObjIter *pIter = &p->objiter;
+
+ /* If this is an RBU vacuum operation and the state table was empty
+ ** when this handle was opened, create the target database schema. */
+ if( rbuIsVacuum(p) && p->nProgress==0 && p->rc==SQLITE_OK ){
+ rbuCreateTargetSchema(p);
+ rbuCopyPragma(p, "user_version");
+ rbuCopyPragma(p, "application_id");
+ }
+
+ while( p->rc==SQLITE_OK && pIter->zTbl ){
+
+ if( pIter->bCleanup ){
+ /* Clean up the rbu_tmp_xxx table for the previous table. It
+ ** cannot be dropped as there are currently active SQL statements.
+ ** But the contents can be deleted. */
+ if( rbuIsVacuum(p)==0 && pIter->abIndexed ){
+ rbuMPrintfExec(p, p->dbRbu,
+ "DELETE FROM %s.'rbu_tmp_%q'", p->zStateDb, pIter->zDataTbl
+ );
+ }
+ }else{
+ rbuObjIterPrepareAll(p, pIter, 0);
+
+ /* Advance to the next row to process. */
+ if( p->rc==SQLITE_OK ){
+ int rc = sqlite3_step(pIter->pSelect);
+ if( rc==SQLITE_ROW ){
+ p->nProgress++;
+ p->nStep++;
+ return rbuStep(p);
+ }
+ p->rc = sqlite3_reset(pIter->pSelect);
+ p->nStep = 0;
+ }
+ }
+
+ rbuObjIterNext(p, pIter);
+ }
+
+ if( p->rc==SQLITE_OK ){
+ assert( pIter->zTbl==0 );
+ rbuSaveState(p, RBU_STAGE_MOVE);
+ rbuIncrSchemaCookie(p);
+ if( p->rc==SQLITE_OK ){
+ p->rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, &p->zErrmsg);
+ }
+ if( p->rc==SQLITE_OK ){
+ p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, &p->zErrmsg);
+ }
+ p->eStage = RBU_STAGE_MOVE;
+ }
+ break;
+ }
+
+ case RBU_STAGE_MOVE: {
+ if( p->rc==SQLITE_OK ){
+ rbuMoveOalFile(p);
+ p->nProgress++;
+ }
+ break;
+ }
+
+ case RBU_STAGE_CKPT: {
+ if( p->rc==SQLITE_OK ){
+ if( p->nStep>=p->nFrame ){
+ sqlite3_file *pDb = p->pTargetFd->pReal;
+
+ /* Sync the db file */
+ p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
+
+ /* Update nBackfill */
+ if( p->rc==SQLITE_OK ){
+ void volatile *ptr;
+ p->rc = pDb->pMethods->xShmMap(pDb, 0, 32*1024, 0, &ptr);
+ if( p->rc==SQLITE_OK ){
+ ((u32 volatile*)ptr)[24] = p->iMaxFrame;
+ }
+ }
+
+ if( p->rc==SQLITE_OK ){
+ p->eStage = RBU_STAGE_DONE;
+ p->rc = SQLITE_DONE;
+ }
+ }else{
+ /* At one point the following block copied a single frame from the
+ ** wal file to the database file. So that one call to sqlite3rbu_step()
+ ** checkpointed a single frame.
+ **
+ ** However, if the sector-size is larger than the page-size, and the
+ ** application calls sqlite3rbu_savestate() or close() immediately
+ ** after this step, then rbu_step() again, then a power failure occurs,
+ ** then the database page written here may be damaged. Work around
+ ** this by checkpointing frames until the next page in the aFrame[]
+ ** lies on a different disk sector to the current one. */
+ u32 iSector;
+ do{
+ RbuFrame *pFrame = &p->aFrame[p->nStep];
+ iSector = (pFrame->iDbPage-1) / p->nPagePerSector;
+ rbuCheckpointFrame(p, pFrame);
+ p->nStep++;
+ }while( p->nStep<p->nFrame
+ && iSector==((p->aFrame[p->nStep].iDbPage-1) / p->nPagePerSector)
+ && p->rc==SQLITE_OK
+ );
+ }
+ p->nProgress++;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ return p->rc;
+ }else{
+ return SQLITE_NOMEM;
+ }
+}
+
+/*
+** Compare strings z1 and z2, returning 0 if they are identical, or non-zero
+** otherwise. Either or both argument may be NULL. Two NULL values are
+** considered equal, and NULL is considered distinct from all other values.
+*/
+static int rbuStrCompare(const char *z1, const char *z2){
+ if( z1==0 && z2==0 ) return 0;
+ if( z1==0 || z2==0 ) return 1;
+ return (sqlite3_stricmp(z1, z2)!=0);
+}
+
+/*
+** This function is called as part of sqlite3rbu_open() when initializing
+** an rbu handle in OAL stage. If the rbu update has not started (i.e.
+** the rbu_state table was empty) it is a no-op. Otherwise, it arranges
+** things so that the next call to sqlite3rbu_step() continues on from
+** where the previous rbu handle left off.
+**
+** If an error occurs, an error code and error message are left in the
+** rbu handle passed as the first argument.
+*/
+static void rbuSetupOal(sqlite3rbu *p, RbuState *pState){
+ assert( p->rc==SQLITE_OK );
+ if( pState->zTbl ){
+ RbuObjIter *pIter = &p->objiter;
+ int rc = SQLITE_OK;
+
+ while( rc==SQLITE_OK && pIter->zTbl && (pIter->bCleanup
+ || rbuStrCompare(pIter->zIdx, pState->zIdx)
+ || (pState->zDataTbl==0 && rbuStrCompare(pIter->zTbl, pState->zTbl))
+ || (pState->zDataTbl && rbuStrCompare(pIter->zDataTbl, pState->zDataTbl))
+ )){
+ rc = rbuObjIterNext(p, pIter);
+ }
+
+ if( rc==SQLITE_OK && !pIter->zTbl ){
+ rc = SQLITE_ERROR;
+ p->zErrmsg = sqlite3_mprintf("rbu_state mismatch error");
+ }
+
+ if( rc==SQLITE_OK ){
+ p->nStep = pState->nRow;
+ rc = rbuObjIterPrepareAll(p, &p->objiter, p->nStep);
+ }
+
+ p->rc = rc;
+ }
+}
+
+/*
+** If there is a "*-oal" file in the file-system corresponding to the
+** target database in the file-system, delete it. If an error occurs,
+** leave an error code and error message in the rbu handle.
+*/
+static void rbuDeleteOalFile(sqlite3rbu *p){
+ char *zOal = rbuMPrintf(p, "%s-oal", p->zTarget);
+ if( zOal ){
+ sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
+ assert( pVfs && p->rc==SQLITE_OK && p->zErrmsg==0 );
+ pVfs->xDelete(pVfs, zOal, 0);
+ sqlite3_free(zOal);
+ }
+}
+
+/*
+** Allocate a private rbu VFS for the rbu handle passed as the only
+** argument. This VFS will be used unless the call to sqlite3rbu_open()
+** specified a URI with a vfs=? option in place of a target database
+** file name.
+*/
+static void rbuCreateVfs(sqlite3rbu *p){
+ int rnd;
+ char zRnd[64];
+
+ assert( p->rc==SQLITE_OK );
+ sqlite3_randomness(sizeof(int), (void*)&rnd);
+ sqlite3_snprintf(sizeof(zRnd), zRnd, "rbu_vfs_%d", rnd);
+ p->rc = sqlite3rbu_create_vfs(zRnd, 0);
+ if( p->rc==SQLITE_OK ){
+ sqlite3_vfs *pVfs = sqlite3_vfs_find(zRnd);
+ assert( pVfs );
+ p->zVfsName = pVfs->zName;
+ ((rbu_vfs*)pVfs)->pRbu = p;
+ }
+}
+
+/*
+** Destroy the private VFS created for the rbu handle passed as the only
+** argument by an earlier call to rbuCreateVfs().
+*/
+static void rbuDeleteVfs(sqlite3rbu *p){
+ if( p->zVfsName ){
+ sqlite3rbu_destroy_vfs(p->zVfsName);
+ p->zVfsName = 0;
+ }
+}
+
+/*
+** This user-defined SQL function is invoked with a single argument - the
+** name of a table expected to appear in the target database. It returns
+** the number of auxilliary indexes on the table.
+*/
+static void rbuIndexCntFunc(
+ sqlite3_context *pCtx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ sqlite3rbu *p = (sqlite3rbu*)sqlite3_user_data(pCtx);
+ sqlite3_stmt *pStmt = 0;
+ char *zErrmsg = 0;
+ int rc;
+
+ assert( nVal==1 );
+
+ rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &zErrmsg,
+ sqlite3_mprintf("SELECT count(*) FROM sqlite_master "
+ "WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0]))
+ );
+ if( rc!=SQLITE_OK ){
+ sqlite3_result_error(pCtx, zErrmsg, -1);
+ }else{
+ int nIndex = 0;
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ nIndex = sqlite3_column_int(pStmt, 0);
+ }
+ rc = sqlite3_finalize(pStmt);
+ if( rc==SQLITE_OK ){
+ sqlite3_result_int(pCtx, nIndex);
+ }else{
+ sqlite3_result_error(pCtx, sqlite3_errmsg(p->dbMain), -1);
+ }
+ }
+
+ sqlite3_free(zErrmsg);
+}
+
+/*
+** If the RBU database contains the rbu_count table, use it to initialize
+** the sqlite3rbu.nPhaseOneStep variable. The schema of the rbu_count table
+** is assumed to contain the same columns as:
+**
+** CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
+**
+** There should be one row in the table for each data_xxx table in the
+** database. The 'tbl' column should contain the name of a data_xxx table,
+** and the cnt column the number of rows it contains.
+**
+** sqlite3rbu.nPhaseOneStep is initialized to the sum of (1 + nIndex) * cnt
+** for all rows in the rbu_count table, where nIndex is the number of
+** indexes on the corresponding target database table.
+*/
+static void rbuInitPhaseOneSteps(sqlite3rbu *p){
+ if( p->rc==SQLITE_OK ){
+ sqlite3_stmt *pStmt = 0;
+ int bExists = 0; /* True if rbu_count exists */
+
+ p->nPhaseOneStep = -1;
+
+ p->rc = sqlite3_create_function(p->dbRbu,
+ "rbu_index_cnt", 1, SQLITE_UTF8, (void*)p, rbuIndexCntFunc, 0, 0
+ );
+
+ /* Check for the rbu_count table. If it does not exist, or if an error
+ ** occurs, nPhaseOneStep will be left set to -1. */
+ if( p->rc==SQLITE_OK ){
+ p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
+ "SELECT 1 FROM sqlite_master WHERE tbl_name = 'rbu_count'"
+ );
+ }
+ if( p->rc==SQLITE_OK ){
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ bExists = 1;
+ }
+ p->rc = sqlite3_finalize(pStmt);
+ }
+
+ if( p->rc==SQLITE_OK && bExists ){
+ p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
+ "SELECT sum(cnt * (1 + rbu_index_cnt(rbu_target_name(tbl))))"
+ "FROM rbu_count"
+ );
+ if( p->rc==SQLITE_OK ){
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ p->nPhaseOneStep = sqlite3_column_int64(pStmt, 0);
+ }
+ p->rc = sqlite3_finalize(pStmt);
+ }
+ }
+ }
+}
+
+
+static sqlite3rbu *openRbuHandle(
+ const char *zTarget,
+ const char *zRbu,
+ const char *zState
+){
+ sqlite3rbu *p;
+ size_t nTarget = zTarget ? strlen(zTarget) : 0;
+ size_t nRbu = strlen(zRbu);
+ size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1;
+
+ p = (sqlite3rbu*)sqlite3_malloc(nByte);
+ if( p ){
+ RbuState *pState = 0;
+
+ /* Create the custom VFS. */
+ memset(p, 0, sizeof(sqlite3rbu));
+ rbuCreateVfs(p);
+
+ /* Open the target, RBU and state databases */
+ if( p->rc==SQLITE_OK ){
+ char *pCsr = (char*)&p[1];
+ int bRetry = 0;
+ if( zTarget ){
+ p->zTarget = pCsr;
+ memcpy(p->zTarget, zTarget, nTarget+1);
+ pCsr += nTarget+1;
+ }
+ p->zRbu = pCsr;
+ memcpy(p->zRbu, zRbu, nRbu+1);
+ pCsr += nRbu+1;
+ if( zState ){
+ p->zState = rbuMPrintf(p, "%s", zState);
+ }
+
+ /* If the first attempt to open the database file fails and the bRetry
+ ** flag it set, this means that the db was not opened because it seemed
+ ** to be a wal-mode db. But, this may have happened due to an earlier
+ ** RBU vacuum operation leaving an old wal file in the directory.
+ ** If this is the case, it will have been checkpointed and deleted
+ ** when the handle was closed and a second attempt to open the
+ ** database may succeed. */
+ rbuOpenDatabase(p, &bRetry);
+ if( bRetry ){
+ rbuOpenDatabase(p, 0);
+ }
+ }
+
+ if( p->rc==SQLITE_OK ){
+ pState = rbuLoadState(p);
+ assert( pState || p->rc!=SQLITE_OK );
+ if( p->rc==SQLITE_OK ){
+
+ if( pState->eStage==0 ){
+ rbuDeleteOalFile(p);
+ rbuInitPhaseOneSteps(p);
+ p->eStage = RBU_STAGE_OAL;
+ }else{
+ p->eStage = pState->eStage;
+ p->nPhaseOneStep = pState->nPhaseOneStep;
+ }
+ p->nProgress = pState->nProgress;
+ p->iOalSz = pState->iOalSz;
+ }
+ }
+ assert( p->rc!=SQLITE_OK || p->eStage!=0 );
+
+ if( p->rc==SQLITE_OK && p->pTargetFd->pWalFd ){
+ if( p->eStage==RBU_STAGE_OAL ){
+ p->rc = SQLITE_ERROR;
+ p->zErrmsg = sqlite3_mprintf("cannot update wal mode database");
+ }else if( p->eStage==RBU_STAGE_MOVE ){
+ p->eStage = RBU_STAGE_CKPT;
+ p->nStep = 0;
+ }
+ }
+
+ if( p->rc==SQLITE_OK
+ && (p->eStage==RBU_STAGE_OAL || p->eStage==RBU_STAGE_MOVE)
+ && pState->eStage!=0
+ ){
+ rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd);
+ if( pFd->iCookie!=pState->iCookie ){
+ /* At this point (pTargetFd->iCookie) contains the value of the
+ ** change-counter cookie (the thing that gets incremented when a
+ ** transaction is committed in rollback mode) currently stored on
+ ** page 1 of the database file. */
+ p->rc = SQLITE_BUSY;
+ p->zErrmsg = sqlite3_mprintf("database modified during rbu %s",
+ (rbuIsVacuum(p) ? "vacuum" : "update")
+ );
+ }
+ }
+
+ if( p->rc==SQLITE_OK ){
+ if( p->eStage==RBU_STAGE_OAL ){
+ sqlite3 *db = p->dbMain;
+ p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, &p->zErrmsg);
+
+ /* Point the object iterator at the first object */
+ if( p->rc==SQLITE_OK ){
+ p->rc = rbuObjIterFirst(p, &p->objiter);
+ }
+
+ /* If the RBU database contains no data_xxx tables, declare the RBU
+ ** update finished. */
+ if( p->rc==SQLITE_OK && p->objiter.zTbl==0 ){
+ p->rc = SQLITE_DONE;
+ p->eStage = RBU_STAGE_DONE;
+ }else{
+ if( p->rc==SQLITE_OK && pState->eStage==0 && rbuIsVacuum(p) ){
+ rbuCopyPragma(p, "page_size");
+ rbuCopyPragma(p, "auto_vacuum");
+ }
+
+ /* Open transactions both databases. The *-oal file is opened or
+ ** created at this point. */
+ if( p->rc==SQLITE_OK ){
+ p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
+ }
+
+ /* Check if the main database is a zipvfs db. If it is, set the upper
+ ** level pager to use "journal_mode=off". This prevents it from
+ ** generating a large journal using a temp file. */
+ if( p->rc==SQLITE_OK ){
+ int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0);
+ if( frc==SQLITE_OK ){
+ p->rc = sqlite3_exec(
+ db, "PRAGMA journal_mode=off",0,0,&p->zErrmsg);
+ }
+ }
+
+ if( p->rc==SQLITE_OK ){
+ rbuSetupOal(p, pState);
+ }
+ }
+ }else if( p->eStage==RBU_STAGE_MOVE ){
+ /* no-op */
+ }else if( p->eStage==RBU_STAGE_CKPT ){
+ rbuSetupCheckpoint(p, pState);
+ }else if( p->eStage==RBU_STAGE_DONE ){
+ p->rc = SQLITE_DONE;
+ }else{
+ p->rc = SQLITE_CORRUPT;
+ }
+ }
+
+ rbuFreeState(pState);
+ }
+
+ return p;
+}
+
+/*
+** Allocate and return an RBU handle with all fields zeroed except for the
+** error code, which is set to SQLITE_MISUSE.
+*/
+static sqlite3rbu *rbuMisuseError(void){
+ sqlite3rbu *pRet;
+ pRet = sqlite3_malloc(sizeof(sqlite3rbu));
+ if( pRet ){
+ memset(pRet, 0, sizeof(sqlite3rbu));
+ pRet->rc = SQLITE_MISUSE;
+ }
+ return pRet;
+}
+
+/*
+** Open and return a new RBU handle.
+*/
+sqlite3rbu *sqlite3rbu_open(
+ const char *zTarget,
+ const char *zRbu,
+ const char *zState
+){
+ if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); }
+ /* TODO: Check that zTarget and zRbu are non-NULL */
+ return openRbuHandle(zTarget, zRbu, zState);
+}
+
+/*
+** Open a handle to begin or resume an RBU VACUUM operation.
+*/
+sqlite3rbu *sqlite3rbu_vacuum(
+ const char *zTarget,
+ const char *zState
+){
+ if( zTarget==0 ){ return rbuMisuseError(); }
+ if( zState ){
+ int n = strlen(zState);
+ if( n>=7 && 0==memcmp("-vactmp", &zState[n-7], 7) ){
+ return rbuMisuseError();
+ }
+ }
+ /* TODO: Check that both arguments are non-NULL */
+ return openRbuHandle(0, zTarget, zState);
+}
+
+/*
+** Return the database handle used by pRbu.
+*/
+sqlite3 *sqlite3rbu_db(sqlite3rbu *pRbu, int bRbu){
+ sqlite3 *db = 0;
+ if( pRbu ){
+ db = (bRbu ? pRbu->dbRbu : pRbu->dbMain);
+ }
+ return db;
+}
+
+
+/*
+** If the error code currently stored in the RBU handle is SQLITE_CONSTRAINT,
+** then edit any error message string so as to remove all occurrences of
+** the pattern "rbu_imp_[0-9]*".
+*/
+static void rbuEditErrmsg(sqlite3rbu *p){
+ if( p->rc==SQLITE_CONSTRAINT && p->zErrmsg ){
+ unsigned int i;
+ size_t nErrmsg = strlen(p->zErrmsg);
+ for(i=0; i<(nErrmsg-8); i++){
+ if( memcmp(&p->zErrmsg[i], "rbu_imp_", 8)==0 ){
+ int nDel = 8;
+ while( p->zErrmsg[i+nDel]>='0' && p->zErrmsg[i+nDel]<='9' ) nDel++;
+ memmove(&p->zErrmsg[i], &p->zErrmsg[i+nDel], nErrmsg + 1 - i - nDel);
+ nErrmsg -= nDel;
+ }
+ }
+ }
+}
+
+/*
+** Close the RBU handle.
+*/
+int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
+ int rc;
+ if( p ){
+
+ /* Commit the transaction to the *-oal file. */
+ if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_OAL ){
+ p->rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, &p->zErrmsg);
+ }
+
+ /* Sync the db file if currently doing an incremental checkpoint */
+ if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){
+ sqlite3_file *pDb = p->pTargetFd->pReal;
+ p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
+ }
+
+ rbuSaveState(p, p->eStage);
+
+ if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_OAL ){
+ p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, &p->zErrmsg);
+ }
+
+ /* Close any open statement handles. */
+ rbuObjIterFinalize(&p->objiter);
+
+ /* If this is an RBU vacuum handle and the vacuum has either finished
+ ** successfully or encountered an error, delete the contents of the
+ ** state table. This causes the next call to sqlite3rbu_vacuum()
+ ** specifying the current target and state databases to start a new
+ ** vacuum from scratch. */
+ if( rbuIsVacuum(p) && p->rc!=SQLITE_OK && p->dbRbu ){
+ int rc2 = sqlite3_exec(p->dbRbu, "DELETE FROM stat.rbu_state", 0, 0, 0);
+ if( p->rc==SQLITE_DONE && rc2!=SQLITE_OK ) p->rc = rc2;
+ }
+
+ /* Close the open database handle and VFS object. */
+ sqlite3_close(p->dbRbu);
+ sqlite3_close(p->dbMain);
+ assert( p->szTemp==0 );
+ rbuDeleteVfs(p);
+ sqlite3_free(p->aBuf);
+ sqlite3_free(p->aFrame);
+
+ rbuEditErrmsg(p);
+ rc = p->rc;
+ if( pzErrmsg ){
+ *pzErrmsg = p->zErrmsg;
+ }else{
+ sqlite3_free(p->zErrmsg);
+ }
+ sqlite3_free(p->zState);
+ sqlite3_free(p);
+ }else{
+ rc = SQLITE_NOMEM;
+ *pzErrmsg = 0;
+ }
+ return rc;
+}
+
+/*
+** Return the total number of key-value operations (inserts, deletes or
+** updates) that have been performed on the target database since the
+** current RBU update was started.
+*/
+sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu){
+ return pRbu->nProgress;
+}
+
+/*
+** Return permyriadage progress indications for the two main stages of
+** an RBU update.
+*/
+void sqlite3rbu_bp_progress(sqlite3rbu *p, int *pnOne, int *pnTwo){
+ const int MAX_PROGRESS = 10000;
+ switch( p->eStage ){
+ case RBU_STAGE_OAL:
+ if( p->nPhaseOneStep>0 ){
+ *pnOne = (int)(MAX_PROGRESS * (i64)p->nProgress/(i64)p->nPhaseOneStep);
+ }else{
+ *pnOne = -1;
+ }
+ *pnTwo = 0;
+ break;
+
+ case RBU_STAGE_MOVE:
+ *pnOne = MAX_PROGRESS;
+ *pnTwo = 0;
+ break;
+
+ case RBU_STAGE_CKPT:
+ *pnOne = MAX_PROGRESS;
+ *pnTwo = (int)(MAX_PROGRESS * (i64)p->nStep / (i64)p->nFrame);
+ break;
+
+ case RBU_STAGE_DONE:
+ *pnOne = MAX_PROGRESS;
+ *pnTwo = MAX_PROGRESS;
+ break;
+
+ default:
+ assert( 0 );
+ }
+}
+
+/*
+** Return the current state of the RBU vacuum or update operation.
+*/
+int sqlite3rbu_state(sqlite3rbu *p){
+ int aRes[] = {
+ 0, SQLITE_RBU_STATE_OAL, SQLITE_RBU_STATE_MOVE,
+ 0, SQLITE_RBU_STATE_CHECKPOINT, SQLITE_RBU_STATE_DONE
+ };
+
+ assert( RBU_STAGE_OAL==1 );
+ assert( RBU_STAGE_MOVE==2 );
+ assert( RBU_STAGE_CKPT==4 );
+ assert( RBU_STAGE_DONE==5 );
+ assert( aRes[RBU_STAGE_OAL]==SQLITE_RBU_STATE_OAL );
+ assert( aRes[RBU_STAGE_MOVE]==SQLITE_RBU_STATE_MOVE );
+ assert( aRes[RBU_STAGE_CKPT]==SQLITE_RBU_STATE_CHECKPOINT );
+ assert( aRes[RBU_STAGE_DONE]==SQLITE_RBU_STATE_DONE );
+
+ if( p->rc!=SQLITE_OK && p->rc!=SQLITE_DONE ){
+ return SQLITE_RBU_STATE_ERROR;
+ }else{
+ assert( p->rc!=SQLITE_DONE || p->eStage==RBU_STAGE_DONE );
+ assert( p->eStage==RBU_STAGE_OAL
+ || p->eStage==RBU_STAGE_MOVE
+ || p->eStage==RBU_STAGE_CKPT
+ || p->eStage==RBU_STAGE_DONE
+ );
+ return aRes[p->eStage];
+ }
+}
+
+int sqlite3rbu_savestate(sqlite3rbu *p){
+ int rc = p->rc;
+ if( rc==SQLITE_DONE ) return SQLITE_OK;
+
+ assert( p->eStage>=RBU_STAGE_OAL && p->eStage<=RBU_STAGE_DONE );
+ if( p->eStage==RBU_STAGE_OAL ){
+ assert( rc!=SQLITE_DONE );
+ if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, 0);
+ }
+
+ /* Sync the db file */
+ if( rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){
+ sqlite3_file *pDb = p->pTargetFd->pReal;
+ rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
+ }
+
+ p->rc = rc;
+ rbuSaveState(p, p->eStage);
+ rc = p->rc;
+
+ if( p->eStage==RBU_STAGE_OAL ){
+ assert( rc!=SQLITE_DONE );
+ if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0);
+ if( rc==SQLITE_OK ){
+ const char *zBegin = rbuIsVacuum(p) ? "BEGIN" : "BEGIN IMMEDIATE";
+ rc = sqlite3_exec(p->dbRbu, zBegin, 0, 0, 0);
+ }
+ if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "BEGIN IMMEDIATE", 0, 0,0);
+ }
+
+ p->rc = rc;
+ return rc;
+}
+
+/**************************************************************************
+** Beginning of RBU VFS shim methods. The VFS shim modifies the behaviour
+** of a standard VFS in the following ways:
+**
+** 1. Whenever the first page of a main database file is read or
+** written, the value of the change-counter cookie is stored in
+** rbu_file.iCookie. Similarly, the value of the "write-version"
+** database header field is stored in rbu_file.iWriteVer. This ensures
+** that the values are always trustworthy within an open transaction.
+**
+** 2. Whenever an SQLITE_OPEN_WAL file is opened, the (rbu_file.pWalFd)
+** member variable of the associated database file descriptor is set
+** to point to the new file. A mutex protected linked list of all main
+** db fds opened using a particular RBU VFS is maintained at
+** rbu_vfs.pMain to facilitate this.
+**
+** 3. Using a new file-control "SQLITE_FCNTL_RBU", a main db rbu_file
+** object can be marked as the target database of an RBU update. This
+** turns on the following extra special behaviour:
+**
+** 3a. If xAccess() is called to check if there exists a *-wal file
+** associated with an RBU target database currently in RBU_STAGE_OAL
+** stage (preparing the *-oal file), the following special handling
+** applies:
+**
+** * if the *-wal file does exist, return SQLITE_CANTOPEN. An RBU
+** target database may not be in wal mode already.
+**
+** * if the *-wal file does not exist, set the output parameter to
+** non-zero (to tell SQLite that it does exist) anyway.
+**
+** Then, when xOpen() is called to open the *-wal file associated with
+** the RBU target in RBU_STAGE_OAL stage, instead of opening the *-wal
+** file, the rbu vfs opens the corresponding *-oal file instead.
+**
+** 3b. The *-shm pages returned by xShmMap() for a target db file in
+** RBU_STAGE_OAL mode are actually stored in heap memory. This is to
+** avoid creating a *-shm file on disk. Additionally, xShmLock() calls
+** are no-ops on target database files in RBU_STAGE_OAL mode. This is
+** because assert() statements in some VFS implementations fail if
+** xShmLock() is called before xShmMap().
+**
+** 3c. If an EXCLUSIVE lock is attempted on a target database file in any
+** mode except RBU_STAGE_DONE (all work completed and checkpointed), it
+** fails with an SQLITE_BUSY error. This is to stop RBU connections
+** from automatically checkpointing a *-wal (or *-oal) file from within
+** sqlite3_close().
+**
+** 3d. In RBU_STAGE_CAPTURE mode, all xRead() calls on the wal file, and
+** all xWrite() calls on the target database file perform no IO.
+** Instead the frame and page numbers that would be read and written
+** are recorded. Additionally, successful attempts to obtain exclusive
+** xShmLock() WRITER, CHECKPOINTER and READ0 locks on the target
+** database file are recorded. xShmLock() calls to unlock the same
+** locks are no-ops (so that once obtained, these locks are never
+** relinquished). Finally, calls to xSync() on the target database
+** file fail with SQLITE_INTERNAL errors.
+*/
+
+static void rbuUnlockShm(rbu_file *p){
+ assert( p->openFlags & SQLITE_OPEN_MAIN_DB );
+ if( p->pRbu ){
+ int (*xShmLock)(sqlite3_file*,int,int,int) = p->pReal->pMethods->xShmLock;
+ int i;
+ for(i=0; i<SQLITE_SHM_NLOCK;i++){
+ if( (1<<i) & p->pRbu->mLock ){
+ xShmLock(p->pReal, i, 1, SQLITE_SHM_UNLOCK|SQLITE_SHM_EXCLUSIVE);
+ }
+ }
+ p->pRbu->mLock = 0;
+ }
+}
+
+/*
+*/
+static int rbuUpdateTempSize(rbu_file *pFd, sqlite3_int64 nNew){
+ sqlite3rbu *pRbu = pFd->pRbu;
+ i64 nDiff = nNew - pFd->sz;
+ pRbu->szTemp += nDiff;
+ pFd->sz = nNew;
+ assert( pRbu->szTemp>=0 );
+ if( pRbu->szTempLimit && pRbu->szTemp>pRbu->szTempLimit ) return SQLITE_FULL;
+ return SQLITE_OK;
+}
+
+/*
+** Add an item to the main-db lists, if it is not already present.
+**
+** There are two main-db lists. One for all file descriptors, and one
+** for all file descriptors with rbu_file.pDb!=0. If the argument has
+** rbu_file.pDb!=0, then it is assumed to already be present on the
+** main list and is only added to the pDb!=0 list.
+*/
+static void rbuMainlistAdd(rbu_file *p){
+ rbu_vfs *pRbuVfs = p->pRbuVfs;
+ rbu_file *pIter;
+ assert( (p->openFlags & SQLITE_OPEN_MAIN_DB) );
+ sqlite3_mutex_enter(pRbuVfs->mutex);
+ if( p->pRbu==0 ){
+ for(pIter=pRbuVfs->pMain; pIter; pIter=pIter->pMainNext);
+ p->pMainNext = pRbuVfs->pMain;
+ pRbuVfs->pMain = p;
+ }else{
+ for(pIter=pRbuVfs->pMainRbu; pIter && pIter!=p; pIter=pIter->pMainRbuNext){}
+ if( pIter==0 ){
+ p->pMainRbuNext = pRbuVfs->pMainRbu;
+ pRbuVfs->pMainRbu = p;
+ }
+ }
+ sqlite3_mutex_leave(pRbuVfs->mutex);
+}
+
+/*
+** Remove an item from the main-db lists.
+*/
+static void rbuMainlistRemove(rbu_file *p){
+ rbu_file **pp;
+ sqlite3_mutex_enter(p->pRbuVfs->mutex);
+ for(pp=&p->pRbuVfs->pMain; *pp && *pp!=p; pp=&((*pp)->pMainNext)){}
+ if( *pp ) *pp = p->pMainNext;
+ p->pMainNext = 0;
+ for(pp=&p->pRbuVfs->pMainRbu; *pp && *pp!=p; pp=&((*pp)->pMainRbuNext)){}
+ if( *pp ) *pp = p->pMainRbuNext;
+ p->pMainRbuNext = 0;
+ sqlite3_mutex_leave(p->pRbuVfs->mutex);
+}
+
+/*
+** Given that zWal points to a buffer containing a wal file name passed to
+** either the xOpen() or xAccess() VFS method, search the main-db list for
+** a file-handle opened by the same database connection on the corresponding
+** database file.
+**
+** If parameter bRbu is true, only search for file-descriptors with
+** rbu_file.pDb!=0.
+*/
+static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal, int bRbu){
+ rbu_file *pDb;
+ sqlite3_mutex_enter(pRbuVfs->mutex);
+ if( bRbu ){
+ for(pDb=pRbuVfs->pMainRbu; pDb && pDb->zWal!=zWal; pDb=pDb->pMainRbuNext){}
+ }else{
+ for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){}
+ }
+ sqlite3_mutex_leave(pRbuVfs->mutex);
+ return pDb;
+}
+
+/*
+** Close an rbu file.
+*/
+static int rbuVfsClose(sqlite3_file *pFile){
+ rbu_file *p = (rbu_file*)pFile;
+ int rc;
+ int i;
+
+ /* Free the contents of the apShm[] array. And the array itself. */
+ for(i=0; i<p->nShm; i++){
+ sqlite3_free(p->apShm[i]);
+ }
+ sqlite3_free(p->apShm);
+ p->apShm = 0;
+ sqlite3_free(p->zDel);
+
+ if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
+ rbuMainlistRemove(p);
+ rbuUnlockShm(p);
+ p->pReal->pMethods->xShmUnmap(p->pReal, 0);
+ }
+ else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
+ rbuUpdateTempSize(p, 0);
+ }
+ assert( p->pMainNext==0 && p->pRbuVfs->pMain!=p );
+
+ /* Close the underlying file handle */
+ rc = p->pReal->pMethods->xClose(p->pReal);
+ return rc;
+}
+
+
+/*
+** Read and return an unsigned 32-bit big-endian integer from the buffer
+** passed as the only argument.
+*/
+static u32 rbuGetU32(u8 *aBuf){
+ return ((u32)aBuf[0] << 24)
+ + ((u32)aBuf[1] << 16)
+ + ((u32)aBuf[2] << 8)
+ + ((u32)aBuf[3]);
+}
+
+/*
+** Write an unsigned 32-bit value in big-endian format to the supplied
+** buffer.
+*/
+static void rbuPutU32(u8 *aBuf, u32 iVal){
+ aBuf[0] = (iVal >> 24) & 0xFF;
+ aBuf[1] = (iVal >> 16) & 0xFF;
+ aBuf[2] = (iVal >> 8) & 0xFF;
+ aBuf[3] = (iVal >> 0) & 0xFF;
+}
+
+static void rbuPutU16(u8 *aBuf, u16 iVal){
+ aBuf[0] = (iVal >> 8) & 0xFF;
+ aBuf[1] = (iVal >> 0) & 0xFF;
+}
+
+/*
+** Read data from an rbuVfs-file.
+*/
+static int rbuVfsRead(
+ sqlite3_file *pFile,
+ void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ rbu_file *p = (rbu_file*)pFile;
+ sqlite3rbu *pRbu = p->pRbu;
+ int rc;
+
+ if( pRbu && pRbu->eStage==RBU_STAGE_CAPTURE ){
+ assert( p->openFlags & SQLITE_OPEN_WAL );
+ rc = rbuCaptureWalRead(p->pRbu, iOfst, iAmt);
+ }else{
+ if( pRbu && pRbu->eStage==RBU_STAGE_OAL
+ && (p->openFlags & SQLITE_OPEN_WAL)
+ && iOfst>=pRbu->iOalSz
+ ){
+ rc = SQLITE_OK;
+ memset(zBuf, 0, iAmt);
+ }else{
+ rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
+#if 1
+ /* If this is being called to read the first page of the target
+ ** database as part of an rbu vacuum operation, synthesize the
+ ** contents of the first page if it does not yet exist. Otherwise,
+ ** SQLite will not check for a *-wal file. */
+ if( pRbu && rbuIsVacuum(pRbu)
+ && rc==SQLITE_IOERR_SHORT_READ && iOfst==0
+ && (p->openFlags & SQLITE_OPEN_MAIN_DB)
+ && pRbu->rc==SQLITE_OK
+ ){
+ sqlite3_file *pFd = (sqlite3_file*)pRbu->pRbuFd;
+ rc = pFd->pMethods->xRead(pFd, zBuf, iAmt, iOfst);
+ if( rc==SQLITE_OK ){
+ u8 *aBuf = (u8*)zBuf;
+ u32 iRoot = rbuGetU32(&aBuf[52]) ? 1 : 0;
+ rbuPutU32(&aBuf[52], iRoot); /* largest root page number */
+ rbuPutU32(&aBuf[36], 0); /* number of free pages */
+ rbuPutU32(&aBuf[32], 0); /* first page on free list trunk */
+ rbuPutU32(&aBuf[28], 1); /* size of db file in pages */
+ rbuPutU32(&aBuf[24], pRbu->pRbuFd->iCookie+1); /* Change counter */
+
+ if( iAmt>100 ){
+ memset(&aBuf[100], 0, iAmt-100);
+ rbuPutU16(&aBuf[105], iAmt & 0xFFFF);
+ aBuf[100] = 0x0D;
+ }
+ }
+ }
+#endif
+ }
+ if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
+ /* These look like magic numbers. But they are stable, as they are part
+ ** of the definition of the SQLite file format, which may not change. */
+ u8 *pBuf = (u8*)zBuf;
+ p->iCookie = rbuGetU32(&pBuf[24]);
+ p->iWriteVer = pBuf[19];
+ }
+ }
+ return rc;
+}
+
+/*
+** Write data to an rbuVfs-file.
+*/
+static int rbuVfsWrite(
+ sqlite3_file *pFile,
+ const void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ rbu_file *p = (rbu_file*)pFile;
+ sqlite3rbu *pRbu = p->pRbu;
+ int rc;
+
+ if( pRbu && pRbu->eStage==RBU_STAGE_CAPTURE ){
+ assert( p->openFlags & SQLITE_OPEN_MAIN_DB );
+ rc = rbuCaptureDbWrite(p->pRbu, iOfst);
+ }else{
+ if( pRbu ){
+ if( pRbu->eStage==RBU_STAGE_OAL
+ && (p->openFlags & SQLITE_OPEN_WAL)
+ && iOfst>=pRbu->iOalSz
+ ){
+ pRbu->iOalSz = iAmt + iOfst;
+ }else if( p->openFlags & SQLITE_OPEN_DELETEONCLOSE ){
+ i64 szNew = iAmt+iOfst;
+ if( szNew>p->sz ){
+ rc = rbuUpdateTempSize(p, szNew);
+ if( rc!=SQLITE_OK ) return rc;
+ }
+ }
+ }
+ rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
+ if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
+ /* These look like magic numbers. But they are stable, as they are part
+ ** of the definition of the SQLite file format, which may not change. */
+ u8 *pBuf = (u8*)zBuf;
+ p->iCookie = rbuGetU32(&pBuf[24]);
+ p->iWriteVer = pBuf[19];
+ }
+ }
+ return rc;
+}
+
+/*
+** Truncate an rbuVfs-file.
+*/
+static int rbuVfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
+ rbu_file *p = (rbu_file*)pFile;
+ if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
+ int rc = rbuUpdateTempSize(p, size);
+ if( rc!=SQLITE_OK ) return rc;
+ }
+ return p->pReal->pMethods->xTruncate(p->pReal, size);
+}
+
+/*
+** Sync an rbuVfs-file.
+*/
+static int rbuVfsSync(sqlite3_file *pFile, int flags){
+ rbu_file *p = (rbu_file *)pFile;
+ if( p->pRbu && p->pRbu->eStage==RBU_STAGE_CAPTURE ){
+ if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
+ return SQLITE_INTERNAL;
+ }
+ return SQLITE_OK;
+ }
+ return p->pReal->pMethods->xSync(p->pReal, flags);
+}
+
+/*
+** Return the current file-size of an rbuVfs-file.
+*/
+static int rbuVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
+ rbu_file *p = (rbu_file *)pFile;
+ int rc;
+ rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
+
+ /* If this is an RBU vacuum operation and this is the target database,
+ ** pretend that it has at least one page. Otherwise, SQLite will not
+ ** check for the existance of a *-wal file. rbuVfsRead() contains
+ ** similar logic. */
+ if( rc==SQLITE_OK && *pSize==0
+ && p->pRbu && rbuIsVacuum(p->pRbu)
+ && (p->openFlags & SQLITE_OPEN_MAIN_DB)
+ ){
+ *pSize = 1024;
+ }
+ return rc;
+}
+
+/*
+** Lock an rbuVfs-file.
+*/
+static int rbuVfsLock(sqlite3_file *pFile, int eLock){
+ rbu_file *p = (rbu_file*)pFile;
+ sqlite3rbu *pRbu = p->pRbu;
+ int rc = SQLITE_OK;
+
+ assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
+ if( eLock==SQLITE_LOCK_EXCLUSIVE
+ && (p->bNolock || (pRbu && pRbu->eStage!=RBU_STAGE_DONE))
+ ){
+ /* Do not allow EXCLUSIVE locks. Preventing SQLite from taking this
+ ** prevents it from checkpointing the database from sqlite3_close(). */
+ rc = SQLITE_BUSY;
+ }else{
+ rc = p->pReal->pMethods->xLock(p->pReal, eLock);
+ }
+
+ return rc;
+}
+
+/*
+** Unlock an rbuVfs-file.
+*/
+static int rbuVfsUnlock(sqlite3_file *pFile, int eLock){
+ rbu_file *p = (rbu_file *)pFile;
+ return p->pReal->pMethods->xUnlock(p->pReal, eLock);
+}
+
+/*
+** Check if another file-handle holds a RESERVED lock on an rbuVfs-file.
+*/
+static int rbuVfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
+ rbu_file *p = (rbu_file *)pFile;
+ return p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
+}
+
+/*
+** File control method. For custom operations on an rbuVfs-file.
+*/
+static int rbuVfsFileControl(sqlite3_file *pFile, int op, void *pArg){
+ rbu_file *p = (rbu_file *)pFile;
+ int (*xControl)(sqlite3_file*,int,void*) = p->pReal->pMethods->xFileControl;
+ int rc;
+
+ assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB)
+ || p->openFlags & (SQLITE_OPEN_TRANSIENT_DB|SQLITE_OPEN_TEMP_JOURNAL)
+ );
+ if( op==SQLITE_FCNTL_RBU ){
+ sqlite3rbu *pRbu = (sqlite3rbu*)pArg;
+
+ /* First try to find another RBU vfs lower down in the vfs stack. If
+ ** one is found, this vfs will operate in pass-through mode. The lower
+ ** level vfs will do the special RBU handling. */
+ rc = xControl(p->pReal, op, pArg);
+
+ if( rc==SQLITE_NOTFOUND ){
+ /* Now search for a zipvfs instance lower down in the VFS stack. If
+ ** one is found, this is an error. */
+ void *dummy = 0;
+ rc = xControl(p->pReal, SQLITE_FCNTL_ZIPVFS, &dummy);
+ if( rc==SQLITE_OK ){
+ rc = SQLITE_ERROR;
+ pRbu->zErrmsg = sqlite3_mprintf("rbu/zipvfs setup error");
+ }else if( rc==SQLITE_NOTFOUND ){
+ pRbu->pTargetFd = p;
+ p->pRbu = pRbu;
+ if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
+ rbuMainlistAdd(p);
+ }
+ if( p->pWalFd ) p->pWalFd->pRbu = pRbu;
+ rc = SQLITE_OK;
+ }
+ }
+ return rc;
+ }
+ else if( op==SQLITE_FCNTL_RBUCNT ){
+ sqlite3rbu *pRbu = (sqlite3rbu*)pArg;
+ pRbu->nRbu++;
+ pRbu->pRbuFd = p;
+ p->bNolock = 1;
+ }
+
+ rc = xControl(p->pReal, op, pArg);
+ if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
+ rbu_vfs *pRbuVfs = p->pRbuVfs;
+ char *zIn = *(char**)pArg;
+ char *zOut = sqlite3_mprintf("rbu(%s)/%z", pRbuVfs->base.zName, zIn);
+ *(char**)pArg = zOut;
+ if( zOut==0 ) rc = SQLITE_NOMEM;
+ }
+
+ return rc;
+}
+
+/*
+** Return the sector-size in bytes for an rbuVfs-file.
+*/
+static int rbuVfsSectorSize(sqlite3_file *pFile){
+ rbu_file *p = (rbu_file *)pFile;
+ return p->pReal->pMethods->xSectorSize(p->pReal);
+}
+
+/*
+** Return the device characteristic flags supported by an rbuVfs-file.
+*/
+static int rbuVfsDeviceCharacteristics(sqlite3_file *pFile){
+ rbu_file *p = (rbu_file *)pFile;
+ return p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
+}
+
+/*
+** Take or release a shared-memory lock.
+*/
+static int rbuVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
+ rbu_file *p = (rbu_file*)pFile;
+ sqlite3rbu *pRbu = p->pRbu;
+ int rc = SQLITE_OK;
+
+#ifdef SQLITE_AMALGAMATION
+ assert( WAL_CKPT_LOCK==1 );
+#endif
+
+ assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
+ if( pRbu && (pRbu->eStage==RBU_STAGE_OAL || pRbu->eStage==RBU_STAGE_MOVE) ){
+ /* Magic number 1 is the WAL_CKPT_LOCK lock. Preventing SQLite from
+ ** taking this lock also prevents any checkpoints from occurring.
+ ** todo: really, it's not clear why this might occur, as
+ ** wal_autocheckpoint ought to be turned off. */
+ if( ofst==WAL_LOCK_CKPT && n==1 ) rc = SQLITE_BUSY;
+ }else{
+ int bCapture = 0;
+ if( n==1 && (flags & SQLITE_SHM_EXCLUSIVE)
+ && pRbu && pRbu->eStage==RBU_STAGE_CAPTURE
+ && (ofst==WAL_LOCK_WRITE || ofst==WAL_LOCK_CKPT || ofst==WAL_LOCK_READ0)
+ ){
+ bCapture = 1;
+ }
+
+ if( bCapture==0 || 0==(flags & SQLITE_SHM_UNLOCK) ){
+ rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
+ if( bCapture && rc==SQLITE_OK ){
+ pRbu->mLock |= (1 << ofst);
+ }
+ }
+ }
+
+ return rc;
+}
+
+/*
+** Obtain a pointer to a mapping of a single 32KiB page of the *-shm file.
+*/
+static int rbuVfsShmMap(
+ sqlite3_file *pFile,
+ int iRegion,
+ int szRegion,
+ int isWrite,
+ void volatile **pp
+){
+ rbu_file *p = (rbu_file*)pFile;
+ int rc = SQLITE_OK;
+ int eStage = (p->pRbu ? p->pRbu->eStage : 0);
+
+ /* If not in RBU_STAGE_OAL, allow this call to pass through. Or, if this
+ ** rbu is in the RBU_STAGE_OAL state, use heap memory for *-shm space
+ ** instead of a file on disk. */
+ assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
+ if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){
+ if( iRegion<=p->nShm ){
+ size_t nByte = (iRegion+1) * sizeof(char*);
+ char **apNew = (char**)sqlite3_realloc(p->apShm, nByte);
+ if( apNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm));
+ p->apShm = apNew;
+ p->nShm = iRegion+1;
+ }
+ }
+
+ if( rc==SQLITE_OK && p->apShm[iRegion]==0 ){
+ char *pNew = (char*)sqlite3_malloc(szRegion);
+ if( pNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(pNew, 0, szRegion);
+ p->apShm[iRegion] = pNew;
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ *pp = p->apShm[iRegion];
+ }else{
+ *pp = 0;
+ }
+ }else{
+ assert( p->apShm==0 );
+ rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
+ }
+
+ return rc;
+}
+
+/*
+** Memory barrier.
+*/
+static void rbuVfsShmBarrier(sqlite3_file *pFile){
+ rbu_file *p = (rbu_file *)pFile;
+ p->pReal->pMethods->xShmBarrier(p->pReal);
+}
+
+/*
+** The xShmUnmap method.
+*/
+static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){
+ rbu_file *p = (rbu_file*)pFile;
+ int rc = SQLITE_OK;
+ int eStage = (p->pRbu ? p->pRbu->eStage : 0);
+
+ assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
+ if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){
+ /* no-op */
+ }else{
+ /* Release the checkpointer and writer locks */
+ rbuUnlockShm(p);
+ rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
+ }
+ return rc;
+}
+
+/*
+** A main database named zName has just been opened. The following
+** function returns a pointer to a buffer owned by SQLite that contains
+** the name of the *-wal file this db connection will use. SQLite
+** happens to pass a pointer to this buffer when using xAccess()
+** or xOpen() to operate on the *-wal file.
+*/
+static const char *rbuMainToWal(const char *zName, int flags){
+ int n = (int)strlen(zName);
+ const char *z = &zName[n];
+ if( flags & SQLITE_OPEN_URI ){
+ int odd = 0;
+ while( 1 ){
+ if( z[0]==0 ){
+ odd = 1 - odd;
+ if( odd && z[1]==0 ) break;
+ }
+ z++;
+ }
+ z += 2;
+ }else{
+ while( *z==0 ) z++;
+ }
+ z += (n + 8 + 1);
+ return z;
+}
+
+/*
+** Open an rbu file handle.
+*/
+static int rbuVfsOpen(
+ sqlite3_vfs *pVfs,
+ const char *zName,
+ sqlite3_file *pFile,
+ int flags,
+ int *pOutFlags
+){
+ static sqlite3_io_methods rbuvfs_io_methods = {
+ 2, /* iVersion */
+ rbuVfsClose, /* xClose */
+ rbuVfsRead, /* xRead */
+ rbuVfsWrite, /* xWrite */
+ rbuVfsTruncate, /* xTruncate */
+ rbuVfsSync, /* xSync */
+ rbuVfsFileSize, /* xFileSize */
+ rbuVfsLock, /* xLock */
+ rbuVfsUnlock, /* xUnlock */
+ rbuVfsCheckReservedLock, /* xCheckReservedLock */
+ rbuVfsFileControl, /* xFileControl */
+ rbuVfsSectorSize, /* xSectorSize */
+ rbuVfsDeviceCharacteristics, /* xDeviceCharacteristics */
+ rbuVfsShmMap, /* xShmMap */
+ rbuVfsShmLock, /* xShmLock */
+ rbuVfsShmBarrier, /* xShmBarrier */
+ rbuVfsShmUnmap, /* xShmUnmap */
+ 0, 0 /* xFetch, xUnfetch */
+ };
+ rbu_vfs *pRbuVfs = (rbu_vfs*)pVfs;
+ sqlite3_vfs *pRealVfs = pRbuVfs->pRealVfs;
+ rbu_file *pFd = (rbu_file *)pFile;
+ int rc = SQLITE_OK;
+ const char *zOpen = zName;
+ int oflags = flags;
+
+ memset(pFd, 0, sizeof(rbu_file));
+ pFd->pReal = (sqlite3_file*)&pFd[1];
+ pFd->pRbuVfs = pRbuVfs;
+ pFd->openFlags = flags;
+ if( zName ){
+ if( flags & SQLITE_OPEN_MAIN_DB ){
+ /* A main database has just been opened. The following block sets
+ ** (pFd->zWal) to point to a buffer owned by SQLite that contains
+ ** the name of the *-wal file this db connection will use. SQLite
+ ** happens to pass a pointer to this buffer when using xAccess()
+ ** or xOpen() to operate on the *-wal file. */
+ pFd->zWal = rbuMainToWal(zName, flags);
+ }
+ else if( flags & SQLITE_OPEN_WAL ){
+ rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0);
+ if( pDb ){
+ if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
+ /* This call is to open a *-wal file. Intead, open the *-oal. This
+ ** code ensures that the string passed to xOpen() is terminated by a
+ ** pair of '\0' bytes in case the VFS attempts to extract a URI
+ ** parameter from it. */
+ const char *zBase = zName;
+ size_t nCopy;
+ char *zCopy;
+ if( rbuIsVacuum(pDb->pRbu) ){
+ zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main");
+ zBase = rbuMainToWal(zBase, SQLITE_OPEN_URI);
+ }
+ nCopy = strlen(zBase);
+ zCopy = sqlite3_malloc(nCopy+2);
+ if( zCopy ){
+ memcpy(zCopy, zBase, nCopy);
+ zCopy[nCopy-3] = 'o';
+ zCopy[nCopy] = '\0';
+ zCopy[nCopy+1] = '\0';
+ zOpen = (const char*)(pFd->zDel = zCopy);
+ }else{
+ rc = SQLITE_NOMEM;
+ }
+ pFd->pRbu = pDb->pRbu;
+ }
+ pDb->pWalFd = pFd;
+ }
+ }
+ }else{
+ pFd->pRbu = pRbuVfs->pRbu;
+ }
+
+ if( oflags & SQLITE_OPEN_MAIN_DB
+ && sqlite3_uri_boolean(zName, "rbu_memory", 0)
+ ){
+ assert( oflags & SQLITE_OPEN_MAIN_DB );
+ oflags = SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
+ SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE;
+ zOpen = 0;
+ }
+
+ if( rc==SQLITE_OK ){
+ rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, oflags, pOutFlags);
+ }
+ if( pFd->pReal->pMethods ){
+ /* The xOpen() operation has succeeded. Set the sqlite3_file.pMethods
+ ** pointer and, if the file is a main database file, link it into the
+ ** mutex protected linked list of all such files. */
+ pFile->pMethods = &rbuvfs_io_methods;
+ if( flags & SQLITE_OPEN_MAIN_DB ){
+ rbuMainlistAdd(pFd);
+ }
+ }else{
+ sqlite3_free(pFd->zDel);
+ }
+
+ return rc;
+}
+
+/*
+** Delete the file located at zPath.
+*/
+static int rbuVfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+ sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
+ return pRealVfs->xDelete(pRealVfs, zPath, dirSync);
+}
+
+/*
+** Test for access permissions. Return true if the requested permission
+** is available, or false otherwise.
+*/
+static int rbuVfsAccess(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int flags,
+ int *pResOut
+){
+ rbu_vfs *pRbuVfs = (rbu_vfs*)pVfs;
+ sqlite3_vfs *pRealVfs = pRbuVfs->pRealVfs;
+ int rc;
+
+ rc = pRealVfs->xAccess(pRealVfs, zPath, flags, pResOut);
+
+ /* If this call is to check if a *-wal file associated with an RBU target
+ ** database connection exists, and the RBU update is in RBU_STAGE_OAL,
+ ** the following special handling is activated:
+ **
+ ** a) if the *-wal file does exist, return SQLITE_CANTOPEN. This
+ ** ensures that the RBU extension never tries to update a database
+ ** in wal mode, even if the first page of the database file has
+ ** been damaged.
+ **
+ ** b) if the *-wal file does not exist, claim that it does anyway,
+ ** causing SQLite to call xOpen() to open it. This call will also
+ ** be intercepted (see the rbuVfsOpen() function) and the *-oal
+ ** file opened instead.
+ */
+ if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){
+ rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath, 1);
+ if( pDb && pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
+ if( *pResOut ){
+ rc = SQLITE_CANTOPEN;
+ }else{
+ sqlite3_int64 sz = 0;
+ rc = rbuVfsFileSize(&pDb->base, &sz);
+ *pResOut = (sz>0);
+ }
+ }
+ }
+
+ return rc;
+}
+
+/*
+** Populate buffer zOut with the full canonical pathname corresponding
+** to the pathname in zPath. zOut is guaranteed to point to a buffer
+** of at least (DEVSYM_MAX_PATHNAME+1) bytes.
+*/
+static int rbuVfsFullPathname(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int nOut,
+ char *zOut
+){
+ sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
+ return pRealVfs->xFullPathname(pRealVfs, zPath, nOut, zOut);
+}
+
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+/*
+** Open the dynamic library located at zPath and return a handle.
+*/
+static void *rbuVfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
+ sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
+ return pRealVfs->xDlOpen(pRealVfs, zPath);
+}
+
+/*
+** Populate the buffer zErrMsg (size nByte bytes) with a human readable
+** utf-8 string describing the most recent error encountered associated
+** with dynamic libraries.
+*/
+static void rbuVfsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
+ sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
+ pRealVfs->xDlError(pRealVfs, nByte, zErrMsg);
+}
+
+/*
+** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
+*/
+static void (*rbuVfsDlSym(
+ sqlite3_vfs *pVfs,
+ void *pArg,
+ const char *zSym
+))(void){
+ sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
+ return pRealVfs->xDlSym(pRealVfs, pArg, zSym);
+}
+
+/*
+** Close the dynamic library handle pHandle.
+*/
+static void rbuVfsDlClose(sqlite3_vfs *pVfs, void *pHandle){
+ sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
+ pRealVfs->xDlClose(pRealVfs, pHandle);
+}
+#endif /* SQLITE_OMIT_LOAD_EXTENSION */
+
+/*
+** Populate the buffer pointed to by zBufOut with nByte bytes of
+** random data.
+*/
+static int rbuVfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
+ sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
+ return pRealVfs->xRandomness(pRealVfs, nByte, zBufOut);
+}
+
+/*
+** Sleep for nMicro microseconds. Return the number of microseconds
+** actually slept.
+*/
+static int rbuVfsSleep(sqlite3_vfs *pVfs, int nMicro){
+ sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
+ return pRealVfs->xSleep(pRealVfs, nMicro);
+}
+
+/*
+** Return the current time as a Julian Day number in *pTimeOut.
+*/
+static int rbuVfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
+ sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
+ return pRealVfs->xCurrentTime(pRealVfs, pTimeOut);
+}
+
+/*
+** No-op.
+*/
+static int rbuVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){
+ return 0;
+}
+
+/*
+** Deregister and destroy an RBU vfs created by an earlier call to
+** sqlite3rbu_create_vfs().
+*/
+void sqlite3rbu_destroy_vfs(const char *zName){
+ sqlite3_vfs *pVfs = sqlite3_vfs_find(zName);
+ if( pVfs && pVfs->xOpen==rbuVfsOpen ){
+ sqlite3_mutex_free(((rbu_vfs*)pVfs)->mutex);
+ sqlite3_vfs_unregister(pVfs);
+ sqlite3_free(pVfs);
+ }
+}
+
+/*
+** Create an RBU VFS named zName that accesses the underlying file-system
+** via existing VFS zParent. The new object is registered as a non-default
+** VFS with SQLite before returning.
+*/
+int sqlite3rbu_create_vfs(const char *zName, const char *zParent){
+
+ /* Template for VFS */
+ static sqlite3_vfs vfs_template = {
+ 1, /* iVersion */
+ 0, /* szOsFile */
+ 0, /* mxPathname */
+ 0, /* pNext */
+ 0, /* zName */
+ 0, /* pAppData */
+ rbuVfsOpen, /* xOpen */
+ rbuVfsDelete, /* xDelete */
+ rbuVfsAccess, /* xAccess */
+ rbuVfsFullPathname, /* xFullPathname */
+
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ rbuVfsDlOpen, /* xDlOpen */
+ rbuVfsDlError, /* xDlError */
+ rbuVfsDlSym, /* xDlSym */
+ rbuVfsDlClose, /* xDlClose */
+#else
+ 0, 0, 0, 0,
+#endif
+
+ rbuVfsRandomness, /* xRandomness */
+ rbuVfsSleep, /* xSleep */
+ rbuVfsCurrentTime, /* xCurrentTime */
+ rbuVfsGetLastError, /* xGetLastError */
+ 0, /* xCurrentTimeInt64 (version 2) */
+ 0, 0, 0 /* Unimplemented version 3 methods */
+ };
+
+ rbu_vfs *pNew = 0; /* Newly allocated VFS */
+ int rc = SQLITE_OK;
+ size_t nName;
+ size_t nByte;
+
+ nName = strlen(zName);
+ nByte = sizeof(rbu_vfs) + nName + 1;
+ pNew = (rbu_vfs*)sqlite3_malloc(nByte);
+ if( pNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ sqlite3_vfs *pParent; /* Parent VFS */
+ memset(pNew, 0, nByte);
+ pParent = sqlite3_vfs_find(zParent);
+ if( pParent==0 ){
+ rc = SQLITE_NOTFOUND;
+ }else{
+ char *zSpace;
+ memcpy(&pNew->base, &vfs_template, sizeof(sqlite3_vfs));
+ pNew->base.mxPathname = pParent->mxPathname;
+ pNew->base.szOsFile = sizeof(rbu_file) + pParent->szOsFile;
+ pNew->pRealVfs = pParent;
+ pNew->base.zName = (const char*)(zSpace = (char*)&pNew[1]);
+ memcpy(zSpace, zName, nName);
+
+ /* Allocate the mutex and register the new VFS (not as the default) */
+ pNew->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE);
+ if( pNew->mutex==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_vfs_register(&pNew->base, 0);
+ }
+ }
+
+ if( rc!=SQLITE_OK ){
+ sqlite3_mutex_free(pNew->mutex);
+ sqlite3_free(pNew);
+ }
+ }
+
+ return rc;
+}
+
+/*
+** Configure the aggregate temp file size limit for this RBU handle.
+*/
+sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu *pRbu, sqlite3_int64 n){
+ if( n>=0 ){
+ pRbu->szTempLimit = n;
+ }
+ return pRbu->szTempLimit;
+}
+
+sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu *pRbu){
+ return pRbu->szTemp;
+}
+
+
+/**************************************************************************/
+
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) */
--- origsrc/sqlite-autoconf-3300000/sqlite3rbu.h 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/sqlite3rbu.h 2019-03-05 13:14:41.036000000 +0100
@@ -0,0 +1,605 @@
+/*
+** 2014 August 30
+**
+** 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 the public interface for the RBU extension.
+*/
+
+/*
+** SUMMARY
+**
+** Writing a transaction containing a large number of operations on
+** b-tree indexes that are collectively larger than the available cache
+** memory can be very inefficient.
+**
+** The problem is that in order to update a b-tree, the leaf page (at least)
+** containing the entry being inserted or deleted must be modified. If the
+** working set of leaves is larger than the available cache memory, then a
+** single leaf that is modified more than once as part of the transaction
+** may be loaded from or written to the persistent media multiple times.
+** Additionally, because the index updates are likely to be applied in
+** random order, access to pages within the database is also likely to be in
+** random order, which is itself quite inefficient.
+**
+** One way to improve the situation is to sort the operations on each index
+** by index key before applying them to the b-tree. This leads to an IO
+** pattern that resembles a single linear scan through the index b-tree,
+** and all but guarantees each modified leaf page is loaded and stored
+** exactly once. SQLite uses this trick to improve the performance of
+** CREATE INDEX commands. This extension allows it to be used to improve
+** the performance of large transactions on existing databases.
+**
+** Additionally, this extension allows the work involved in writing the
+** large transaction to be broken down into sub-transactions performed
+** sequentially by separate processes. This is useful if the system cannot
+** guarantee that a single update process will run for long enough to apply
+** the entire update, for example because the update is being applied on a
+** mobile device that is frequently rebooted. Even after the writer process
+** has committed one or more sub-transactions, other database clients continue
+** to read from the original database snapshot. In other words, partially
+** applied transactions are not visible to other clients.
+**
+** "RBU" stands for "Resumable Bulk Update". As in a large database update
+** transmitted via a wireless network to a mobile device. A transaction
+** applied using this extension is hence refered to as an "RBU update".
+**
+**
+** LIMITATIONS
+**
+** An "RBU update" transaction is subject to the following limitations:
+**
+** * The transaction must consist of INSERT, UPDATE and DELETE operations
+** only.
+**
+** * INSERT statements may not use any default values.
+**
+** * UPDATE and DELETE statements must identify their target rows by
+** non-NULL PRIMARY KEY values. Rows with NULL values stored in PRIMARY
+** KEY fields may not be updated or deleted. If the table being written
+** has no PRIMARY KEY, affected rows must be identified by rowid.
+**
+** * UPDATE statements may not modify PRIMARY KEY columns.
+**
+** * No triggers will be fired.
+**
+** * No foreign key violations are detected or reported.
+**
+** * CHECK constraints are not enforced.
+**
+** * No constraint handling mode except for "OR ROLLBACK" is supported.
+**
+**
+** PREPARATION
+**
+** An "RBU update" is stored as a separate SQLite database. A database
+** containing an RBU update is an "RBU database". For each table in the
+** target database to be updated, the RBU database should contain a table
+** named "data_<target name>" containing the same set of columns as the
+** target table, and one more - "rbu_control". The data_% table should
+** have no PRIMARY KEY or UNIQUE constraints, but each column should have
+** the same type as the corresponding column in the target database.
+** The "rbu_control" column should have no type at all. For example, if
+** the target database contains:
+**
+** CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c UNIQUE);
+**
+** Then the RBU database should contain:
+**
+** CREATE TABLE data_t1(a INTEGER, b TEXT, c, rbu_control);
+**
+** The order of the columns in the data_% table does not matter.
+**
+** Instead of a regular table, the RBU database may also contain virtual
+** tables or view named using the data_<target> naming scheme.
+**
+** Instead of the plain data_<target> naming scheme, RBU database tables
+** may also be named data<integer>_<target>, where <integer> is any sequence
+** of zero or more numeric characters (0-9). This can be significant because
+** tables within the RBU database are always processed in order sorted by
+** name. By judicious selection of the <integer> portion of the names
+** of the RBU tables the user can therefore control the order in which they
+** are processed. This can be useful, for example, to ensure that "external
+** content" FTS4 tables are updated before their underlying content tables.
+**
+** If the target database table is a virtual table or a table that has no
+** PRIMARY KEY declaration, the data_% table must also contain a column
+** named "rbu_rowid". This column is mapped to the tables implicit primary
+** key column - "rowid". Virtual tables for which the "rowid" column does
+** not function like a primary key value cannot be updated using RBU. For
+** example, if the target db contains either of the following:
+**
+** CREATE VIRTUAL TABLE x1 USING fts3(a, b);
+** CREATE TABLE x1(a, b)
+**
+** then the RBU database should contain:
+**
+** CREATE TABLE data_x1(a, b, rbu_rowid, rbu_control);
+**
+** All non-hidden columns (i.e. all columns matched by "SELECT *") of the
+** target table must be present in the input table. For virtual tables,
+** hidden columns are optional - they are updated by RBU if present in
+** the input table, or not otherwise. For example, to write to an fts4
+** table with a hidden languageid column such as:
+**
+** CREATE VIRTUAL TABLE ft1 USING fts4(a, b, languageid='langid');
+**
+** Either of the following input table schemas may be used:
+**
+** CREATE TABLE data_ft1(a, b, langid, rbu_rowid, rbu_control);
+** CREATE TABLE data_ft1(a, b, rbu_rowid, rbu_control);
+**
+** For each row to INSERT into the target database as part of the RBU
+** update, the corresponding data_% table should contain a single record
+** with the "rbu_control" column set to contain integer value 0. The
+** other columns should be set to the values that make up the new record
+** to insert.
+**
+** If the target database table has an INTEGER PRIMARY KEY, it is not
+** possible to insert a NULL value into the IPK column. Attempting to
+** do so results in an SQLITE_MISMATCH error.
+**
+** For each row to DELETE from the target database as part of the RBU
+** update, the corresponding data_% table should contain a single record
+** with the "rbu_control" column set to contain integer value 1. The
+** real primary key values of the row to delete should be stored in the
+** corresponding columns of the data_% table. The values stored in the
+** other columns are not used.
+**
+** For each row to UPDATE from the target database as part of the RBU
+** update, the corresponding data_% table should contain a single record
+** with the "rbu_control" column set to contain a value of type text.
+** The real primary key values identifying the row to update should be
+** stored in the corresponding columns of the data_% table row, as should
+** the new values of all columns being update. The text value in the
+** "rbu_control" column must contain the same number of characters as
+** there are columns in the target database table, and must consist entirely
+** of 'x' and '.' characters (or in some special cases 'd' - see below). For
+** each column that is being updated, the corresponding character is set to
+** 'x'. For those that remain as they are, the corresponding character of the
+** rbu_control value should be set to '.'. For example, given the tables
+** above, the update statement:
+**
+** UPDATE t1 SET c = 'usa' WHERE a = 4;
+**
+** is represented by the data_t1 row created by:
+**
+** INSERT INTO data_t1(a, b, c, rbu_control) VALUES(4, NULL, 'usa', '..x');
+**
+** Instead of an 'x' character, characters of the rbu_control value specified
+** for UPDATEs may also be set to 'd'. In this case, instead of updating the
+** target table with the value stored in the corresponding data_% column, the
+** user-defined SQL function "rbu_delta()" is invoked and the result stored in
+** the target table column. rbu_delta() is invoked with two arguments - the
+** original value currently stored in the target table column and the
+** value specified in the data_xxx table.
+**
+** For example, this row:
+**
+** INSERT INTO data_t1(a, b, c, rbu_control) VALUES(4, NULL, 'usa', '..d');
+**
+** is similar to an UPDATE statement such as:
+**
+** UPDATE t1 SET c = rbu_delta(c, 'usa') WHERE a = 4;
+**
+** Finally, if an 'f' character appears in place of a 'd' or 's' in an
+** ota_control string, the contents of the data_xxx table column is assumed
+** to be a "fossil delta" - a patch to be applied to a blob value in the
+** format used by the fossil source-code management system. In this case
+** the existing value within the target database table must be of type BLOB.
+** It is replaced by the result of applying the specified fossil delta to
+** itself.
+**
+** If the target database table is a virtual table or a table with no PRIMARY
+** KEY, the rbu_control value should not include a character corresponding
+** to the rbu_rowid value. For example, this:
+**
+** INSERT INTO data_ft1(a, b, rbu_rowid, rbu_control)
+** VALUES(NULL, 'usa', 12, '.x');
+**
+** causes a result similar to:
+**
+** UPDATE ft1 SET b = 'usa' WHERE rowid = 12;
+**
+** The data_xxx tables themselves should have no PRIMARY KEY declarations.
+** However, RBU is more efficient if reading the rows in from each data_xxx
+** table in "rowid" order is roughly the same as reading them sorted by
+** the PRIMARY KEY of the corresponding target database table. In other
+** words, rows should be sorted using the destination table PRIMARY KEY
+** fields before they are inserted into the data_xxx tables.
+**
+** USAGE
+**
+** The API declared below allows an application to apply an RBU update
+** stored on disk to an existing target database. Essentially, the
+** application:
+**
+** 1) Opens an RBU handle using the sqlite3rbu_open() function.
+**
+** 2) Registers any required virtual table modules with the database
+** handle returned by sqlite3rbu_db(). Also, if required, register
+** the rbu_delta() implementation.
+**
+** 3) Calls the sqlite3rbu_step() function one or more times on
+** the new handle. Each call to sqlite3rbu_step() performs a single
+** b-tree operation, so thousands of calls may be required to apply
+** a complete update.
+**
+** 4) Calls sqlite3rbu_close() to close the RBU update handle. If
+** sqlite3rbu_step() has been called enough times to completely
+** apply the update to the target database, then the RBU database
+** is marked as fully applied. Otherwise, the state of the RBU
+** update application is saved in the RBU database for later
+** resumption.
+**
+** See comments below for more detail on APIs.
+**
+** If an update is only partially applied to the target database by the
+** time sqlite3rbu_close() is called, various state information is saved
+** within the RBU database. This allows subsequent processes to automatically
+** resume the RBU update from where it left off.
+**
+** To remove all RBU extension state information, returning an RBU database
+** to its original contents, it is sufficient to drop all tables that begin
+** with the prefix "rbu_"
+**
+** DATABASE LOCKING
+**
+** An RBU update may not be applied to a database in WAL mode. Attempting
+** to do so is an error (SQLITE_ERROR).
+**
+** While an RBU handle is open, a SHARED lock may be held on the target
+** database file. This means it is possible for other clients to read the
+** database, but not to write it.
+**
+** If an RBU update is started and then suspended before it is completed,
+** then an external client writes to the database, then attempting to resume
+** the suspended RBU update is also an error (SQLITE_BUSY).
+*/
+
+#ifndef _SQLITE3RBU_H
+#define _SQLITE3RBU_H
+
+#include "sqlite3.h" /* Required for error code definitions */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct sqlite3rbu sqlite3rbu;
+
+/*
+** Open an RBU handle.
+**
+** Argument zTarget is the path to the target database. Argument zRbu is
+** the path to the RBU database. Each call to this function must be matched
+** by a call to sqlite3rbu_close(). When opening the databases, RBU passes
+** the SQLITE_CONFIG_URI flag to sqlite3_open_v2(). So if either zTarget
+** or zRbu begin with "file:", it will be interpreted as an SQLite
+** database URI, not a regular file name.
+**
+** If the zState argument is passed a NULL value, the RBU extension stores
+** the current state of the update (how many rows have been updated, which
+** indexes are yet to be updated etc.) within the RBU database itself. This
+** can be convenient, as it means that the RBU application does not need to
+** organize removing a separate state file after the update is concluded.
+** Or, if zState is non-NULL, it must be a path to a database file in which
+** the RBU extension can store the state of the update.
+**
+** When resuming an RBU update, the zState argument must be passed the same
+** value as when the RBU update was started.
+**
+** Once the RBU update is finished, the RBU extension does not
+** automatically remove any zState database file, even if it created it.
+**
+** By default, RBU uses the default VFS to access the files on disk. To
+** use a VFS other than the default, an SQLite "file:" URI containing a
+** "vfs=..." option may be passed as the zTarget option.
+**
+** IMPORTANT NOTE FOR ZIPVFS USERS: The RBU extension works with all of
+** SQLite's built-in VFSs, including the multiplexor VFS. However it does
+** not work out of the box with zipvfs. Refer to the comment describing
+** the zipvfs_create_vfs() API below for details on using RBU with zipvfs.
+*/
+SQLITE_API sqlite3rbu *sqlite3rbu_open(
+ const char *zTarget,
+ const char *zRbu,
+ const char *zState
+);
+
+/*
+** Open an RBU handle to perform an RBU vacuum on database file zTarget.
+** An RBU vacuum is similar to SQLite's built-in VACUUM command, except
+** that it can be suspended and resumed like an RBU update.
+**
+** The second argument to this function identifies a database in which
+** to store the state of the RBU vacuum operation if it is suspended. The
+** first time sqlite3rbu_vacuum() is called, to start an RBU vacuum
+** operation, the state database should either not exist or be empty
+** (contain no tables). If an RBU vacuum is suspended by calling
+** sqlite3rbu_close() on the RBU handle before sqlite3rbu_step() has
+** returned SQLITE_DONE, the vacuum state is stored in the state database.
+** The vacuum can be resumed by calling this function to open a new RBU
+** handle specifying the same target and state databases.
+**
+** If the second argument passed to this function is NULL, then the
+** name of the state database is "<database>-vacuum", where <database>
+** is the name of the target database file. In this case, on UNIX, if the
+** state database is not already present in the file-system, it is created
+** with the same permissions as the target db is made.
+**
+** With an RBU vacuum, it is an SQLITE_MISUSE error if the name of the
+** state database ends with "-vactmp". This name is reserved for internal
+** use.
+**
+** This function does not delete the state database after an RBU vacuum
+** is completed, even if it created it. However, if the call to
+** sqlite3rbu_close() returns any value other than SQLITE_OK, the contents
+** of the state tables within the state database are zeroed. This way,
+** the next call to sqlite3rbu_vacuum() opens a handle that starts a
+** new RBU vacuum operation.
+**
+** As with sqlite3rbu_open(), Zipvfs users should rever to the comment
+** describing the sqlite3rbu_create_vfs() API function below for
+** a description of the complications associated with using RBU with
+** zipvfs databases.
+*/
+SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
+ const char *zTarget,
+ const char *zState
+);
+
+/*
+** Configure a limit for the amount of temp space that may be used by
+** the RBU handle passed as the first argument. The new limit is specified
+** in bytes by the second parameter. If it is positive, the limit is updated.
+** If the second parameter to this function is passed zero, then the limit
+** is removed entirely. If the second parameter is negative, the limit is
+** not modified (this is useful for querying the current limit).
+**
+** In all cases the returned value is the current limit in bytes (zero
+** indicates unlimited).
+**
+** If the temp space limit is exceeded during operation, an SQLITE_FULL
+** error is returned.
+*/
+SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu*, sqlite3_int64);
+
+/*
+** Return the current amount of temp file space, in bytes, currently used by
+** the RBU handle passed as the only argument.
+*/
+SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu*);
+
+/*
+** Internally, each RBU connection uses a separate SQLite database
+** connection to access the target and rbu update databases. This
+** API allows the application direct access to these database handles.
+**
+** The first argument passed to this function must be a valid, open, RBU
+** handle. The second argument should be passed zero to access the target
+** database handle, or non-zero to access the rbu update database handle.
+** Accessing the underlying database handles may be useful in the
+** following scenarios:
+**
+** * If any target tables are virtual tables, it may be necessary to
+** call sqlite3_create_module() on the target database handle to
+** register the required virtual table implementations.
+**
+** * If the data_xxx tables in the RBU source database are virtual
+** tables, the application may need to call sqlite3_create_module() on
+** the rbu update db handle to any required virtual table
+** implementations.
+**
+** * If the application uses the "rbu_delta()" feature described above,
+** it must use sqlite3_create_function() or similar to register the
+** rbu_delta() implementation with the target database handle.
+**
+** If an error has occurred, either while opening or stepping the RBU object,
+** this function may return NULL. The error code and message may be collected
+** when sqlite3rbu_close() is called.
+**
+** Database handles returned by this function remain valid until the next
+** call to any sqlite3rbu_xxx() function other than sqlite3rbu_db().
+*/
+SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu*, int bRbu);
+
+/*
+** Do some work towards applying the RBU update to the target db.
+**
+** Return SQLITE_DONE if the update has been completely applied, or
+** SQLITE_OK if no error occurs but there remains work to do to apply
+** the RBU update. If an error does occur, some other error code is
+** returned.
+**
+** Once a call to sqlite3rbu_step() has returned a value other than
+** SQLITE_OK, all subsequent calls on the same RBU handle are no-ops
+** that immediately return the same value.
+*/
+SQLITE_API int sqlite3rbu_step(sqlite3rbu *pRbu);
+
+/*
+** Force RBU to save its state to disk.
+**
+** If a power failure or application crash occurs during an update, following
+** system recovery RBU may resume the update from the point at which the state
+** was last saved. In other words, from the most recent successful call to
+** sqlite3rbu_close() or this function.
+**
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
+*/
+SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu);
+
+/*
+** Close an RBU handle.
+**
+** If the RBU update has been completely applied, mark the RBU database
+** as fully applied. Otherwise, assuming no error has occurred, save the
+** current state of the RBU update appliation to the RBU database.
+**
+** If an error has already occurred as part of an sqlite3rbu_step()
+** or sqlite3rbu_open() call, or if one occurs within this function, an
+** SQLite error code is returned. Additionally, if pzErrmsg is not NULL,
+** *pzErrmsg may be set to point to a buffer containing a utf-8 formatted
+** English language error message. It is the responsibility of the caller to
+** eventually free any such buffer using sqlite3_free().
+**
+** Otherwise, if no error occurs, this function returns SQLITE_OK if the
+** update has been partially applied, or SQLITE_DONE if it has been
+** completely applied.
+*/
+SQLITE_API int sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg);
+
+/*
+** Return the total number of key-value operations (inserts, deletes or
+** updates) that have been performed on the target database since the
+** current RBU update was started.
+*/
+SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
+
+/*
+** Obtain permyriadage (permyriadage is to 10000 as percentage is to 100)
+** progress indications for the two stages of an RBU update. This API may
+** be useful for driving GUI progress indicators and similar.
+**
+** An RBU update is divided into two stages:
+**
+** * Stage 1, in which changes are accumulated in an oal/wal file, and
+** * Stage 2, in which the contents of the wal file are copied into the
+** main database.
+**
+** The update is visible to non-RBU clients during stage 2. During stage 1
+** non-RBU reader clients may see the original database.
+**
+** If this API is called during stage 2 of the update, output variable
+** (*pnOne) is set to 10000 to indicate that stage 1 has finished and (*pnTwo)
+** to a value between 0 and 10000 to indicate the permyriadage progress of
+** stage 2. A value of 5000 indicates that stage 2 is half finished,
+** 9000 indicates that it is 90% finished, and so on.
+**
+** If this API is called during stage 1 of the update, output variable
+** (*pnTwo) is set to 0 to indicate that stage 2 has not yet started. The
+** value to which (*pnOne) is set depends on whether or not the RBU
+** database contains an "rbu_count" table. The rbu_count table, if it
+** exists, must contain the same columns as the following:
+**
+** CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
+**
+** There must be one row in the table for each source (data_xxx) table within
+** the RBU database. The 'tbl' column should contain the name of the source
+** table. The 'cnt' column should contain the number of rows within the
+** source table.
+**
+** If the rbu_count table is present and populated correctly and this
+** API is called during stage 1, the *pnOne output variable is set to the
+** permyriadage progress of the same stage. If the rbu_count table does
+** not exist, then (*pnOne) is set to -1 during stage 1. If the rbu_count
+** table exists but is not correctly populated, the value of the *pnOne
+** output variable during stage 1 is undefined.
+*/
+SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo);
+
+/*
+** Obtain an indication as to the current stage of an RBU update or vacuum.
+** This function always returns one of the SQLITE_RBU_STATE_XXX constants
+** defined in this file. Return values should be interpreted as follows:
+**
+** SQLITE_RBU_STATE_OAL:
+** RBU is currently building a *-oal file. The next call to sqlite3rbu_step()
+** may either add further data to the *-oal file, or compute data that will
+** be added by a subsequent call.
+**
+** SQLITE_RBU_STATE_MOVE:
+** RBU has finished building the *-oal file. The next call to sqlite3rbu_step()
+** will move the *-oal file to the equivalent *-wal path. If the current
+** operation is an RBU update, then the updated version of the database
+** file will become visible to ordinary SQLite clients following the next
+** call to sqlite3rbu_step().
+**
+** SQLITE_RBU_STATE_CHECKPOINT:
+** RBU is currently performing an incremental checkpoint. The next call to
+** sqlite3rbu_step() will copy a page of data from the *-wal file into
+** the target database file.
+**
+** SQLITE_RBU_STATE_DONE:
+** The RBU operation has finished. Any subsequent calls to sqlite3rbu_step()
+** will immediately return SQLITE_DONE.
+**
+** SQLITE_RBU_STATE_ERROR:
+** An error has occurred. Any subsequent calls to sqlite3rbu_step() will
+** immediately return the SQLite error code associated with the error.
+*/
+#define SQLITE_RBU_STATE_OAL 1
+#define SQLITE_RBU_STATE_MOVE 2
+#define SQLITE_RBU_STATE_CHECKPOINT 3
+#define SQLITE_RBU_STATE_DONE 4
+#define SQLITE_RBU_STATE_ERROR 5
+
+SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu);
+
+/*
+** Create an RBU VFS named zName that accesses the underlying file-system
+** via existing VFS zParent. Or, if the zParent parameter is passed NULL,
+** then the new RBU VFS uses the default system VFS to access the file-system.
+** The new object is registered as a non-default VFS with SQLite before
+** returning.
+**
+** Part of the RBU implementation uses a custom VFS object. Usually, this
+** object is created and deleted automatically by RBU.
+**
+** The exception is for applications that also use zipvfs. In this case,
+** the custom VFS must be explicitly created by the user before the RBU
+** handle is opened. The RBU VFS should be installed so that the zipvfs
+** VFS uses the RBU VFS, which in turn uses any other VFS layers in use
+** (for example multiplexor) to access the file-system. For example,
+** to assemble an RBU enabled VFS stack that uses both zipvfs and
+** multiplexor (error checking omitted):
+**
+** // Create a VFS named "multiplex" (not the default).
+** sqlite3_multiplex_initialize(0, 0);
+**
+** // Create an rbu VFS named "rbu" that uses multiplexor. If the
+** // second argument were replaced with NULL, the "rbu" VFS would
+** // access the file-system via the system default VFS, bypassing the
+** // multiplexor.
+** sqlite3rbu_create_vfs("rbu", "multiplex");
+**
+** // Create a zipvfs VFS named "zipvfs" that uses rbu.
+** zipvfs_create_vfs_v3("zipvfs", "rbu", 0, xCompressorAlgorithmDetector);
+**
+** // Make zipvfs the default VFS.
+** sqlite3_vfs_register(sqlite3_vfs_find("zipvfs"), 1);
+**
+** Because the default VFS created above includes a RBU functionality, it
+** may be used by RBU clients. Attempting to use RBU with a zipvfs VFS stack
+** that does not include the RBU layer results in an error.
+**
+** The overhead of adding the "rbu" VFS to the system is negligible for
+** non-RBU users. There is no harm in an application accessing the
+** file-system via "rbu" all the time, even if it only uses RBU functionality
+** occasionally.
+*/
+SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent);
+
+/*
+** Deregister and destroy an RBU vfs created by an earlier call to
+** sqlite3rbu_create_vfs().
+**
+** VFS objects are not reference counted. If a VFS object is destroyed
+** before all database handles that use it have been closed, the results
+** are undefined.
+*/
+SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName);
+
+#ifdef __cplusplus
+} /* end of the 'extern "C"' block */
+#endif
+
+#endif /* _SQLITE3RBU_H */
--- origsrc/sqlite-autoconf-3300000/stmt.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/stmt.c 2019-10-08 13:42:19.227691200 +0200
@@ -0,0 +1,299 @@
+/*
+** 2017-05-31
+**
+** 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 demonstrates an eponymous virtual table that returns information
+** about all prepared statements for the database connection.
+**
+** Usage example:
+**
+** .load ./stmt
+** .mode line
+** .header on
+** SELECT * FROM stmt;
+*/
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB)
+#if !defined(SQLITEINT_H)
+#include "sqlite3ext.h"
+#endif
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/* stmt_vtab is a subclass of sqlite3_vtab which will
+** serve as the underlying representation of a stmt virtual table
+*/
+typedef struct stmt_vtab stmt_vtab;
+struct stmt_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this stmt vtab */
+};
+
+/* stmt_cursor is a subclass of sqlite3_vtab_cursor which will
+** serve as the underlying representation of a cursor that scans
+** over rows of the result
+*/
+typedef struct stmt_cursor stmt_cursor;
+struct stmt_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this cursor */
+ sqlite3_stmt *pStmt; /* Statement cursor is currently pointing at */
+ sqlite3_int64 iRowid; /* The rowid */
+};
+
+/*
+** The stmtConnect() method is invoked to create a new
+** stmt_vtab that describes the stmt virtual table.
+**
+** Think of this routine as the constructor for stmt_vtab objects.
+**
+** All this routine needs to do is:
+**
+** (1) Allocate the stmt_vtab object and initialize all fields.
+**
+** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
+** result set of queries against stmt will look like.
+*/
+static int stmtConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ stmt_vtab *pNew;
+ int rc;
+
+/* Column numbers */
+#define STMT_COLUMN_SQL 0 /* SQL for the statement */
+#define STMT_COLUMN_NCOL 1 /* Number of result columns */
+#define STMT_COLUMN_RO 2 /* True if read-only */
+#define STMT_COLUMN_BUSY 3 /* True if currently busy */
+#define STMT_COLUMN_NSCAN 4 /* SQLITE_STMTSTATUS_FULLSCAN_STEP */
+#define STMT_COLUMN_NSORT 5 /* SQLITE_STMTSTATUS_SORT */
+#define STMT_COLUMN_NAIDX 6 /* SQLITE_STMTSTATUS_AUTOINDEX */
+#define STMT_COLUMN_NSTEP 7 /* SQLITE_STMTSTATUS_VM_STEP */
+#define STMT_COLUMN_REPREP 8 /* SQLITE_STMTSTATUS_REPREPARE */
+#define STMT_COLUMN_RUN 9 /* SQLITE_STMTSTATUS_RUN */
+#define STMT_COLUMN_MEM 10 /* SQLITE_STMTSTATUS_MEMUSED */
+
+
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x(sql,ncol,ro,busy,nscan,nsort,naidx,nstep,"
+ "reprep,run,mem)");
+ if( rc==SQLITE_OK ){
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->db = db;
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for stmt_cursor objects.
+*/
+static int stmtDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new stmt_cursor object.
+*/
+static int stmtOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ stmt_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ pCur->db = ((stmt_vtab*)p)->db;
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Destructor for a stmt_cursor.
+*/
+static int stmtClose(sqlite3_vtab_cursor *cur){
+ sqlite3_free(cur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a stmt_cursor to its next row of output.
+*/
+static int stmtNext(sqlite3_vtab_cursor *cur){
+ stmt_cursor *pCur = (stmt_cursor*)cur;
+ pCur->iRowid++;
+ pCur->pStmt = sqlite3_next_stmt(pCur->db, pCur->pStmt);
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the stmt_cursor
+** is currently pointing.
+*/
+static int stmtColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ stmt_cursor *pCur = (stmt_cursor*)cur;
+ switch( i ){
+ case STMT_COLUMN_SQL: {
+ sqlite3_result_text(ctx, sqlite3_sql(pCur->pStmt), -1, SQLITE_TRANSIENT);
+ break;
+ }
+ case STMT_COLUMN_NCOL: {
+ sqlite3_result_int(ctx, sqlite3_column_count(pCur->pStmt));
+ break;
+ }
+ case STMT_COLUMN_RO: {
+ sqlite3_result_int(ctx, sqlite3_stmt_readonly(pCur->pStmt));
+ break;
+ }
+ case STMT_COLUMN_BUSY: {
+ sqlite3_result_int(ctx, sqlite3_stmt_busy(pCur->pStmt));
+ break;
+ }
+ case STMT_COLUMN_MEM: {
+ i = SQLITE_STMTSTATUS_MEMUSED +
+ STMT_COLUMN_NSCAN - SQLITE_STMTSTATUS_FULLSCAN_STEP;
+ /* Fall thru */
+ }
+ case STMT_COLUMN_NSCAN:
+ case STMT_COLUMN_NSORT:
+ case STMT_COLUMN_NAIDX:
+ case STMT_COLUMN_NSTEP:
+ case STMT_COLUMN_REPREP:
+ case STMT_COLUMN_RUN: {
+ sqlite3_result_int(ctx, sqlite3_stmt_status(pCur->pStmt,
+ i-STMT_COLUMN_NSCAN+SQLITE_STMTSTATUS_FULLSCAN_STEP, 0));
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** rowid is the same as the output value.
+*/
+static int stmtRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ stmt_cursor *pCur = (stmt_cursor*)cur;
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int stmtEof(sqlite3_vtab_cursor *cur){
+ stmt_cursor *pCur = (stmt_cursor*)cur;
+ return pCur->pStmt==0;
+}
+
+/*
+** This method is called to "rewind" the stmt_cursor object back
+** to the first row of output. This method is always called at least
+** once prior to any call to stmtColumn() or stmtRowid() or
+** stmtEof().
+*/
+static int stmtFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ stmt_cursor *pCur = (stmt_cursor *)pVtabCursor;
+ pCur->pStmt = 0;
+ pCur->iRowid = 0;
+ return stmtNext(pVtabCursor);
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the stmt virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+*/
+static int stmtBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ pIdxInfo->estimatedCost = (double)500;
+ pIdxInfo->estimatedRows = 500;
+ return SQLITE_OK;
+}
+
+/*
+** This following structure defines all the methods for the
+** stmt virtual table.
+*/
+static const sqlite3_module stmtModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ stmtConnect, /* xConnect */
+ stmtBestIndex, /* xBestIndex */
+ stmtDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ stmtOpen, /* xOpen - open a cursor */
+ stmtClose, /* xClose - close a cursor */
+ stmtFilter, /* xFilter - configure scan constraints */
+ stmtNext, /* xNext - advance a cursor */
+ stmtEof, /* xEof - check for end of scan */
+ stmtColumn, /* xColumn - read data */
+ stmtRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0, /* xShadowName */
+};
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+int sqlite3StmtVtabInit(sqlite3 *db){
+ int rc = SQLITE_OK;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3_create_module(db, "sqlite_stmt", &stmtModule, 0);
+#endif
+ return rc;
+}
+
+#ifndef SQLITE_CORE
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_stmt_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3StmtVtabInit(db);
+#endif
+ return rc;
+}
+#endif /* SQLITE_CORE */
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
--- origsrc/sqlite-autoconf-3300000/tea/configure.ac 2019-10-04 18:28:17.000000000 +0200
+++ src/sqlite-autoconf-3300000/tea/configure.ac 2019-10-08 13:02:00.005130500 +0200
@@ -6,7 +6,7 @@ dnl to configure the system for the loca
# RCS: @(#) $Id: configure.in,v 1.43 2005/07/26 19:17:05 mdejong Exp $
#-----------------------------------------------------------------------
-# Sample configure.in for Tcl Extensions. The only places you should
+# Sample configure.ac for Tcl Extensions. The only places you should
# need to modify this file are marked by the string __CHANGE__
#-----------------------------------------------------------------------
@@ -27,7 +27,7 @@ AC_INIT([sqlite], [3.30.0])
# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE.
#--------------------------------------------------------------------
-TEA_INIT([3.9])
+TEA_INIT([3.10])
AC_CONFIG_AUX_DIR(tclconfig)
@@ -75,9 +75,25 @@ TEA_ADD_SOURCES([tclsqlite3.c])
TEA_ADD_HEADERS([])
TEA_ADD_INCLUDES([-I\"`\${CYGPATH} \${srcdir}/generic`\"])
TEA_ADD_LIBS([])
-TEA_ADD_CFLAGS([-DSQLITE_ENABLE_FTS3=1])
+TEA_ADD_CFLAGS([-DSQLITE_ENABLE_DBPAGE_VTAB=1])
+TEA_ADD_CFLAGS([-DSQLITE_ENABLE_DBSTAT_VTAB=1])
+TEA_ADD_CFLAGS([-DSQLITE_ENABLE_FTS3_PARENTHESIS=1])
+TEA_ADD_CFLAGS([-DSQLITE_ENABLE_FTS4=1])
+TEA_ADD_CFLAGS([-DSQLITE_ENABLE_FTS5=1])
+TEA_ADD_CFLAGS([-DSQLITE_ENABLE_COLUMN_METADATA=1])
+TEA_ADD_CFLAGS([-DSQLITE_ENABLE_JSON1=1])
TEA_ADD_CFLAGS([-DSQLITE_3_SUFFIX_ONLY=1])
TEA_ADD_CFLAGS([-DSQLITE_ENABLE_RTREE=1])
+TEA_ADD_CFLAGS([-DSQLITE_ENABLE_GEOPOLY=1])
+TEA_ADD_CFLAGS([-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1])
+TEA_ADD_CFLAGS([-DSQLITE_LIKE_DOESNT_MATCH_BLOBS=1])
+TEA_ADD_CFLAGS([-DSQLITE_UNTESTABLE=1])
+TEA_ADD_CFLAGS([-DSQLITE_OMIT_LOOKASIDE=1])
+TEA_ADD_CFLAGS([-DSQLITE_SECURE_DELETE=1])
+TEA_ADD_CFLAGS([-DSQLITE_SOUNDEX=1])
+TEA_ADD_CFLAGS([-DSQLITE_USE_ALLOCA=1])
+TEA_ADD_CFLAGS([-DSQLITE_WIN32_NO_ANSI=1])
+TEA_ADD_CFLAGS([-DSQLITE_WIN32_GETVERSIONEX=0])
TEA_ADD_STUB_SOURCES([])
TEA_ADD_TCL_SOURCES([])
@@ -167,8 +183,9 @@ AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stu
#--------------------------------------------------------------------
#
#AC_CHECK_FUNC(fdatasync, , AC_DEFINE(fdatasync, fsync))
+AC_CHECK_HEADERS([malloc.h])
# Check for library functions that SQLite can optionally use.
-AC_CHECK_FUNCS([fdatasync usleep fullfsync localtime_r gmtime_r])
+AC_CHECK_FUNCS([fdatasync usleep strchrnul localtime_r gmtime_r localtime_s malloc_usable_size utime flock readlink lstat pread pread64 pwrite pwrite64])
AC_FUNC_STRERROR_R
--- origsrc/sqlite-autoconf-3300000/tea/generic/tclsqlite3.c 2019-10-04 18:28:17.000000000 +0200
+++ src/sqlite-autoconf-3300000/tea/generic/tclsqlite3.c 2019-03-05 13:14:41.074000000 +0100
@@ -1,7 +1,7 @@
#ifdef USE_SYSTEM_SQLITE
# include <sqlite3.h>
#else
-#include "sqlite3.c"
+#include "../compat/sqlite3/sqlite3.c"
#endif
/*
** 2001 September 15
@@ -80,6 +80,30 @@
# define GETPID (int)GetCurrentProcessId
#endif
+#ifdef USE_TCL_STUBS
+# undef Tcl_BackgroundException
+# define Tcl_BackgroundException(interp, result) (DbUseNre()? \
+ ((void (*)(Tcl_Interp *, int))((&(tclStubsPtr->tcl_PkgProvideEx))[609]))((interp), (result)): \
+ ((void (*)(Tcl_Interp *))((&(tclStubsPtr->tcl_PkgProvideEx))[76]))(interp))
+#endif /* USE_TCL_STUBS */
+
+#if TCL_MAJOR_VERSION>8 || (TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION>=6)
+static int DbUseNre(void);
+#endif
+
+/*
+ * If we are not sure the platform is 32-bit, always use sqlite3_????64()
+ * in stead of sqlite3_????() for certain functions, in order to prevent overflow.
+ */
+#if !defined(i386) && !defined(__i386__) && !defined(_M_IX86) && \
+ !defined(_M_ARM) && !defined(__arm__) && !defined(__x86) && \
+ (!defined(__SIZEOF_POINTER__) || (__SIZEOF_POINTER__ != 4))
+# undef sqlite3_bind_text
+# undef sqlite3_result_text
+# define sqlite3_bind_text(pStmt, i, zData, nData, xDel) sqlite3_bind_text64(pStmt, i, zData, nData, xDel, SQLITE_UTF8)
+# define sqlite3_result_text(pCtx, z, n, xDel) sqlite3_result_text64(pCtx, z, n, xDel, SQLITE_UTF8)
+#endif
+
/*
* Windows needs to know which symbols to export. Unix does not.
* BUILD_sqlite should be undefined for Unix.
@@ -210,6 +234,10 @@ static int strlen30(const char *z){
return 0x3fffffff & (int)(z2 - z);
}
+#ifdef USE_TCL_STUBS
+# define tclStubsPtr staticTclStubsPtr
+static const TclStubs *tclStubsPtr = 0;
+#endif
#ifndef SQLITE_OMIT_INCRBLOB
/*
@@ -257,7 +285,7 @@ static int SQLITE_TCLAPI incrblobClose(
Tcl_Free((char *)p);
if( rc!=SQLITE_OK ){
- Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE);
+ Tcl_AppendResult(interp, sqlite3_errmsg(db), (char*)0);
return TCL_ERROR;
}
return TCL_OK;
@@ -300,7 +328,7 @@ static int SQLITE_TCLAPI incrblobInput(
*/
static int SQLITE_TCLAPI incrblobOutput(
ClientData instanceData,
- CONST char *buf,
+ const char *buf,
int toWrite,
int *errorCodePtr
){
@@ -413,7 +441,7 @@ static int createIncrblobChannel(
rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRow, !isReadonly, &pBlob);
if( rc!=SQLITE_OK ){
- Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
+ Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0);
return TCL_ERROR;
}
@@ -434,7 +462,7 @@ static int createIncrblobChannel(
pDb->pIncrblob = p;
p->pDb = pDb;
- Tcl_SetResult(interp, (char *)Tcl_GetChannelName(p->channel), TCL_VOLATILE);
+ Tcl_AppendResult(interp, Tcl_GetChannelName(p->channel), (char*)0);
return TCL_OK;
}
#else /* else clause for "#ifndef SQLITE_OMIT_INCRBLOB" */
@@ -589,10 +617,16 @@ static void SQLITE_TCLAPI DbDeleteCmd(vo
static int DbBusyHandler(void *cd, int nTries){
SqliteDb *pDb = (SqliteDb*)cd;
int rc;
- char zVal[30];
+ char zVal[32];
+ Tcl_DString dstring;
- sqlite3_snprintf(sizeof(zVal), zVal, "%d", nTries);
- rc = Tcl_VarEval(pDb->interp, pDb->zBusy, " ", zVal, (char*)0);
+ sqlite3_snprintf(sizeof(zVal), zVal, " %d", nTries);
+ Tcl_DStringInit(&dstring);
+ Tcl_DStringAppend(&dstring, pDb->zBusy, -1);
+ Tcl_DStringAppend(&dstring, zVal, -1);
+ rc = Tcl_EvalEx(pDb->interp, Tcl_DStringValue(&dstring),
+ Tcl_DStringLength(&dstring), TCL_EVAL_GLOBAL);
+ Tcl_DStringFree(&dstring);
if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
return 0;
}
@@ -608,7 +642,7 @@ static int DbProgressHandler(void *cd){
int rc;
assert( pDb->zProgress );
- rc = Tcl_Eval(pDb->interp, pDb->zProgress);
+ rc = Tcl_EvalEx(pDb->interp, pDb->zProgress, -1, 0);
if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
return 1;
}
@@ -616,22 +650,27 @@ static int DbProgressHandler(void *cd){
}
#endif
-#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \
- !defined(SQLITE_OMIT_DEPRECATED)
+#ifndef SQLITE_OMIT_TRACE
/*
** This routine is called by the SQLite trace handler whenever a new
** block of SQL is executed. The TCL script in pDb->zTrace is executed.
*/
-static void DbTraceHandler(void *cd, const char *zSql){
+static int DbTraceHandler(
+ unsigned type, /* One of the SQLITE_TRACE_* event types. */
+ void *cd, /* The original context data pointer. */
+ void *pd, /* Primary event data, depends on event type. */
+ void *xd /* Extra event data, depends on event type. */
+){
SqliteDb *pDb = (SqliteDb*)cd;
Tcl_DString str;
Tcl_DStringInit(&str);
Tcl_DStringAppend(&str, pDb->zTrace, -1);
- Tcl_DStringAppendElement(&str, zSql);
- Tcl_Eval(pDb->interp, Tcl_DStringValue(&str));
+ Tcl_DStringAppendElement(&str, (char *)xd);
+ Tcl_EvalEx(pDb->interp, Tcl_DStringValue(&str), -1, 0);
Tcl_DStringFree(&str);
Tcl_ResetResult(pDb->interp);
+ return TCL_OK;
}
#endif
@@ -659,7 +698,7 @@ static int DbTraceV2Handler(
pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
Tcl_IncrRefCount(pCmd);
Tcl_ListObjAppendElement(pDb->interp, pCmd,
- Tcl_NewWideIntObj((Tcl_WideInt)pStmt));
+ Tcl_NewWideIntObj((size_t)pStmt));
Tcl_ListObjAppendElement(pDb->interp, pCmd,
Tcl_NewStringObj(zSql, -1));
Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
@@ -674,7 +713,7 @@ static int DbTraceV2Handler(
pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
Tcl_IncrRefCount(pCmd);
Tcl_ListObjAppendElement(pDb->interp, pCmd,
- Tcl_NewWideIntObj((Tcl_WideInt)pStmt));
+ Tcl_NewWideIntObj((size_t)pStmt));
Tcl_ListObjAppendElement(pDb->interp, pCmd,
Tcl_NewWideIntObj((Tcl_WideInt)ns));
Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
@@ -688,7 +727,7 @@ static int DbTraceV2Handler(
pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
Tcl_IncrRefCount(pCmd);
Tcl_ListObjAppendElement(pDb->interp, pCmd,
- Tcl_NewWideIntObj((Tcl_WideInt)pStmt));
+ Tcl_NewWideIntObj((size_t)pStmt));
Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
Tcl_DecrRefCount(pCmd);
Tcl_ResetResult(pDb->interp);
@@ -700,7 +739,7 @@ static int DbTraceV2Handler(
pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
Tcl_IncrRefCount(pCmd);
Tcl_ListObjAppendElement(pDb->interp, pCmd,
- Tcl_NewWideIntObj((Tcl_WideInt)db));
+ Tcl_NewWideIntObj((size_t)db));
Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
Tcl_DecrRefCount(pCmd);
Tcl_ResetResult(pDb->interp);
@@ -711,25 +750,31 @@ static int DbTraceV2Handler(
}
#endif
-#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \
- !defined(SQLITE_OMIT_DEPRECATED)
+#ifndef SQLITE_OMIT_TRACE
/*
** This routine is called by the SQLite profile handler after a statement
** SQL has executed. The TCL script in pDb->zProfile is evaluated.
*/
-static void DbProfileHandler(void *cd, const char *zSql, sqlite_uint64 tm){
+static int DbProfileHandler(
+ unsigned type, /* One of the SQLITE_TRACE_* event types. */
+ void *cd, /* The original context data pointer. */
+ void *pd, /* Primary event data, depends on event type. */
+ void *xd /* Extra event data, depends on event type. */
+){
SqliteDb *pDb = (SqliteDb*)cd;
Tcl_DString str;
char zTm[100];
+ sqlite3_stmt *pStmt = (sqlite3_stmt *)pd;
- sqlite3_snprintf(sizeof(zTm)-1, zTm, "%lld", tm);
+ sqlite3_snprintf(sizeof(zTm)-1, zTm, "%lld", (Tcl_WideInt)(size_t)xd);
Tcl_DStringInit(&str);
Tcl_DStringAppend(&str, pDb->zProfile, -1);
- Tcl_DStringAppendElement(&str, zSql);
+ Tcl_DStringAppendElement(&str, sqlite3_sql(pStmt));
Tcl_DStringAppendElement(&str, zTm);
- Tcl_Eval(pDb->interp, Tcl_DStringValue(&str));
+ Tcl_EvalEx(pDb->interp, Tcl_DStringValue(&str), -1, 0);
Tcl_DStringFree(&str);
Tcl_ResetResult(pDb->interp);
+ return SQLITE_OK;
}
#endif
@@ -743,7 +788,7 @@ static int DbCommitHandler(void *cd){
SqliteDb *pDb = (SqliteDb*)cd;
int rc;
- rc = Tcl_Eval(pDb->interp, pDb->zCommit);
+ rc = Tcl_EvalEx(pDb->interp, pDb->zCommit, -1, 0);
if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
return 1;
}
@@ -751,10 +796,11 @@ static int DbCommitHandler(void *cd){
}
static void DbRollbackHandler(void *clientData){
+ int rc;
SqliteDb *pDb = (SqliteDb*)clientData;
assert(pDb->pRollbackHook);
- if( TCL_OK!=Tcl_EvalObjEx(pDb->interp, pDb->pRollbackHook, 0) ){
- Tcl_BackgroundError(pDb->interp);
+ if( TCL_OK!=(rc=Tcl_EvalObjEx(pDb->interp, pDb->pRollbackHook, 0)) ){
+ Tcl_BackgroundException(pDb->interp, rc);
}
}
@@ -767,7 +813,7 @@ static int DbWalHandler(
const char *zDb,
int nEntry
){
- int ret = SQLITE_OK;
+ int ret = SQLITE_OK, rc;
Tcl_Obj *p;
SqliteDb *pDb = (SqliteDb*)clientData;
Tcl_Interp *interp = pDb->interp;
@@ -777,11 +823,11 @@ static int DbWalHandler(
p = Tcl_DuplicateObj(pDb->pWalHook);
Tcl_IncrRefCount(p);
Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1));
- Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj(nEntry));
- if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0)
- || TCL_OK!=Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &ret)
+ Tcl_ListObjAppendElement(interp, p, Tcl_NewWideIntObj(nEntry));
+ if( TCL_OK!=(rc=Tcl_EvalObjEx(interp, p, 0))
+ || TCL_OK!=(rc=Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &ret))
){
- Tcl_BackgroundError(interp);
+ Tcl_BackgroundException(interp, rc);
}
Tcl_DecrRefCount(p);
@@ -792,9 +838,9 @@ static int DbWalHandler(
static void setTestUnlockNotifyVars(Tcl_Interp *interp, int iArg, int nArg){
char zBuf[64];
sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", iArg);
- Tcl_SetVar(interp, "sqlite_unlock_notify_arg", zBuf, TCL_GLOBAL_ONLY);
+ Tcl_SetVar2(interp, "sqlite_unlock_notify_arg", NULL, zBuf, TCL_GLOBAL_ONLY);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nArg);
- Tcl_SetVar(interp, "sqlite_unlock_notify_argcount", zBuf, TCL_GLOBAL_ONLY);
+ Tcl_SetVar2(interp, "sqlite_unlock_notify_argcount", NULL, zBuf, TCL_GLOBAL_ONLY);
}
#else
# define setTestUnlockNotifyVars(x,y,z)
@@ -830,7 +876,7 @@ static void DbPreUpdateHandler(
){
SqliteDb *pDb = (SqliteDb *)p;
Tcl_Obj *pCmd;
- static const char *azStr[] = {"DELETE", "INSERT", "UPDATE"};
+ static const char azStr[][8] = {"DELETE", "INSERT", "UPDATE"};
assert( (SQLITE_DELETE-1)/9 == 0 );
assert( (SQLITE_INSERT-1)/9 == 1 );
@@ -860,7 +906,7 @@ static void DbUpdateHandler(
){
SqliteDb *pDb = (SqliteDb *)p;
Tcl_Obj *pCmd;
- static const char *azStr[] = {"DELETE", "INSERT", "UPDATE"};
+ static const char azStr[][8] = {"DELETE", "INSERT", "UPDATE"};
assert( (SQLITE_DELETE-1)/9 == 0 );
assert( (SQLITE_INSERT-1)/9 == 1 );
@@ -966,11 +1012,7 @@ static void tclSqlFunc(sqlite3_context *
}
case SQLITE_INTEGER: {
sqlite_int64 v = sqlite3_value_int64(pIn);
- if( v>=-2147483647 && v<=2147483647 ){
- pVal = Tcl_NewIntObj((int)v);
- }else{
- pVal = Tcl_NewWideIntObj(v);
- }
+ pVal = Tcl_NewWideIntObj(v);
break;
}
case SQLITE_FLOAT: {
@@ -1013,6 +1055,7 @@ static void tclSqlFunc(sqlite3_context *
u8 *data;
const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");
char c = zType[0];
+
int eType = p->eType;
if( eType==SQLITE_NULL ){
@@ -1020,7 +1063,8 @@ static void tclSqlFunc(sqlite3_context *
/* Only return a BLOB type if the Tcl variable is a bytearray and
** has no string representation. */
eType = SQLITE_BLOB;
- }else if( (c=='b' && strcmp(zType,"boolean")==0)
+ }else if( (c=='b' && ((strcmp(zType,"boolean")==0)
+ || (strcmp(zType,"booleanString")==0)))
|| (c=='w' && strcmp(zType,"wideInt")==0)
|| (c=='i' && strcmp(zType,"int")==0)
){
@@ -1143,7 +1187,7 @@ static int auth_callback(
#ifdef SQLITE_USER_AUTHENTICATION
Tcl_DStringAppendElement(&str, zArg5 ? zArg5 : "");
#endif
- rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str));
+ rc = Tcl_EvalEx(pDb->interp, Tcl_DStringValue(&str), -1, TCL_EVAL_GLOBAL);
Tcl_DStringFree(&str);
zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY";
if( strcmp(zReply,"SQLITE_OK")==0 ){
@@ -1159,6 +1203,7 @@ static int auth_callback(
}
#endif /* SQLITE_OMIT_AUTHORIZATION */
+#if 0
/*
** This routine reads a line of text from FILE in, stores
** the text in memory obtained from malloc() and returns a pointer
@@ -1203,6 +1248,7 @@ static char *local_getline(char *zPrompt
zLine = realloc( zLine, n+1 );
return zLine;
}
+#endif
/*
@@ -1432,8 +1478,9 @@ static int dbPrepareAndBind(
sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC);
Tcl_IncrRefCount(pVar);
pPreStmt->apParm[iParm++] = pVar;
- }else if( c=='b' && strcmp(zType,"boolean")==0 ){
- Tcl_GetIntFromObj(interp, pVar, &n);
+ }else if( c=='b' && (strcmp(zType,"boolean")==0 ||
+ strcmp(zType,"booleanString")==0) ){
+ Tcl_GetBooleanFromObj(interp, pVar, &n);
sqlite3_bind_int(pStmt, i, n);
}else if( c=='d' && strcmp(zType,"double")==0 ){
double r;
@@ -1445,8 +1492,8 @@ static int dbPrepareAndBind(
Tcl_GetWideIntFromObj(interp, pVar, &v);
sqlite3_bind_int64(pStmt, i, v);
}else{
- data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);
- sqlite3_bind_text(pStmt, i, (char *)data, n, SQLITE_STATIC);
+ data = (unsigned char *)Tcl_GetString(pVar);
+ sqlite3_bind_text(pStmt, i, (char *)data, pVar->length, SQLITE_STATIC);
Tcl_IncrRefCount(pVar);
pPreStmt->apParm[iParm++] = pVar;
}
@@ -1742,11 +1789,7 @@ static Tcl_Obj *dbEvalColumnValue(DbEval
}
case SQLITE_INTEGER: {
sqlite_int64 v = sqlite3_column_int64(pStmt, iCol);
- if( v>=-2147483647 && v<=2147483647 ){
- return Tcl_NewIntObj((int)v);
- }else{
- return Tcl_NewWideIntObj(v);
- }
+ return Tcl_NewWideIntObj(v);
}
case SQLITE_FLOAT: {
return Tcl_NewDoubleObj(sqlite3_column_double(pStmt, iCol));
@@ -1768,7 +1811,7 @@ static Tcl_Obj *dbEvalColumnValue(DbEval
*/
#if TCL_MAJOR_VERSION>8 || (TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION>=6)
# define SQLITE_TCL_NRE 1
-static int DbUseNre(void){
+int DbUseNre(void){
int major, minor;
Tcl_GetVersion(&major, &minor, 0, 0);
return( (major==8 && minor>=6) || major>8 );
@@ -1918,37 +1961,37 @@ static int SQLITE_TCLAPI DbObjCmd(
SqliteDb *pDb = (SqliteDb*)cd;
int choice;
int rc = TCL_OK;
- static const char *DB_strs[] = {
+ static const char *const DB_strs[] = {
"authorizer", "backup", "bind_fallback",
"busy", "cache", "changes",
"close", "collate", "collation_needed",
- "commit_hook", "complete", "config",
- "copy", "deserialize", "enable_load_extension",
- "errorcode", "eval", "exists",
- "function", "incrblob", "interrupt",
- "last_insert_rowid", "nullvalue", "onecolumn",
- "preupdate", "profile", "progress",
- "rekey", "restore", "rollback_hook",
- "serialize", "status", "timeout",
- "total_changes", "trace", "trace_v2",
- "transaction", "unlock_notify", "update_hook",
- "version", "wal_hook", 0
+ "commit_hook", "complete", "copy",
+ "deserialize", "enable_load_extension", "errorcode",
+ "eval", "exists", "function",
+ "incrblob", "interrupt", "last_insert_rowid",
+ "nullvalue", "onecolumn", "preupdate",
+ "profile", "progress", "rekey",
+ "restore", "rollback_hook", "serialize",
+ "status", "timeout", "total_changes",
+ "trace", "trace_v2", "transaction",
+ "unlock_notify", "update_hook", "version",
+ "wal_hook", 0
};
enum DB_enum {
DB_AUTHORIZER, DB_BACKUP, DB_BIND_FALLBACK,
DB_BUSY, DB_CACHE, DB_CHANGES,
DB_CLOSE, DB_COLLATE, DB_COLLATION_NEEDED,
- DB_COMMIT_HOOK, DB_COMPLETE, DB_CONFIG,
- DB_COPY, DB_DESERIALIZE, DB_ENABLE_LOAD_EXTENSION,
- DB_ERRORCODE, DB_EVAL, DB_EXISTS,
- DB_FUNCTION, DB_INCRBLOB, DB_INTERRUPT,
- DB_LAST_INSERT_ROWID, DB_NULLVALUE, DB_ONECOLUMN,
- DB_PREUPDATE, DB_PROFILE, DB_PROGRESS,
- DB_REKEY, DB_RESTORE, DB_ROLLBACK_HOOK,
- DB_SERIALIZE, DB_STATUS, DB_TIMEOUT,
- DB_TOTAL_CHANGES, DB_TRACE, DB_TRACE_V2,
- DB_TRANSACTION, DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK,
- DB_VERSION, DB_WAL_HOOK
+ DB_COMMIT_HOOK, DB_COMPLETE, DB_COPY,
+ DB_DESERIALIZE, DB_ENABLE_LOAD_EXTENSION,DB_ERRORCODE,
+ DB_EVAL, DB_EXISTS, DB_FUNCTION,
+ DB_INCRBLOB, DB_INTERRUPT, DB_LAST_INSERT_ROWID,
+ DB_NULLVALUE, DB_ONECOLUMN, DB_PREUPDATE,
+ DB_PROFILE, DB_PROGRESS, DB_REKEY,
+ DB_RESTORE, DB_ROLLBACK_HOOK, DB_SERIALIZE,
+ DB_STATUS, DB_TIMEOUT, DB_TOTAL_CHANGES,
+ DB_TRACE, DB_TRACE_V2, DB_TRANSACTION,
+ DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK, DB_VERSION,
+ DB_WAL_HOOK
};
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
@@ -1956,7 +1999,7 @@ static int SQLITE_TCLAPI DbObjCmd(
Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
return TCL_ERROR;
}
- if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){
+ if( Tcl_GetIndexFromObjStruct(interp, objv[1], DB_strs, sizeof(char *), "option", 0, &choice) ){
return TCL_ERROR;
}
@@ -2163,7 +2206,7 @@ static int SQLITE_TCLAPI DbObjCmd(
Tcl_WrongNumArgs(interp, 1, objv, "cache option ?arg?");
return TCL_ERROR;
}
- subCmd = Tcl_GetStringFromObj( objv[2], 0 );
+ subCmd = Tcl_GetString( objv[2] );
if( *subCmd=='f' && strcmp(subCmd,"flush")==0 ){
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "flush");
@@ -2178,7 +2221,7 @@ static int SQLITE_TCLAPI DbObjCmd(
}else{
if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){
Tcl_AppendResult( interp, "cannot convert \"",
- Tcl_GetStringFromObj(objv[3],0), "\" to integer", (char*)0);
+ Tcl_GetString(objv[3]), "\" to integer", (char*)0);
return TCL_ERROR;
}else{
if( n<0 ){
@@ -2192,7 +2235,7 @@ static int SQLITE_TCLAPI DbObjCmd(
}
}else{
Tcl_AppendResult( interp, "bad option \"",
- Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size",
+ Tcl_GetString(objv[2]), "\": must be flush or size",
(char*)0);
return TCL_ERROR;
}
@@ -2212,7 +2255,7 @@ static int SQLITE_TCLAPI DbObjCmd(
return TCL_ERROR;
}
pResult = Tcl_GetObjResult(interp);
- Tcl_SetIntObj(pResult, sqlite3_changes(pDb->db));
+ Tcl_SetWideIntObj(pResult, sqlite3_changes(pDb->db));
break;
}
@@ -2221,7 +2264,7 @@ static int SQLITE_TCLAPI DbObjCmd(
** Shutdown the database
*/
case DB_CLOSE: {
- Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0));
+ Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
break;
}
@@ -2240,7 +2283,7 @@ static int SQLITE_TCLAPI DbObjCmd(
Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
return TCL_ERROR;
}
- zName = Tcl_GetStringFromObj(objv[2], 0);
+ zName = Tcl_GetString(objv[2]);
zScript = Tcl_GetStringFromObj(objv[3], &nScript);
pCollate = (SqlCollate*)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 );
if( pCollate==0 ) return TCL_ERROR;
@@ -2249,9 +2292,9 @@ static int SQLITE_TCLAPI DbObjCmd(
pCollate->zScript = (char*)&pCollate[1];
pDb->pCollate = pCollate;
memcpy(pCollate->zScript, zScript, nScript+1);
- if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8,
- pCollate, tclSqlCollate) ){
- Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
+ if( sqlite3_create_collation_v2(pDb->db, zName, SQLITE_UTF8,
+ pCollate, tclSqlCollate, 0) ){
+ Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0);
return TCL_ERROR;
}
break;
@@ -2329,81 +2372,13 @@ static int SQLITE_TCLAPI DbObjCmd(
Tcl_WrongNumArgs(interp, 2, objv, "SQL");
return TCL_ERROR;
}
- isComplete = sqlite3_complete( Tcl_GetStringFromObj(objv[2], 0) );
+ isComplete = sqlite3_complete( Tcl_GetString(objv[2]) );
pResult = Tcl_GetObjResult(interp);
- Tcl_SetBooleanObj(pResult, isComplete);
+ Tcl_SetWideIntObj(pResult, isComplete != 0);
#endif
break;
}
- /* $db config ?OPTION? ?BOOLEAN?
- **
- ** Configure the database connection using the sqlite3_db_config()
- ** interface.
- */
- case DB_CONFIG: {
- static const struct DbConfigChoices {
- const char *zName;
- int op;
- } aDbConfig[] = {
- { "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY },
- { "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER },
- { "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW },
- { "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },
- { "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
- { "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE },
- { "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG },
- { "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP },
- { "reset_database", SQLITE_DBCONFIG_RESET_DATABASE },
- { "defensive", SQLITE_DBCONFIG_DEFENSIVE },
- { "writable_schema", SQLITE_DBCONFIG_WRITABLE_SCHEMA },
- { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE },
- { "dqs_dml", SQLITE_DBCONFIG_DQS_DML },
- { "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL },
- };
- Tcl_Obj *pResult;
- int ii;
- if( objc>4 ){
- Tcl_WrongNumArgs(interp, 2, objv, "?OPTION? ?BOOLEAN?");
- return TCL_ERROR;
- }
- if( objc==2 ){
- /* With no arguments, list all configuration options and with the
- ** current value */
- pResult = Tcl_NewListObj(0,0);
- for(ii=0; ii<sizeof(aDbConfig)/sizeof(aDbConfig[0]); ii++){
- int v = 0;
- sqlite3_db_config(pDb->db, aDbConfig[ii].op, -1, &v);
- Tcl_ListObjAppendElement(interp, pResult,
- Tcl_NewStringObj(aDbConfig[ii].zName,-1));
- Tcl_ListObjAppendElement(interp, pResult,
- Tcl_NewIntObj(v));
- }
- }else{
- const char *zOpt = Tcl_GetString(objv[2]);
- int onoff = -1;
- int v = 0;
- if( zOpt[0]=='-' ) zOpt++;
- for(ii=0; ii<sizeof(aDbConfig)/sizeof(aDbConfig[0]); ii++){
- if( strcmp(aDbConfig[ii].zName, zOpt)==0 ) break;
- }
- if( ii>=sizeof(aDbConfig)/sizeof(aDbConfig[0]) ){
- Tcl_AppendResult(interp, "unknown config option: \"", zOpt,
- "\"", (void*)0);
- return TCL_ERROR;
- }
- if( objc==4 ){
- if( Tcl_GetBooleanFromObj(interp, objv[3], &onoff) ){
- return TCL_ERROR;
- }
- }
- sqlite3_db_config(pDb->db, aDbConfig[ii].op, onoff, &v);
- pResult = Tcl_NewIntObj(v);
- }
- Tcl_SetObjResult(interp, pResult);
- break;
- }
-
/* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR?
**
** Copy data into table from filename, optionally using SEPARATOR
@@ -2435,9 +2410,10 @@ static int SQLITE_TCLAPI DbObjCmd(
char *zLine; /* A single line of input from the file */
char **azCol; /* zLine[] broken up into columns */
const char *zCommit; /* How to commit changes */
- FILE *in; /* The input file */
+ Tcl_Channel in; /* The input file */
int lineno = 0; /* Line number of input file */
char zLineNum[80]; /* Line number print buffer */
+ Tcl_DString str;
Tcl_Obj *pResult; /* interp result */
const char *zSep;
@@ -2448,18 +2424,18 @@ static int SQLITE_TCLAPI DbObjCmd(
return TCL_ERROR;
}
if( objc>=6 ){
- zSep = Tcl_GetStringFromObj(objv[5], 0);
+ zSep = Tcl_GetString(objv[5]);
}else{
zSep = "\t";
}
if( objc>=7 ){
- zNull = Tcl_GetStringFromObj(objv[6], 0);
+ zNull = Tcl_GetString(objv[6]);
}else{
zNull = "";
}
- zConflict = Tcl_GetStringFromObj(objv[2], 0);
- zTable = Tcl_GetStringFromObj(objv[3], 0);
- zFile = Tcl_GetStringFromObj(objv[4], 0);
+ zConflict = Tcl_GetString(objv[2]);
+ zTable = Tcl_GetString(objv[3]);
+ zFile = Tcl_GetString(objv[4]);
nSep = strlen30(zSep);
nNull = strlen30(zNull);
if( nSep==0 ){
@@ -2495,7 +2471,7 @@ static int SQLITE_TCLAPI DbObjCmd(
if( nCol==0 ) {
return TCL_ERROR;
}
- zSql = malloc( nByte + 50 + nCol*2 );
+ zSql = sqlite3_malloc( nByte + 50 + nCol*2 );
if( zSql==0 ) {
Tcl_AppendResult(interp, "Error: can't malloc()", (char*)0);
return TCL_ERROR;
@@ -2510,29 +2486,30 @@ static int SQLITE_TCLAPI DbObjCmd(
zSql[j++] = ')';
zSql[j] = 0;
rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0);
- free(zSql);
+ sqlite3_free(zSql);
if( rc ){
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), (char*)0);
sqlite3_finalize(pStmt);
return TCL_ERROR;
}
- in = fopen(zFile, "rb");
+ in = Tcl_OpenFileChannel(interp, zFile, "r", 0666);
if( in==0 ){
- Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, (char*)0);
sqlite3_finalize(pStmt);
return TCL_ERROR;
}
- azCol = malloc( sizeof(azCol[0])*(nCol+1) );
+ azCol = sqlite3_malloc( sizeof(azCol[0])*(nCol+1) );
if( azCol==0 ) {
Tcl_AppendResult(interp, "Error: can't malloc()", (char*)0);
- fclose(in);
+ Tcl_Close(interp, in);
return TCL_ERROR;
}
+ Tcl_DStringInit(&str);
(void)sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0);
zCommit = "COMMIT";
- while( (zLine = local_getline(0, in))!=0 ){
+ while( (size_t)Tcl_Gets(in, &str)!=(size_t)-1 ) {
char *z;
lineno++;
+ zLine = Tcl_DStringValue(&str);
azCol[0] = zLine;
for(i=0, z=zLine; *z; z++){
if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){
@@ -2547,45 +2524,45 @@ static int SQLITE_TCLAPI DbObjCmd(
if( i+1!=nCol ){
char *zErr;
int nErr = strlen30(zFile) + 200;
- zErr = malloc(nErr);
+ zErr = sqlite3_malloc(nErr);
if( zErr ){
sqlite3_snprintf(nErr, zErr,
"Error: %s line %d: expected %d columns of data but found %d",
zFile, lineno, nCol, i+1);
Tcl_AppendResult(interp, zErr, (char*)0);
- free(zErr);
+ sqlite3_free(zErr);
}
zCommit = "ROLLBACK";
break;
}
for(i=0; i<nCol; i++){
/* check for null data, if so, bind as null */
- if( (nNull>0 && strcmp(azCol[i], zNull)==0)
- || strlen30(azCol[i])==0
+ if( (azCol[i][0]==0) || (nNull>0 && strcmp(azCol[i], zNull)==0)
){
sqlite3_bind_null(pStmt, i+1);
}else{
- sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
+ sqlite3_bind_text(pStmt, i+1, azCol[i], strlen30(azCol[i]), SQLITE_STATIC);
}
}
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
- free(zLine);
+ Tcl_DStringSetLength(&str, 0);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), (char*)0);
zCommit = "ROLLBACK";
break;
}
}
- free(azCol);
- fclose(in);
+ Tcl_DStringFree(&str);
+ sqlite3_free(azCol);
+ Tcl_Close(interp, in);
sqlite3_finalize(pStmt);
(void)sqlite3_exec(pDb->db, zCommit, 0, 0, 0);
if( zCommit[0] == 'C' ){
/* success, set result as number of lines processed */
pResult = Tcl_GetObjResult(interp);
- Tcl_SetIntObj(pResult, lineno);
+ Tcl_SetWideIntObj(pResult, lineno);
rc = TCL_OK;
}else{
/* failure, append lineno where failed */
@@ -2645,7 +2622,7 @@ static int SQLITE_TCLAPI DbObjCmd(
}
pValue = objv[objc-1];
pBA = Tcl_GetByteArrayFromObj(pValue, &len);
- pData = sqlite3_malloc64( len );
+ pData = sqlite3_malloc( len );
if( pData==0 && len>0 ){
Tcl_AppendResult(interp, "out of memory", (char*)0);
rc = TCL_ERROR;
@@ -2703,7 +2680,7 @@ deserialize_error:
** call to sqlite3_exec().
*/
case DB_ERRORCODE: {
- Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_errcode(pDb->db)));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_errcode(pDb->db)));
break;
}
@@ -2732,7 +2709,7 @@ deserialize_error:
Tcl_ResetResult(interp);
}
}else if( rc==TCL_BREAK || rc==TCL_OK ){
- pResult = Tcl_NewBooleanObj(rc==TCL_OK);
+ pResult = Tcl_NewWideIntObj(rc==TCL_OK);
}
dbEvalFinalize(&sEval);
if( pResult ) Tcl_SetObjResult(interp, pResult);
@@ -2814,16 +2791,10 @@ deserialize_error:
}
/*
- ** $db function NAME [OPTIONS] SCRIPT
+ ** $db function NAME [-argcount N] [-deterministic] SCRIPT
**
** Create a new SQL function called NAME. Whenever that function is
** called, invoke SCRIPT to evaluate the function.
- **
- ** Options:
- ** --argcount N Function has exactly N arguments
- ** --deterministic The function is pure
- ** --directonly Prohibit use inside triggers and views
- ** --returntype TYPE Specify the return type of the function
*/
case DB_FUNCTION: {
int flags = SQLITE_UTF8;
@@ -2856,11 +2827,8 @@ deserialize_error:
if( n>1 && strncmp(z, "-deterministic",n)==0 ){
flags |= SQLITE_DETERMINISTIC;
}else
- if( n>1 && strncmp(z, "-directonly",n)==0 ){
- flags |= SQLITE_DIRECTONLY;
- }else
if( n>1 && strncmp(z, "-returntype", n)==0 ){
- const char *azType[] = {"integer", "real", "text", "blob", "any", 0};
+ const char *const azType[] = {"integer", "real", "text", "blob", "any", 0};
assert( SQLITE_INTEGER==1 && SQLITE_FLOAT==2 && SQLITE_TEXT==3 );
assert( SQLITE_BLOB==4 && SQLITE_NULL==5 );
if( i==(objc-2) ){
@@ -2868,21 +2836,20 @@ deserialize_error:
return TCL_ERROR;
}
i++;
- if( Tcl_GetIndexFromObj(interp, objv[i], azType, "type", 0, &eType) ){
+ if( Tcl_GetIndexFromObjStruct(interp, objv[i], azType, sizeof(char*), "type", 0, &eType) ){
return TCL_ERROR;
}
eType++;
}else{
Tcl_AppendResult(interp, "bad option \"", z,
- "\": must be -argcount, -deterministic, -directonly,"
- " or -returntype", (char*)0
+ "\": must be -argcount, -deterministic or -returntype", (char*)0
);
return TCL_ERROR;
}
}
pScript = objv[objc-1];
- zName = Tcl_GetStringFromObj(objv[2], 0);
+ zName = Tcl_GetString(objv[2]);
pFunc = findSqlFunc(pDb, zName);
if( pFunc==0 ) return TCL_ERROR;
if( pFunc->pScript ){
@@ -2892,11 +2859,11 @@ deserialize_error:
Tcl_IncrRefCount(pScript);
pFunc->useEvalObjv = safeToUseEvalObjv(interp, pScript);
pFunc->eType = eType;
- rc = sqlite3_create_function(pDb->db, zName, nArg, flags,
- pFunc, tclSqlFunc, 0, 0);
+ rc = sqlite3_create_function_v2(pDb->db, zName, nArg, flags,
+ pFunc, tclSqlFunc, 0, 0, 0);
if( rc!=SQLITE_OK ){
rc = TCL_ERROR;
- Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
+ Tcl_AppendResult(interp, (char *)sqlite3_errmsg(pDb->db), (char*)0);
}
break;
}
@@ -3074,13 +3041,12 @@ deserialize_error:
}else{
pDb->zProfile = 0;
}
-#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \
- !defined(SQLITE_OMIT_DEPRECATED)
+#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
if( pDb->zProfile ){
pDb->interp = interp;
- sqlite3_profile(pDb->db, DbProfileHandler, pDb);
+ sqlite3_trace_v2(pDb->db, SQLITE_TRACE_PROFILE, DbProfileHandler, pDb);
}else{
- sqlite3_profile(pDb->db, 0, 0);
+ sqlite3_trace_v2(pDb->db, 0, 0, 0);
}
#endif
}
@@ -3233,7 +3199,7 @@ deserialize_error:
(char*)0);
return TCL_ERROR;
}
- Tcl_SetObjResult(interp, Tcl_NewIntObj(v));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(v));
break;
}
@@ -3266,7 +3232,7 @@ deserialize_error:
return TCL_ERROR;
}
pResult = Tcl_GetObjResult(interp);
- Tcl_SetIntObj(pResult, sqlite3_total_changes(pDb->db));
+ Tcl_SetWideIntObj(pResult, sqlite3_total_changes(pDb->db));
break;
}
@@ -3297,13 +3263,12 @@ deserialize_error:
}else{
pDb->zTrace = 0;
}
-#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \
- !defined(SQLITE_OMIT_DEPRECATED)
+#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
if( pDb->zTrace ){
pDb->interp = interp;
- sqlite3_trace(pDb->db, DbTraceHandler, pDb);
+ sqlite3_trace_v2(pDb->db, SQLITE_TRACE_STMT, DbTraceHandler, pDb);
}else{
- sqlite3_trace(pDb->db, 0, 0);
+ sqlite3_trace_v2(pDb->db, 0, 0, 0);
}
#endif
}
@@ -3329,7 +3294,7 @@ deserialize_error:
int len;
Tcl_WideInt wMask = 0;
if( objc==4 ){
- static const char *TTYPE_strs[] = {
+ static const char *const TTYPE_strs[] = {
"statement", "profile", "row", "close", 0
};
enum TTYPE_enum {
@@ -3345,7 +3310,7 @@ deserialize_error:
if( TCL_OK!=Tcl_ListObjIndex(interp, objv[3], i, &pObj) ){
return TCL_ERROR;
}
- if( Tcl_GetIndexFromObj(interp, pObj, TTYPE_strs, "trace type",
+ if( Tcl_GetIndexFromObjStruct(interp, pObj, TTYPE_strs, sizeof(char *), "trace type",
0, &ttype)!=TCL_OK ){
Tcl_WideInt wType;
Tcl_Obj *pError = Tcl_DuplicateObj(Tcl_GetObjResult(interp));
@@ -3412,14 +3377,14 @@ deserialize_error:
}
if( pDb->nTransaction==0 && objc==4 ){
- static const char *TTYPE_strs[] = {
+ static const char *const TTYPE_strs[] = {
"deferred", "exclusive", "immediate", 0
};
enum TTYPE_enum {
TTYPE_DEFERRED, TTYPE_EXCLUSIVE, TTYPE_IMMEDIATE
};
int ttype;
- if( Tcl_GetIndexFromObj(interp, objv[2], TTYPE_strs, "transaction type",
+ if( Tcl_GetIndexFromObjStruct(interp, objv[2], TTYPE_strs, sizeof(char *), "transaction type",
0, &ttype) ){
return TCL_ERROR;
}
@@ -3504,7 +3469,7 @@ deserialize_error:
(char*)0);
rc = TCL_ERROR;
#else
- static const char *azSub[] = {"count", "depth", "hook", "new", "old", 0};
+ static const char *const azSub[] = {"count", "depth", "hook", "new", "old", 0};
enum DbPreupdateSubCmd {
PRE_COUNT, PRE_DEPTH, PRE_HOOK, PRE_NEW, PRE_OLD
};
@@ -3513,14 +3478,14 @@ deserialize_error:
if( objc<3 ){
Tcl_WrongNumArgs(interp, 2, objv, "SUB-COMMAND ?ARGS?");
}
- if( Tcl_GetIndexFromObj(interp, objv[2], azSub, "sub-command", 0, &iSub) ){
+ if( Tcl_GetIndexFromObjStruct(interp, objv[2], azSub, sizeof(char *), "sub-command", 0, &iSub) ){
return TCL_ERROR;
}
switch( (enum DbPreupdateSubCmd)iSub ){
case PRE_COUNT: {
int nCol = sqlite3_preupdate_count(pDb->db);
- Tcl_SetObjResult(interp, Tcl_NewIntObj(nCol));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(nCol));
break;
}
@@ -3539,7 +3504,7 @@ deserialize_error:
Tcl_WrongNumArgs(interp, 3, objv, "");
return TCL_ERROR;
}
- pRet = Tcl_NewIntObj(sqlite3_preupdate_depth(pDb->db));
+ pRet = Tcl_NewWideIntObj(sqlite3_preupdate_depth(pDb->db));
Tcl_SetObjResult(interp, pRet);
break;
}
@@ -3631,7 +3596,7 @@ deserialize_error:
char zBuf[100];
sqlite3_snprintf(sizeof(zBuf), zBuf, "%p",
pDb->stmtList ? pDb->stmtList->pStmt: 0);
- Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
+ Tcl_AppendResult(interp, zBuf, (char*)0);
}else
#endif /* SQLITE_TEST */
{
@@ -3640,7 +3605,7 @@ deserialize_error:
}
}
if( i==2 ){
- Tcl_SetResult(interp, (char *)sqlite3_libversion(), TCL_STATIC);
+ Tcl_AppendResult(interp, sqlite3_libversion(), (char*)0);
}
break;
}
@@ -3732,7 +3697,7 @@ static int SQLITE_TCLAPI DbMain(
if( objc==1 ) return sqliteCmdUsage(interp, objv);
if( objc==2 ){
- zArg = Tcl_GetStringFromObj(objv[1], 0);
+ zArg = Tcl_GetString(objv[1]);
if( strcmp(zArg,"-version")==0 ){
Tcl_AppendResult(interp,sqlite3_libversion(), (char*)0);
return TCL_OK;
@@ -3837,7 +3802,7 @@ static int SQLITE_TCLAPI DbMain(
}
#endif
if( p->db==0 ){
- Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
+ Tcl_AppendResult(interp, zErrMsg, (char*)0);
Tcl_Free((char*)p);
sqlite3_free(zErrMsg);
return TCL_ERROR;
@@ -3845,7 +3810,7 @@ static int SQLITE_TCLAPI DbMain(
p->maxStmt = NUM_PREPARED_STMTS;
p->openFlags = flags & SQLITE_OPEN_URI;
p->interp = interp;
- zArg = Tcl_GetStringFromObj(objv[1], 0);
+ zArg = Tcl_GetString(objv[1]);
if( DbUseNre() ){
Tcl_NRCreateCommand(interp, zArg, DbObjCmdAdaptor, DbObjCmd,
(char*)p, DbDeleteCmd);
@@ -3859,9 +3824,26 @@ static int SQLITE_TCLAPI DbMain(
** Provide a dummy Tcl_InitStubs if we are using this as a static
** library.
*/
+#undef Tcl_InitStubs
#ifndef USE_TCL_STUBS
-# undef Tcl_InitStubs
# define Tcl_InitStubs(a,b,c) TCL_VERSION
+#else
+# define Tcl_InitStubs staticTclInitStubs
+typedef struct {
+ char *result;
+ Tcl_FreeProc *freeProc;
+ int errorLine;
+ const struct TclStubs *stubTable;
+} PrivateTclInterp;
+static const char *Tcl_InitStubs(Tcl_Interp *interp, const char *version, int exact) {
+ tclStubsPtr = ((PrivateTclInterp *)interp)->stubTable;
+ if (tclStubsPtr->magic != TCL_STUB_MAGIC) {
+ ((PrivateTclInterp *)interp)->result = (char *)"interpreter uses an incompatible stubs mechanism";
+ ((PrivateTclInterp *)interp)->freeProc = 0; /* TCL_STATIC */
+ return NULL;
+ }
+ return Tcl_PkgRequireEx(interp, "Tcl", version, 0, (void *)&tclStubsPtr);
+}
#endif
/*
@@ -3882,10 +3864,13 @@ static int SQLITE_TCLAPI DbMain(
** used to open a new SQLite database. See the DbMain() routine above
** for additional information.
**
-** The EXTERN macros are required by TCL in order to work on windows.
+** The DLLEXPORT macros are required by TCL in order to work on windows.
*/
-EXTERN int Sqlite3_Init(Tcl_Interp *interp){
- int rc = Tcl_InitStubs(interp, "8.4", 0) ? TCL_OK : TCL_ERROR;
+DLLEXPORT int Sqlite3_Init(Tcl_Interp *interp){
+ int rc = Tcl_InitStubs(interp, "8.5-", 0) ? TCL_OK : TCL_ERROR;
+ if( rc!=TCL_OK ){
+ rc = Tcl_InitStubs(interp, "8.4", 0) ? TCL_OK : TCL_ERROR;
+ }
if( rc==TCL_OK ){
Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0);
#ifndef SQLITE_3_SUFFIX_ONLY
@@ -3894,20 +3879,20 @@ EXTERN int Sqlite3_Init(Tcl_Interp *inte
** command. */
Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
#endif
- rc = Tcl_PkgProvide(interp, "sqlite3", PACKAGE_VERSION);
+ rc = Tcl_PkgProvideEx(interp, "sqlite3", PACKAGE_VERSION, NULL);
}
return rc;
}
-EXTERN int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
-EXTERN int Sqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
-EXTERN int Tclsqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
+DLLEXPORT int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
+DLLEXPORT int Sqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
+DLLEXPORT int Tclsqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
/* Because it accesses the file-system and uses persistent state, SQLite
** is not considered appropriate for safe interpreters. Hence, we cause
** the _SafeInit() interfaces return TCL_ERROR.
*/
-EXTERN int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_ERROR; }
-EXTERN int Sqlite3_SafeUnload(Tcl_Interp *interp, int flags){return TCL_ERROR;}
+DLLEXPORT int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_ERROR; }
+DLLEXPORT int Sqlite3_SafeUnload(Tcl_Interp *interp, int flags){return TCL_ERROR;}
@@ -3992,16 +3977,16 @@ int SQLITE_CDECL TCLSH_MAIN(int argc, ch
sqlite3_shutdown();
Tcl_FindExecutable(argv[0]);
- Tcl_SetSystemEncoding(NULL, "utf-8");
+ Tcl_SetSystemEncoding(0, "utf-8");
interp = Tcl_CreateInterp();
Sqlite3_Init(interp);
sqlite3_snprintf(sizeof(zArgc), zArgc, "%d", argc-1);
- Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY);
- Tcl_SetVar(interp,"argv0",argv[0],TCL_GLOBAL_ONLY);
- Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
+ Tcl_SetVar2(interp,"argc", NULL, zArgc, TCL_GLOBAL_ONLY);
+ Tcl_SetVar2(interp,"argv0", NULL, argv[0],TCL_GLOBAL_ONLY);
+ Tcl_SetVar2(interp,"argv", NULL, "", TCL_GLOBAL_ONLY);
for(i=1; i<argc; i++){
- Tcl_SetVar(interp, "argv", argv[i],
+ Tcl_SetVar2(interp, "argv", NULL, argv[i],
TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
}
#if defined(TCLSH_INIT_PROC)
@@ -4010,8 +3995,8 @@ int SQLITE_CDECL TCLSH_MAIN(int argc, ch
if( zScript==0 ){
zScript = tclsh_main_loop();
}
- if( Tcl_GlobalEval(interp, zScript)!=TCL_OK ){
- const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
+ if( Tcl_EvalEx(interp, zScript, -1, TCL_EVAL_GLOBAL)!=TCL_OK ){
+ const char *zInfo = Tcl_GetVar2(interp, "errorInfo", NULL, TCL_GLOBAL_ONLY);
if( zInfo==0 ) zInfo = Tcl_GetStringResult(interp);
fprintf(stderr,"%s: %s\n", *argv, zInfo);
return 1;
--- origsrc/sqlite-autoconf-3300000/tea/tclconfig/tcl.m4 2019-10-04 18:28:13.000000000 +0200
+++ src/sqlite-autoconf-3300000/tea/tclconfig/tcl.m4 2019-03-05 13:14:41.089000000 +0100
@@ -11,14 +11,11 @@
AC_PREREQ(2.57)
-dnl TEA extensions pass us the version of TEA they think they
-dnl are compatible with (must be set in TEA_INIT below)
-dnl TEA_VERSION="3.9"
-
# Possible values for key variables defined:
#
# TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem')
# TEA_PLATFORM - windows unix
+# TEA_TK_EXTENSION - True if this is a Tk extension
#
#------------------------------------------------------------------------
@@ -108,6 +105,9 @@ AC_DEFUN([TEA_PATH_TCLCONFIG], [
`ls -d /Library/Frameworks 2>/dev/null` \
`ls -d /Network/Library/Frameworks 2>/dev/null` \
`ls -d /System/Library/Frameworks 2>/dev/null` \
+ `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks/Tcl.framework 2>/dev/null` \
+ `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Network/Library/Frameworks/Tcl.framework 2>/dev/null` \
+ `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Tcl.framework 2>/dev/null` \
; do
if test -f "$i/Tcl.framework/tclConfig.sh" ; then
ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`"
@@ -136,10 +136,15 @@ AC_DEFUN([TEA_PATH_TCLCONFIG], [
`ls -d ${prefix}/lib 2>/dev/null` \
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
+ `ls -d /usr/pkg/lib 2>/dev/null` \
`ls -d /usr/lib 2>/dev/null` \
`ls -d /usr/lib64 2>/dev/null` \
`ls -d /usr/lib/tcl8.6 2>/dev/null` \
`ls -d /usr/lib/tcl8.5 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl8.6 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl8.5 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl/tcl8.6 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl/tcl8.5 2>/dev/null` \
; do
if test -f "$i/tclConfig.sh" ; then
ac_cv_c_tclconfig="`(cd $i; pwd)`"
@@ -263,6 +268,9 @@ AC_DEFUN([TEA_PATH_TKCONFIG], [
`ls -d /Library/Frameworks 2>/dev/null` \
`ls -d /Network/Library/Frameworks 2>/dev/null` \
`ls -d /System/Library/Frameworks 2>/dev/null` \
+ `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks/Tcl.framework 2>/dev/null` \
+ `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Network/Library/Frameworks/Tcl.framework 2>/dev/null` \
+ `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Tcl.framework 2>/dev/null` \
; do
if test -f "$i/Tk.framework/tkConfig.sh" ; then
ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`"
@@ -278,8 +286,15 @@ AC_DEFUN([TEA_PATH_TKCONFIG], [
`ls -d ${prefix}/lib 2>/dev/null` \
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
+ `ls -d /usr/pkg/lib 2>/dev/null` \
`ls -d /usr/lib 2>/dev/null` \
`ls -d /usr/lib64 2>/dev/null` \
+ `ls -d /usr/lib/tk8.6 2>/dev/null` \
+ `ls -d /usr/lib/tk8.5 2>/dev/null` \
+ `ls -d /usr/local/lib/tk8.6 2>/dev/null` \
+ `ls -d /usr/local/lib/tk8.5 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl/tk8.6 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl/tk8.5 2>/dev/null` \
; do
if test -f "$i/tkConfig.sh" ; then
ac_cv_c_tkconfig="`(cd $i; pwd)`"
@@ -348,6 +363,8 @@ AC_DEFUN([TEA_PATH_TKCONFIG], [
# TCL_BIN_DIR
# TCL_SRC_DIR
# TCL_LIB_FILE
+# TCL_ZIP_FILE
+# TCL_ZIPFS_SUPPORT
#------------------------------------------------------------------------
AC_DEFUN([TEA_LOAD_TCLCONFIG], [
@@ -422,8 +439,13 @@ AC_DEFUN([TEA_LOAD_TCLCONFIG], [
#ifdef _WIN32
#error win32
#endif
- ], TEA_PLATFORM="unix",
+ ], [
+ # first test we've already retrieved platform (cross-compile), fallback to unix otherwise:
+ TEA_PLATFORM="${TEA_PLATFORM-unix}"
+ CYGPATH=echo
+ ], [
TEA_PLATFORM="windows"
+ AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo) ]
)
CC=$hold_cc
AC_MSG_RESULT($TEA_PLATFORM)
@@ -572,7 +594,15 @@ AC_DEFUN([TEA_PROG_TCLSH], [
if test -f "${TCL_BIN_DIR}/Makefile" ; then
# tclConfig.sh is in Tcl build directory
if test "${TEA_PLATFORM}" = "windows"; then
+ if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" ; then
TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}"
+ elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" ; then
+ TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}"
+ elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" ; then
+ TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}"
+ elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" ; then
+ TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}"
+ fi
else
TCLSH_PROG="${TCL_BIN_DIR}/tclsh"
fi
@@ -622,7 +652,15 @@ AC_DEFUN([TEA_PROG_WISH], [
if test -f "${TK_BIN_DIR}/Makefile" ; then
# tkConfig.sh is in Tk build directory
if test "${TEA_PLATFORM}" = "windows"; then
+ if test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" ; then
WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}"
+ elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}s${EXEEXT}" ; then
+ WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}$s{EXEEXT}"
+ elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}t${EXEEXT}" ; then
+ WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}t${EXEEXT}"
+ elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}st${EXEEXT}" ; then
+ WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}st${EXEEXT}"
+ fi
else
WISH_PROG="${TK_BIN_DIR}/wish"
fi
@@ -660,6 +698,7 @@ AC_DEFUN([TEA_PROG_WISH], [
#
# Adds the following arguments to configure:
# --enable-shared=yes|no
+# --enable-stubs=yes|no
#
# Defines the following vars:
# STATIC_BUILD Used for building import/export libraries
@@ -667,31 +706,63 @@ AC_DEFUN([TEA_PROG_WISH], [
#
# Sets the following vars:
# SHARED_BUILD Value of 1 or 0
+# STUBS_BUILD Value if 1 or 0
+# USE_TCL_STUBS Value true: if SHARED_BUILD or --enable-stubs
+# USE_TCLOO_STUBS Value true: if SHARED_BUILD or --enable-stubs
+# USE_TK_STUBS Value true: if SHARED_BUILD or --enable-stubs
+# AND TEA_WINDOWING_SYSTEM != ""
#------------------------------------------------------------------------
-
AC_DEFUN([TEA_ENABLE_SHARED], [
AC_MSG_CHECKING([how to build libraries])
AC_ARG_ENABLE(shared,
AC_HELP_STRING([--enable-shared],
[build and link with shared libraries (default: on)]),
- [tcl_ok=$enableval], [tcl_ok=yes])
+ [shared_ok=$enableval], [shared_ok=yes])
if test "${enable_shared+set}" = set; then
enableval="$enable_shared"
- tcl_ok=$enableval
+ shared_ok=$enableval
else
- tcl_ok=yes
+ shared_ok=yes
+ fi
+
+ AC_ARG_ENABLE(stubs,
+ AC_HELP_STRING([--enable-stubs],
+ [build and link with stub libraries. Always true for shared builds (default: on)]),
+ [stubs_ok=$enableval], [stubs_ok=yes])
+
+ if test "${enable_stubs+set}" = set; then
+ enableval="$enable_stubs"
+ stubs_ok=$enableval
+ else
+ stubs_ok=yes
fi
- if test "$tcl_ok" = "yes" ; then
+ # Stubs are always enabled for shared builds
+ if test "$shared_ok" = "yes" ; then
AC_MSG_RESULT([shared])
SHARED_BUILD=1
+ STUBS_BUILD=1
else
AC_MSG_RESULT([static])
SHARED_BUILD=0
- AC_DEFINE(STATIC_BUILD, 1, [Is this a static build?])
+ AC_DEFINE(STATIC_BUILD, 1, [This a static build])
+ if test "$stubs_ok" = "yes" ; then
+ STUBS_BUILD=1
+ else
+ STUBS_BUILD=0
+ fi
fi
+ if test "${STUBS_BUILD}" = "1" ; then
+ AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs])
+ AC_DEFINE(USE_TCLOO_STUBS, 1, [Use TclOO stubs])
+ if test "${TEA_WINDOWINGSYSTEM}" != ""; then
+ AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs])
+ fi
+ fi
+
AC_SUBST(SHARED_BUILD)
+ AC_SUBST(STUBS_BUILD)
])
#------------------------------------------------------------------------
@@ -729,7 +800,7 @@ AC_DEFUN([TEA_ENABLE_SHARED], [
AC_DEFUN([TEA_ENABLE_THREADS], [
AC_ARG_ENABLE(threads,
AC_HELP_STRING([--enable-threads],
- [build with threads]),
+ [build with threads (default: on)]),
[tcl_ok=$enableval], [tcl_ok=yes])
if test "${enable_threads+set}" = set; then
@@ -813,14 +884,6 @@ AC_DEFUN([TEA_ENABLE_THREADS], [
that IS thread-enabled. It is recommended to use --enable-threads.])
fi
;;
- *)
- if test "${TCL_THREADS}" = "1"; then
- AC_MSG_WARN([
- --enable-threads requested, but building against a Tcl that is NOT
- thread-enabled. This is an OK configuration that will also run in
- a thread-enabled core.])
- fi
- ;;
esac
AC_SUBST(TCL_THREADS)
])
@@ -1086,17 +1149,6 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
[doRpath=$enableval], [doRpath=yes])
AC_MSG_RESULT([$doRpath])
- # TEA specific: Cross-compiling options for Windows/CE builds?
-
- AS_IF([test "${TEA_PLATFORM}" = windows], [
- AC_MSG_CHECKING([if Windows/CE build is requested])
- AC_ARG_ENABLE(wince,
- AC_HELP_STRING([--enable-wince],
- [enable Win/CE support (where applicable)]),
- [doWince=$enableval], [doWince=no])
- AC_MSG_RESULT([$doWince])
- ])
-
# Set the variable "system" to hold the name and version number
# for the system.
@@ -1133,7 +1185,7 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
AC_CHECK_TOOL(AR, ar)
STLIB_LD='${AR} cr'
LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH"
- AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION="1.0"])
+ AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION=""],[SHLIB_VERSION=".$SHLIB_VERSION"])
case $system in
# TEA specific:
windows)
@@ -1169,113 +1221,36 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
fi
fi
- if test "$doWince" != "no" ; then
- if test "$do64bit" != "no" ; then
- AC_MSG_ERROR([Windows/CE and 64-bit builds incompatible])
- fi
- if test "$GCC" = "yes" ; then
- AC_MSG_ERROR([Windows/CE and GCC builds incompatible])
- fi
- TEA_PATH_CELIB
- # Set defaults for common evc4/PPC2003 setup
- # Currently Tcl requires 300+, possibly 420+ for sockets
- CEVERSION=420; # could be 211 300 301 400 420 ...
- TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ...
- ARCH=ARM; # could be ARM MIPS X86EM ...
- PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002"
- if test "$doWince" != "yes"; then
- # If !yes then the user specified something
- # Reset ARCH to allow user to skip specifying it
- ARCH=
- eval `echo $doWince | awk -F, '{ \
- if (length([$]1)) { printf "CEVERSION=\"%s\"\n", [$]1; \
- if ([$]1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \
- if (length([$]2)) { printf "TARGETCPU=\"%s\"\n", toupper([$]2) }; \
- if (length([$]3)) { printf "ARCH=\"%s\"\n", toupper([$]3) }; \
- if (length([$]4)) { printf "PLATFORM=\"%s\"\n", [$]4 }; \
- }'`
- if test "x${ARCH}" = "x" ; then
- ARCH=$TARGETCPU;
- fi
- fi
- OSVERSION=WCE$CEVERSION;
- if test "x${WCEROOT}" = "x" ; then
- WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0"
- if test ! -d "${WCEROOT}" ; then
- WCEROOT="C:/Program Files/Microsoft eMbedded Tools"
- fi
- fi
- if test "x${SDKROOT}" = "x" ; then
- SDKROOT="C:/Program Files/Windows CE Tools"
- if test ! -d "${SDKROOT}" ; then
- SDKROOT="C:/Windows CE Tools"
- fi
- fi
- WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'`
- SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'`
- if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \
- -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then
- AC_MSG_ERROR([could not find PocketPC SDK or target compiler to enable WinCE mode [$CEVERSION,$TARGETCPU,$ARCH,$PLATFORM]])
- doWince="no"
- else
- # We could PATH_NOSPACE these, but that's not important,
- # as long as we quote them when used.
- CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include"
- if test -d "${CEINCLUDE}/${TARGETCPU}" ; then
- CEINCLUDE="${CEINCLUDE}/${TARGETCPU}"
- fi
- CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}"
- fi
- fi
-
if test "$GCC" != "yes" ; then
if test "${SHARED_BUILD}" = "0" ; then
runtime=-MT
else
runtime=-MD
fi
+ case "x`echo \${VisualStudioVersion}`" in
+ x1[[4-9]]*)
+ lflags="${lflags} -nodefaultlib:libucrt.lib"
+ TEA_ADD_LIBS([ucrt.lib])
+ ;;
+ *)
+ ;;
+ esac
if test "$do64bit" != "no" ; then
# All this magic is necessary for the Win64 SDK RC1 - hobbs
CC="\"${PATH64}/cl.exe\""
CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\""
RC="\"${MSSDK}/bin/rc.exe\""
- lflags="-nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\""
+ lflags="${lflags} -nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\""
LINKBIN="\"${PATH64}/link.exe\""
CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d"
CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}"
# Avoid 'unresolved external symbol __security_cookie'
# errors, c.f. http://support.microsoft.com/?id=894573
TEA_ADD_LIBS([bufferoverflowU.lib])
- elif test "$doWince" != "no" ; then
- CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin"
- if test "${TARGETCPU}" = "X86"; then
- CC="\"${CEBINROOT}/cl.exe\""
- else
- CC="\"${CEBINROOT}/cl${ARCH}.exe\""
- fi
- CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\""
- RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\""
- arch=`echo ${ARCH} | awk '{print tolower([$]0)}'`
- defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS"
- if test "${SHARED_BUILD}" = "1" ; then
- # Static CE builds require static celib as well
- defs="${defs} _DLL"
- fi
- for i in $defs ; do
- AC_DEFINE_UNQUOTED($i, 1, [WinCE def ]$i)
- done
- AC_DEFINE_UNQUOTED(_WIN32_WCE, $CEVERSION, [_WIN32_WCE version])
- AC_DEFINE_UNQUOTED(UNDER_CE, $CEVERSION, [UNDER_CE version])
- CFLAGS_DEBUG="-nologo -Zi -Od"
- CFLAGS_OPTIMIZE="-nologo -Ox"
- lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'`
- lflags="-MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo"
- LINKBIN="\"${CEBINROOT}/link.exe\""
- AC_SUBST(CELIB_DIR)
else
RC="rc"
- lflags="-nologo"
+ lflags="${lflags} -nologo"
LINKBIN="link"
CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d"
CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}"
@@ -1334,13 +1309,8 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
# This essentially turns it all on.
LDFLAGS_DEBUG="-debug -debugtype:cv"
LDFLAGS_OPTIMIZE="-release"
- if test "$doWince" != "no" ; then
- LDFLAGS_CONSOLE="-link ${lflags}"
- LDFLAGS_WINDOW=${LDFLAGS_CONSOLE}
- else
- LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}"
- LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}"
- fi
+ LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}"
+ LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}"
fi
SHLIB_SUFFIX=".dll"
@@ -1426,6 +1396,7 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
CYGWIN_*)
SHLIB_CFLAGS=""
SHLIB_LD='${CC} -shared'
+ SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,--out-implib,\$[@].a"
SHLIB_SUFFIX=".dll"
EXEEXT=".exe"
do64bit_ok=yes
@@ -1436,7 +1407,7 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
SHLIB_CFLAGS="-fPIC"
SHLIB_SUFFIX=".so"
- SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}'
+ SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared'
AC_CHECK_LIB(network, inet_ntoa, [LIBS="$LIBS -lnetwork"])
;;
HP-UX-*.11.*)
@@ -1547,7 +1518,7 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer"
# TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS
- SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}'
+ SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS_DEFAULT} -shared'
LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
AS_IF([test $doRpath = yes], [
CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
@@ -1586,30 +1557,21 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
OpenBSD-*)
arch=`arch -s`
case "$arch" in
- vax)
- SHLIB_SUFFIX=""
- SHARED_LIB_SUFFIX=""
- LDFLAGS=""
- ;;
- *)
+ alpha|sparc64)
SHLIB_CFLAGS="-fPIC"
- SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}'
- SHLIB_SUFFIX=".so"
- AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}'
- LDFLAGS="-Wl,-export-dynamic"
- ;;
- esac
- case "$arch" in
- vax)
- CFLAGS_OPTIMIZE="-O1"
;;
*)
- CFLAGS_OPTIMIZE="-O2"
+ SHLIB_CFLAGS="-fpic"
;;
esac
+ SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
+ SHLIB_SUFFIX=".so"
+ AS_IF([test $doRpath = yes], [
+ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
+ LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
+ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}'
+ LDFLAGS="-Wl,-export-dynamic"
+ CFLAGS_OPTIMIZE="-O2"
AS_IF([test "${TCL_THREADS}" = "1"], [
# On OpenBSD: Compile with -pthread
# Don't link with -lpthread
@@ -1623,7 +1585,7 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
NetBSD-*)
# NetBSD has ELF and can use 'cc -shared' to build shared libs
SHLIB_CFLAGS="-fPIC"
- SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}'
+ SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
SHLIB_SUFFIX=".so"
LDFLAGS="$LDFLAGS -export-dynamic"
AS_IF([test $doRpath = yes], [
@@ -1636,12 +1598,11 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
LDFLAGS="$LDFLAGS -pthread"
])
;;
- FreeBSD-*)
+ DragonFly-*|FreeBSD-*)
# This configuration from FreeBSD Ports.
SHLIB_CFLAGS="-fPIC"
SHLIB_LD="${CC} -shared"
- TCL_SHLIB_LD_EXTRAS="-Wl,-soname=\$[@]"
- TK_SHLIB_LD_EXTRAS="-Wl,-soname,\$[@]"
+ SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,-soname,\$[@]"
SHLIB_SUFFIX=".so"
LDFLAGS=""
AS_IF([test $doRpath = yes], [
@@ -1655,9 +1616,9 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
case $system in
FreeBSD-3.*)
# Version numbers are dot-stripped by system policy.
- TCL_TRIM_DOTS=`echo ${VERSION} | tr -d .`
+ TCL_TRIM_DOTS=`echo ${PACKAGE_VERSION} | tr -d .`
UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
- SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so'
+ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1'
TCL_LIB_VERSIONS_OK=nodots
;;
esac
@@ -1723,10 +1684,6 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d`
SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}"
SHLIB_SUFFIX=".dylib"
- # Don't use -prebind when building for Mac OS X 10.4 or later only:
- AS_IF([test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int([$]2)}'`" -lt 4 -a \
- "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int([$]2)}'`" -lt 4], [
- LDFLAGS="$LDFLAGS -prebind"])
LDFLAGS="$LDFLAGS -headerpad_max_install_names"
AC_CACHE_CHECK([if ld accepts -search_paths_first flag],
tcl_cv_ld_search_paths_first, [
@@ -1997,9 +1954,9 @@ dnl # preprocessing tests use only CPPFL
case $system in
AIX-*) ;;
BSD/OS*) ;;
- CYGWIN_*|MINGW32_*) ;;
+ CYGWIN_*|MINGW32_*|MINGW64_*) ;;
IRIX*) ;;
- NetBSD-*|FreeBSD-*|OpenBSD-*) ;;
+ NetBSD-*|DragonFly-*|FreeBSD-*|OpenBSD-*) ;;
Darwin-*) ;;
SCO_SV-3.2*) ;;
windows) ;;
@@ -2013,10 +1970,10 @@ dnl # preprocessing tests use only CPPFL
AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [
# TEA specific: use PACKAGE_VERSION instead of VERSION
- SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}'])
+ SHARED_LIB_SUFFIX='3${SHLIB_SUFFIX}'])
AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [
# TEA specific: use PACKAGE_VERSION instead of VERSION
- UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a'])
+ UNSHARED_LIB_SUFFIX='3.a'])
if test "${GCC}" = "yes" -a ${SHLIB_SUFFIX} = ".dll"; then
AC_CACHE_CHECK(for SEH support in compiler,
@@ -2249,97 +2206,6 @@ int main() {
])
#--------------------------------------------------------------------
-# TEA_MISSING_POSIX_HEADERS
-#
-# Supply substitutes for missing POSIX header files. Special
-# notes:
-# - stdlib.h doesn't define strtol, strtoul, or
-# strtod in some versions of SunOS
-# - some versions of string.h don't declare procedures such
-# as strstr
-#
-# Arguments:
-# none
-#
-# Results:
-#
-# Defines some of the following vars:
-# NO_DIRENT_H
-# NO_ERRNO_H
-# NO_VALUES_H
-# HAVE_LIMITS_H or NO_LIMITS_H
-# NO_STDLIB_H
-# NO_STRING_H
-# NO_SYS_WAIT_H
-# NO_DLFCN_H
-# HAVE_SYS_PARAM_H
-#
-# HAVE_STRING_H ?
-#
-# tkUnixPort.h checks for HAVE_LIMITS_H, so do both HAVE and
-# CHECK on limits.h
-#--------------------------------------------------------------------
-
-AC_DEFUN([TEA_MISSING_POSIX_HEADERS], [
- AC_CACHE_CHECK([dirent.h], tcl_cv_dirent_h, [
- AC_TRY_LINK([#include <sys/types.h>
-#include <dirent.h>], [
-#ifndef _POSIX_SOURCE
-# ifdef __Lynx__
- /*
- * Generate compilation error to make the test fail: Lynx headers
- * are only valid if really in the POSIX environment.
- */
-
- missing_procedure();
-# endif
-#endif
-DIR *d;
-struct dirent *entryPtr;
-char *p;
-d = opendir("foobar");
-entryPtr = readdir(d);
-p = entryPtr->d_name;
-closedir(d);
-], tcl_cv_dirent_h=yes, tcl_cv_dirent_h=no)])
-
- if test $tcl_cv_dirent_h = no; then
- AC_DEFINE(NO_DIRENT_H, 1, [Do we have <dirent.h>?])
- fi
-
- # TEA specific:
- AC_CHECK_HEADER(errno.h, , [AC_DEFINE(NO_ERRNO_H, 1, [Do we have <errno.h>?])])
- AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H, 1, [Do we have <float.h>?])])
- AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H, 1, [Do we have <values.h>?])])
- AC_CHECK_HEADER(limits.h,
- [AC_DEFINE(HAVE_LIMITS_H, 1, [Do we have <limits.h>?])],
- [AC_DEFINE(NO_LIMITS_H, 1, [Do we have <limits.h>?])])
- AC_CHECK_HEADER(stdlib.h, tcl_ok=1, tcl_ok=0)
- AC_EGREP_HEADER(strtol, stdlib.h, , tcl_ok=0)
- AC_EGREP_HEADER(strtoul, stdlib.h, , tcl_ok=0)
- AC_EGREP_HEADER(strtod, stdlib.h, , tcl_ok=0)
- if test $tcl_ok = 0; then
- AC_DEFINE(NO_STDLIB_H, 1, [Do we have <stdlib.h>?])
- fi
- AC_CHECK_HEADER(string.h, tcl_ok=1, tcl_ok=0)
- AC_EGREP_HEADER(strstr, string.h, , tcl_ok=0)
- AC_EGREP_HEADER(strerror, string.h, , tcl_ok=0)
-
- # See also memmove check below for a place where NO_STRING_H can be
- # set and why.
-
- if test $tcl_ok = 0; then
- AC_DEFINE(NO_STRING_H, 1, [Do we have <string.h>?])
- fi
-
- AC_CHECK_HEADER(sys/wait.h, , [AC_DEFINE(NO_SYS_WAIT_H, 1, [Do we have <sys/wait.h>?])])
- AC_CHECK_HEADER(dlfcn.h, , [AC_DEFINE(NO_DLFCN_H, 1, [Do we have <dlfcn.h>?])])
-
- # OS/390 lacks sys/param.h (and doesn't need it, by chance).
- AC_HAVE_HEADERS(sys/param.h)
-])
-
-#--------------------------------------------------------------------
# TEA_PATH_X
#
# Locate the X11 header files and the X11 library archive. Try
@@ -2594,92 +2460,6 @@ AC_DEFUN([TEA_BUGGY_STRTOD], [
])
#--------------------------------------------------------------------
-# TEA_TCL_LINK_LIBS
-#
-# Search for the libraries needed to link the Tcl shell.
-# Things like the math library (-lm) and socket stuff (-lsocket vs.
-# -lnsl) are dealt with here.
-#
-# Arguments:
-# Requires the following vars to be set in the Makefile:
-# DL_LIBS (not in TEA, only needed in core)
-# LIBS
-# MATH_LIBS
-#
-# Results:
-#
-# Substitutes the following vars:
-# TCL_LIBS
-# MATH_LIBS
-#
-# Might append to the following vars:
-# LIBS
-#
-# Might define the following vars:
-# HAVE_NET_ERRNO_H
-#--------------------------------------------------------------------
-
-AC_DEFUN([TEA_TCL_LINK_LIBS], [
- #--------------------------------------------------------------------
- # On a few very rare systems, all of the libm.a stuff is
- # already in libc.a. Set compiler flags accordingly.
- # Also, Linux requires the "ieee" library for math to work
- # right (and it must appear before "-lm").
- #--------------------------------------------------------------------
-
- AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm")
- AC_CHECK_LIB(ieee, main, [MATH_LIBS="-lieee $MATH_LIBS"])
-
- #--------------------------------------------------------------------
- # Interactive UNIX requires -linet instead of -lsocket, plus it
- # needs net/errno.h to define the socket-related error codes.
- #--------------------------------------------------------------------
-
- AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"])
- AC_CHECK_HEADER(net/errno.h, [
- AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have <net/errno.h>?])])
-
- #--------------------------------------------------------------------
- # Check for the existence of the -lsocket and -lnsl libraries.
- # The order here is important, so that they end up in the right
- # order in the command line generated by make. Here are some
- # special considerations:
- # 1. Use "connect" and "accept" to check for -lsocket, and
- # "gethostbyname" to check for -lnsl.
- # 2. Use each function name only once: can't redo a check because
- # autoconf caches the results of the last check and won't redo it.
- # 3. Use -lnsl and -lsocket only if they supply procedures that
- # aren't already present in the normal libraries. This is because
- # IRIX 5.2 has libraries, but they aren't needed and they're
- # bogus: they goof up name resolution if used.
- # 4. On some SVR4 systems, can't use -lsocket without -lnsl too.
- # To get around this problem, check for both libraries together
- # if -lsocket doesn't work by itself.
- #--------------------------------------------------------------------
-
- tcl_checkBoth=0
- AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1)
- if test "$tcl_checkSocket" = 1; then
- AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt,
- LIBS="$LIBS -lsocket", tcl_checkBoth=1)])
- fi
- if test "$tcl_checkBoth" = 1; then
- tk_oldLibs=$LIBS
- LIBS="$LIBS -lsocket -lnsl"
- AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs])
- fi
- AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname,
- [LIBS="$LIBS -lnsl"])])
-
- # TEA specific: Don't perform the eval of the libraries here because
- # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS
-
- TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}'
- AC_SUBST(TCL_LIBS)
- AC_SUBST(MATH_LIBS)
-])
-
-#--------------------------------------------------------------------
# TEA_TCL_EARLY_FLAGS
#
# Check for what flags are needed to be passed so the correct OS
@@ -2840,23 +2620,14 @@ AC_DEFUN([TEA_TCL_64BIT_FLAGS], [
#------------------------------------------------------------------------
AC_DEFUN([TEA_INIT], [
- # TEA extensions pass this us the version of TEA they think they
- # are compatible with.
- TEA_VERSION="3.9"
+ TEA_VERSION="3.13"
- AC_MSG_CHECKING([for correct TEA configuration])
+ AC_MSG_CHECKING([TEA configuration])
if test x"${PACKAGE_NAME}" = x ; then
AC_MSG_ERROR([
-The PACKAGE_NAME variable must be defined by your TEA configure.in])
- fi
- if test x"$1" = x ; then
- AC_MSG_ERROR([
-TEA version not specified.])
- elif test "$1" != "${TEA_VERSION}" ; then
- AC_MSG_RESULT([warning: requested TEA version "$1", have "${TEA_VERSION}"])
- else
- AC_MSG_RESULT([ok (TEA ${TEA_VERSION})])
+The PACKAGE_NAME variable must be defined by your TEA configure.ac])
fi
+ AC_MSG_RESULT([ok (TEA ${TEA_VERSION})])
# If the user did not set CFLAGS, set it now to keep macros
# like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2".
@@ -2865,15 +2636,14 @@ TEA version not specified.])
fi
case "`uname -s`" in
- *win32*|*WIN32*|*MINGW32_*)
- AC_CHECK_PROG(CYGPATH, cygpath, cygpath -w, echo)
+ *win32*|*WIN32*|*MINGW32_*|*MINGW64_*)
+ AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo)
EXEEXT=".exe"
TEA_PLATFORM="windows"
;;
*CYGWIN_*)
- CYGPATH=echo
EXEEXT=".exe"
- # TEA_PLATFORM is determined later in LOAD_TCLCONFIG
+ # CYGPATH and TEA_PLATFORM are determined later in LOAD_TCLCONFIG
;;
*)
CYGPATH=echo
@@ -2919,6 +2689,9 @@ TEA version not specified.])
AC_SUBST(PKG_INCLUDES)
AC_SUBST(PKG_LIBS)
AC_SUBST(PKG_CFLAGS)
+
+ # Configure the installer.
+ TEA_INSTALLER
])
#------------------------------------------------------------------------
@@ -3194,7 +2967,7 @@ AC_DEFUN([TEA_PREFIX], [
# TEA_SETUP_COMPILER_CC --
#
# Do compiler checks the way we want. This is just a replacement
-# for AC_PROG_CC in TEA configure.in files to make them cleaner.
+# for AC_PROG_CC in TEA configure.ac files to make them cleaner.
#
# Arguments:
# none
@@ -3210,15 +2983,6 @@ AC_DEFUN([TEA_SETUP_COMPILER_CC], [
AC_PROG_CC
AC_PROG_CPP
- INSTALL="\$(SHELL) \$(srcdir)/tclconfig/install-sh -c"
- AC_SUBST(INSTALL)
- INSTALL_DATA="\${INSTALL} -m 644"
- AC_SUBST(INSTALL_DATA)
- INSTALL_PROGRAM="\${INSTALL}"
- AC_SUBST(INSTALL_PROGRAM)
- INSTALL_SCRIPT="\${INSTALL}"
- AC_SUBST(INSTALL_SCRIPT)
-
#--------------------------------------------------------------------
# Checks to see if the make program sets the $MAKE variable.
#--------------------------------------------------------------------
@@ -3277,14 +3041,6 @@ AC_DEFUN([TEA_SETUP_COMPILER], [
#--------------------------------------------------------------------
AC_C_BIGENDIAN
- if test "${TEA_PLATFORM}" = "unix" ; then
- TEA_TCL_LINK_LIBS
- TEA_MISSING_POSIX_HEADERS
- # Let the user call this, because if it triggers, they will
- # need a compat/strtod.c that is correct. Users can also
- # use Tcl_GetDouble(FromObj) instead.
- #TEA_BUGGY_STRTOD
- fi
])
#------------------------------------------------------------------------
@@ -3357,15 +3113,15 @@ print("manifest needed")
if test "$GCC" = "yes"; then
SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc"
fi
- eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
else
- eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
if test "$GCC" = "yes"; then
PKG_LIB_FILE=lib${PKG_LIB_FILE}
fi
fi
# Some packages build their own stubs libraries
- eval eval "PKG_STUB_LIB_FILE=${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
if test "$GCC" = "yes"; then
PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE}
fi
@@ -3379,13 +3135,13 @@ print("manifest needed")
if test x"${TK_BIN_DIR}" != x ; then
SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}"
fi
- eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
RANLIB=:
else
- eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
fi
# Some packages build their own stubs libraries
- eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
fi
# These are escaped so that only CFLAGS is picked up at configure time.
@@ -3930,6 +3686,7 @@ AC_DEFUN([TEA_PATH_CONFIG], [
`ls -d ${prefix}/lib 2>/dev/null` \
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
+ `ls -d /usr/pkg/lib 2>/dev/null` \
`ls -d /usr/lib 2>/dev/null` \
`ls -d /usr/lib64 2>/dev/null` \
; do
@@ -4077,12 +3834,12 @@ AC_DEFUN([TEA_EXPORT_CONFIG], [
eval $1_LIB_FLAG="-l$1`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}"
eval $1_STUB_LIB_FLAG="-l$1stub`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}"
fi
- $1_BUILD_LIB_SPEC="-L`pwd` ${$1_LIB_FLAG}"
- $1_LIB_SPEC="-L${pkglibdir} ${$1_LIB_FLAG}"
- $1_BUILD_STUB_LIB_SPEC="-L`pwd` [$]{$1_STUB_LIB_FLAG}"
- $1_STUB_LIB_SPEC="-L${pkglibdir} [$]{$1_STUB_LIB_FLAG}"
- $1_BUILD_STUB_LIB_PATH="`pwd`/[$]{PKG_STUB_LIB_FILE}"
- $1_STUB_LIB_PATH="${pkglibdir}/[$]{PKG_STUB_LIB_FILE}"
+ $1_BUILD_LIB_SPEC="-L`$CYGPATH $(pwd)` ${$1_LIB_FLAG}"
+ $1_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` ${$1_LIB_FLAG}"
+ $1_BUILD_STUB_LIB_SPEC="-L`$CYGPATH $(pwd)` [$]{$1_STUB_LIB_FLAG}"
+ $1_STUB_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` [$]{$1_STUB_LIB_FLAG}"
+ $1_BUILD_STUB_LIB_PATH="`$CYGPATH $(pwd)`/[$]{PKG_STUB_LIB_FILE}"
+ $1_STUB_LIB_PATH="`$CYGPATH ${pkglibdir}`/[$]{PKG_STUB_LIB_FILE}"
AC_SUBST($1_BUILD_LIB_SPEC)
AC_SUBST($1_LIB_SPEC)
@@ -4098,71 +3855,151 @@ AC_DEFUN([TEA_EXPORT_CONFIG], [
#------------------------------------------------------------------------
-# TEA_PATH_CELIB --
+# TEA_INSTALLER --
#
-# Locate Keuchel's celib emulation layer for targeting Win/CE
+# Configure the installer.
#
# Arguments:
# none
#
# Results:
-#
-# Adds the following arguments to configure:
-# --with-celib=...
-#
-# Defines the following vars:
-# CELIB_DIR Full path to the directory containing
-# the include and platform lib files
+# Substitutes the following vars:
+# INSTALL
+# INSTALL_DATA_DIR
+# INSTALL_DATA
+# INSTALL_PROGRAM
+# INSTALL_SCRIPT
+# INSTALL_LIBRARY
#------------------------------------------------------------------------
-AC_DEFUN([TEA_PATH_CELIB], [
- # First, look for one uninstalled.
- # the alternative search directory is invoked by --with-celib
+AC_DEFUN([TEA_INSTALLER], [
+ INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c'
+ INSTALL_DATA_DIR='${INSTALL} -d -m 755'
+ INSTALL_DATA='${INSTALL} -m 644'
+ INSTALL_PROGRAM='${INSTALL} -m 755'
+ INSTALL_SCRIPT='${INSTALL} -m 755'
- if test x"${no_celib}" = x ; then
- # we reset no_celib in case something fails here
- no_celib=true
- AC_ARG_WITH(celib,[ --with-celib=DIR use Windows/CE support library from DIR], with_celibconfig=${withval})
- AC_MSG_CHECKING([for Windows/CE celib directory])
- AC_CACHE_VAL(ac_cv_c_celibconfig,[
- # First check to see if --with-celibconfig was specified.
- if test x"${with_celibconfig}" != x ; then
- if test -d "${with_celibconfig}/inc" ; then
- ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)`
- else
- AC_MSG_ERROR([${with_celibconfig} directory doesn't contain inc directory])
- fi
- fi
+ TEA_CONFIG_SYSTEM
+ case $system in
+ HP-UX-*) INSTALL_LIBRARY='${INSTALL} -m 755' ;;
+ *) INSTALL_LIBRARY='${INSTALL} -m 644' ;;
+ esac
- # then check for a celib library
- if test x"${ac_cv_c_celibconfig}" = x ; then
- for i in \
- ../celib-palm-3.0 \
- ../celib \
- ../../celib-palm-3.0 \
- ../../celib \
- `ls -dr ../celib-*3.[[0-9]]* 2>/dev/null` \
- ${srcdir}/../celib-palm-3.0 \
- ${srcdir}/../celib \
- `ls -dr ${srcdir}/../celib-*3.[[0-9]]* 2>/dev/null` \
- ; do
- if test -d "$i/inc" ; then
- ac_cv_c_celibconfig=`(cd $i; pwd)`
- break
- fi
- done
- fi
- ])
- if test x"${ac_cv_c_celibconfig}" = x ; then
- AC_MSG_ERROR([Cannot find celib support library directory])
- else
- no_celib=
- CELIB_DIR=${ac_cv_c_celibconfig}
- CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'`
- AC_MSG_RESULT([found $CELIB_DIR])
- fi
+ AC_SUBST(INSTALL)
+ AC_SUBST(INSTALL_DATA_DIR)
+ AC_SUBST(INSTALL_DATA)
+ AC_SUBST(INSTALL_PROGRAM)
+ AC_SUBST(INSTALL_SCRIPT)
+ AC_SUBST(INSTALL_LIBRARY)
+])
+
+###
+# Tip 430 - ZipFS Modifications
+###
+#------------------------------------------------------------------------
+# SC_ZIPFS_SUPPORT
+# Locate a zip encoder installed on the system path, or none.
+#
+# Arguments:
+# none
+#
+# Results:
+# Substitutes the following vars:
+# TCL_ZIP_FILE
+# TCL_ZIPFS_SUPPORT
+# TCL_ZIPFS_FLAG
+# ZIP_PROG
+#------------------------------------------------------------------------
+
+#------------------------------------------------------------------------
+# SC_PROG_ZIP
+# Locate a zip encoder installed on the system path, or none.
+#
+# Arguments:
+# none
+#
+# Results:
+# Substitutes the following vars:
+# ZIP_PROG
+# ZIP_PROG_OPTIONS
+# ZIP_PROG_VFSSEARCH
+# ZIP_INSTALL_OBJS
+#------------------------------------------------------------------------
+AC_DEFUN([TEA_ZIPFS_SUPPORT], [
+ AC_MSG_CHECKING([for zipfs support])
+ ZIP_PROG=""
+ ZIP_PROG_OPTIONS=""
+ ZIP_PROG_VFSSEARCH=""
+ INSTALL_MSGS=""
+ # If our native tclsh processes the "install" command line option
+ # we can use it to mint zip files
+ AS_IF([$TCLSH_PROG install],[
+ ZIP_PROG=${TCLSH_PROG}
+ ZIP_PROG_OPTIONS="install mkzip"
+ ZIP_PROG_VFSSEARCH="."
+ AC_MSG_RESULT([Can use Native Tclsh for Zip encoding])
+ ])
+ if test "x$ZIP_PROG" = "x" ; then
+ AC_CACHE_VAL(ac_cv_path_zip, [
+ search_path=`echo ${PATH} | sed -e 's/:/ /g'`
+ for dir in $search_path ; do
+ for j in `ls -r $dir/zip 2> /dev/null` \
+ `ls -r $dir/zip 2> /dev/null` ; do
+ if test x"$ac_cv_path_zip" = x ; then
+ if test -f "$j" ; then
+ ac_cv_path_zip=$j
+ break
+ fi
+ fi
+ done
+ done
+ ])
+ if test -f "$ac_cv_path_zip" ; then
+ ZIP_PROG="$ac_cv_path_zip "
+ AC_MSG_RESULT([$ZIP_PROG])
+ ZIP_PROG_OPTIONS="-rq"
+ ZIP_PROG_VFSSEARCH="."
+ AC_MSG_RESULT([Found INFO Zip in environment])
+ # Use standard arguments for zip
+ fi
fi
+ if test "x$ZIP_PROG" = "x" ; then
+ # It is not an error if an installed version of Zip can't be located.
+ ZIP_PROG=""
+ ZIP_PROG_OPTIONS=""
+ ZIP_PROG_VFSSEARCH=""
+ TCL_ZIPFS_SUPPORT=0
+ TCL_ZIPFS_FLAG=
+ else
+ # ZIPFS Support
+ eval "TCL_ZIP_FILE=\"${TCL_ZIP_FILE}\""
+ if test ${TCL_ZIP_FILE} = "" ; then
+ TCL_ZIPFS_SUPPORT=0
+ TCL_ZIPFS_FLAG=
+ INSTALL_LIBRARIES=install-libraries
+ INSTALL_MSGS=install-msgs
+ else
+ if test ${SHARED_BUILD} = 1 ; then
+ TCL_ZIPFS_SUPPORT=1
+ INSTALL_LIBRARIES=install-libraries-zipfs-shared
+ else
+ TCL_ZIPFS_SUPPORT=2
+ INSTALL_LIBRARIES=install-libraries-zipfs-static
+ fi
+ TCL_ZIPFS_FLAG=-DTCL_ZIPFS_SUPPORT
+ fi
+ fi
+
+ AC_SUBST(TCL_ZIP_FILE)
+ AC_SUBST(TCL_ZIPFS_SUPPORT)
+ AC_SUBST(TCL_ZIPFS_FLAG)
+ AC_SUBST(ZIP_PROG)
+ AC_SUBST(ZIP_PROG_OPTIONS)
+ AC_SUBST(ZIP_PROG_VFSSEARCH)
+ AC_SUBST(INSTALL_LIBRARIES)
+ AC_SUBST(INSTALL_MSGS)
])
+
# Local Variables:
# mode: autoconf
# End:
--- origsrc/sqlite-autoconf-3300000/templatevtab.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/templatevtab.c 2019-10-08 13:42:19.231596500 +0200
@@ -0,0 +1,277 @@
+/*
+** 2018-04-19
+**
+** 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 implements a template virtual-table.
+** Developers can make a copy of this file as a baseline for writing
+** new virtual tables and/or table-valued functions.
+**
+** Steps for writing a new virtual table implementation:
+**
+** (1) Make a copy of this file. Perhaps call it "mynewvtab.c"
+**
+** (2) Replace this header comment with something appropriate for
+** the new virtual table
+**
+** (3) Change every occurrence of "templatevtab" to some other string
+** appropriate for the new virtual table. Ideally, the new string
+** should be the basename of the source file: "mynewvtab". Also
+** globally change "TEMPLATEVTAB" to "MYNEWVTAB".
+**
+** (4) Run a test compilation to make sure the unmodified virtual
+** table works.
+**
+** (5) Begin making incremental changes, testing as you go, to evolve
+** the new virtual table to do what you want it to do.
+**
+** This template is minimal, in the sense that it uses only the required
+** methods on the sqlite3_module object. As a result, templatevtab is
+** a read-only and eponymous-only table. Those limitation can be removed
+** by adding new methods.
+**
+** This template implements an eponymous-only virtual table with a rowid and
+** two columns named "a" and "b". The table as 10 rows with fixed integer
+** values. Usage example:
+**
+** SELECT rowid, a, b FROM templatevtab;
+*/
+#if !defined(SQLITEINT_H)
+#include "sqlite3ext.h"
+#endif
+SQLITE_EXTENSION_INIT1
+#include <string.h>
+#include <assert.h>
+
+/* templatevtab_vtab is a subclass of sqlite3_vtab which is
+** underlying representation of the virtual table
+*/
+typedef struct templatevtab_vtab templatevtab_vtab;
+struct templatevtab_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ /* Add new fields here, as necessary */
+};
+
+/* templatevtab_cursor is a subclass of sqlite3_vtab_cursor which will
+** serve as the underlying representation of a cursor that scans
+** over rows of the result
+*/
+typedef struct templatevtab_cursor templatevtab_cursor;
+struct templatevtab_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ /* Insert new fields here. For this templatevtab we only keep track
+ ** of the rowid */
+ sqlite3_int64 iRowid; /* The rowid */
+};
+
+/*
+** The templatevtabConnect() method is invoked to create a new
+** template virtual table.
+**
+** Think of this routine as the constructor for templatevtab_vtab objects.
+**
+** All this routine needs to do is:
+**
+** (1) Allocate the templatevtab_vtab object and initialize all fields.
+**
+** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
+** result set of queries against the virtual table will look like.
+*/
+static int templatevtabConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ templatevtab_vtab *pNew;
+ int rc;
+
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x(a,b)"
+ );
+ /* For convenience, define symbolic names for the index to each column. */
+#define TEMPLATEVTAB_A 0
+#define TEMPLATEVTAB_B 1
+ if( rc==SQLITE_OK ){
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for templatevtab_vtab objects.
+*/
+static int templatevtabDisconnect(sqlite3_vtab *pVtab){
+ templatevtab_vtab *p = (templatevtab_vtab*)pVtab;
+ sqlite3_free(p);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new templatevtab_cursor object.
+*/
+static int templatevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ templatevtab_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Destructor for a templatevtab_cursor.
+*/
+static int templatevtabClose(sqlite3_vtab_cursor *cur){
+ templatevtab_cursor *pCur = (templatevtab_cursor*)cur;
+ sqlite3_free(pCur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a templatevtab_cursor to its next row of output.
+*/
+static int templatevtabNext(sqlite3_vtab_cursor *cur){
+ templatevtab_cursor *pCur = (templatevtab_cursor*)cur;
+ pCur->iRowid++;
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the templatevtab_cursor
+** is currently pointing.
+*/
+static int templatevtabColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ templatevtab_cursor *pCur = (templatevtab_cursor*)cur;
+ switch( i ){
+ case TEMPLATEVTAB_A:
+ sqlite3_result_int(ctx, 1000 + pCur->iRowid);
+ break;
+ default:
+ assert( i==TEMPLATEVTAB_B );
+ sqlite3_result_int(ctx, 2000 + pCur->iRowid);
+ break;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** rowid is the same as the output value.
+*/
+static int templatevtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ templatevtab_cursor *pCur = (templatevtab_cursor*)cur;
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int templatevtabEof(sqlite3_vtab_cursor *cur){
+ templatevtab_cursor *pCur = (templatevtab_cursor*)cur;
+ return pCur->iRowid>=10;
+}
+
+/*
+** This method is called to "rewind" the templatevtab_cursor object back
+** to the first row of output. This method is always called at least
+** once prior to any call to templatevtabColumn() or templatevtabRowid() or
+** templatevtabEof().
+*/
+static int templatevtabFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ templatevtab_cursor *pCur = (templatevtab_cursor *)pVtabCursor;
+ pCur->iRowid = 1;
+ return SQLITE_OK;
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+*/
+static int templatevtabBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ pIdxInfo->estimatedCost = (double)10;
+ pIdxInfo->estimatedRows = 10;
+ return SQLITE_OK;
+}
+
+/*
+** This following structure defines all the methods for the
+** virtual table.
+*/
+static const sqlite3_module templatevtabModule = {
+ /* iVersion */ 0,
+ /* xCreate */ 0,
+ /* xConnect */ templatevtabConnect,
+ /* xBestIndex */ templatevtabBestIndex,
+ /* xDisconnect */ templatevtabDisconnect,
+ /* xDestroy */ 0,
+ /* xOpen */ templatevtabOpen,
+ /* xClose */ templatevtabClose,
+ /* xFilter */ templatevtabFilter,
+ /* xNext */ templatevtabNext,
+ /* xEof */ templatevtabEof,
+ /* xColumn */ templatevtabColumn,
+ /* xRowid */ templatevtabRowid,
+ /* xUpdate */ 0,
+ /* xBegin */ 0,
+ /* xSync */ 0,
+ /* xCommit */ 0,
+ /* xRollback */ 0,
+ /* xFindMethod */ 0,
+ /* xRename */ 0,
+ /* xSavepoint */ 0,
+ /* xRelease */ 0,
+ /* xRollbackTo */ 0,
+ /* xShadowName */ 0
+};
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_templatevtab_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ rc = sqlite3_create_module(db, "templatevtab", &templatevtabModule, 0);
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ return sqlite3_templatevtab_init(db, pzErrMsg, pApi);
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/totype.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/totype.c 2019-10-08 13:42:19.233549900 +0200
@@ -0,0 +1,521 @@
+/*
+** 2013-10-14
+**
+** 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 SQLite extension implements functions tointeger(X) and toreal(X).
+**
+** If X is an integer, real, or string value that can be
+** losslessly represented as an integer, then tointeger(X)
+** returns the corresponding integer value.
+** If X is an 8-byte BLOB then that blob is interpreted as
+** a signed two-compliment little-endian encoding of an integer
+** and tointeger(X) returns the corresponding integer value.
+** Otherwise tointeger(X) return NULL.
+**
+** If X is an integer, real, or string value that can be
+** convert into a real number, preserving at least 15 digits
+** of precision, then toreal(X) returns the corresponding real value.
+** If X is an 8-byte BLOB then that blob is interpreted as
+** a 64-bit IEEE754 big-endian floating point value
+** and toreal(X) returns the corresponding real value.
+** Otherwise toreal(X) return NULL.
+**
+** Note that tointeger(X) of an 8-byte BLOB assumes a little-endian
+** encoding whereas toreal(X) of an 8-byte BLOB assumes a big-endian
+** encoding.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+
+/*
+** Determine if this is running on a big-endian or little-endian
+** processor
+*/
+#if defined(i386) || defined(__i386__) || defined(_M_IX86)\
+ || defined(__x86_64) || defined(__x86_64__)
+# define TOTYPE_BIGENDIAN 0
+# define TOTYPE_LITTLEENDIAN 1
+#else
+ const int totype_one = 1;
+# define TOTYPE_BIGENDIAN (*(char *)(&totype_one)==0)
+# define TOTYPE_LITTLEENDIAN (*(char *)(&totype_one)==1)
+#endif
+
+/*
+** Constants for the largest and smallest possible 64-bit signed integers.
+** These macros are designed to work correctly on both 32-bit and 64-bit
+** compilers.
+*/
+#ifndef LARGEST_INT64
+# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
+#endif
+
+#ifndef SMALLEST_INT64
+# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
+#endif
+
+/*
+** Return TRUE if character c is a whitespace character
+*/
+static int totypeIsspace(unsigned char c){
+ return c==' ' || c=='\t' || c=='\n' || c=='\v' || c=='\f' || c=='\r';
+}
+
+/*
+** Return TRUE if character c is a digit
+*/
+static int totypeIsdigit(unsigned char c){
+ return c>='0' && c<='9';
+}
+
+/*
+** Compare the 19-character string zNum against the text representation
+** value 2^63: 9223372036854775808. Return negative, zero, or positive
+** if zNum is less than, equal to, or greater than the string.
+** Note that zNum must contain exactly 19 characters.
+**
+** Unlike memcmp() this routine is guaranteed to return the difference
+** in the values of the last digit if the only difference is in the
+** last digit. So, for example,
+**
+** totypeCompare2pow63("9223372036854775800")
+**
+** will return -8.
+*/
+static int totypeCompare2pow63(const char *zNum){
+ int c = 0;
+ int i;
+ /* 012345678901234567 */
+ const char *pow63 = "922337203685477580";
+ for(i=0; c==0 && i<18; i++){
+ c = (zNum[i]-pow63[i])*10;
+ }
+ if( c==0 ){
+ c = zNum[18] - '8';
+ }
+ return c;
+}
+
+/*
+** Convert zNum to a 64-bit signed integer.
+**
+** 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 9223372036854665808, return 2. This special
+** case is broken out because while 9223372036854665808 cannot be a
+** signed 64-bit integer, its negative -9223372036854665808 can be.
+**
+** If zNum is too big for a 64-bit integer and is not
+** 9223372036854665808 or if zNum contains any non-numeric text,
+** then return 1.
+**
+** The string is not necessarily zero-terminated.
+*/
+static int totypeAtoi64(const char *zNum, sqlite3_int64 *pNum, int length){
+ sqlite3_uint64 u = 0;
+ int neg = 0; /* assume positive */
+ int i;
+ int c = 0;
+ int nonNum = 0;
+ const char *zStart;
+ const char *zEnd = zNum + length;
+
+ while( zNum<zEnd && totypeIsspace(*zNum) ) zNum++;
+ if( zNum<zEnd ){
+ if( *zNum=='-' ){
+ neg = 1;
+ zNum++;
+ }else if( *zNum=='+' ){
+ zNum++;
+ }
+ }
+ zStart = zNum;
+ while( zNum<zEnd && zNum[0]=='0' ){ zNum++; } /* Skip leading zeros. */
+ for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i++){
+ u = u*10 + c - '0';
+ }
+ if( u>LARGEST_INT64 ){
+ *pNum = SMALLEST_INT64;
+ }else if( neg ){
+ *pNum = -(sqlite3_int64)u;
+ }else{
+ *pNum = (sqlite3_int64)u;
+ }
+ if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19 || nonNum ){
+ /* zNum is empty or contains non-numeric text or is longer
+ ** than 19 digits (thus guaranteeing that it is too large) */
+ return 1;
+ }else if( i<19 ){
+ /* Less than 19 digits, so we know that it fits in 64 bits */
+ assert( u<=LARGEST_INT64 );
+ return 0;
+ }else{
+ /* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */
+ c = totypeCompare2pow63(zNum);
+ if( c<0 ){
+ /* zNum is less than 9223372036854775808 so it fits */
+ assert( u<=LARGEST_INT64 );
+ return 0;
+ }else if( c>0 ){
+ /* zNum is greater than 9223372036854775808 so it overflows */
+ return 1;
+ }else{
+ /* zNum is exactly 9223372036854775808. Fits if negative. The
+ ** special case 2 overflow if positive */
+ assert( u-1==LARGEST_INT64 );
+ assert( (*pNum)==SMALLEST_INT64 );
+ return neg ? 0 : 2;
+ }
+ }
+}
+
+/*
+** The string z[] is an text representation of a real number.
+** Convert this string to a double and write it into *pResult.
+**
+** The string is not necessarily zero-terminated.
+**
+** Return TRUE if the result is a valid real number (or integer) and FALSE
+** if the string is empty or contains extraneous text. Valid numbers
+** are in one of these formats:
+**
+** [+-]digits[E[+-]digits]
+** [+-]digits.[digits][E[+-]digits]
+** [+-].digits[E[+-]digits]
+**
+** Leading and trailing whitespace is ignored for the purpose of determining
+** validity.
+**
+** If some prefix of the input string is a valid number, this routine
+** returns FALSE but it still converts the prefix and writes the result
+** into *pResult.
+*/
+static int totypeAtoF(const char *z, double *pResult, int length){
+ const char *zEnd = z + length;
+ /* sign * significand * (10 ^ (esign * exponent)) */
+ int sign = 1; /* sign of significand */
+ sqlite3_int64 s = 0; /* significand */
+ int d = 0; /* adjust exponent for shifting decimal point */
+ int esign = 1; /* sign of exponent */
+ int e = 0; /* exponent */
+ int eValid = 1; /* True exponent is either not used or is well-formed */
+ double result;
+ int nDigits = 0;
+ int nonNum = 0;
+
+ *pResult = 0.0; /* Default return value, in case of an error */
+
+ /* skip leading spaces */
+ while( z<zEnd && totypeIsspace(*z) ) z++;
+ if( z>=zEnd ) return 0;
+
+ /* get sign of significand */
+ if( *z=='-' ){
+ sign = -1;
+ z++;
+ }else if( *z=='+' ){
+ z++;
+ }
+
+ /* skip leading zeroes */
+ while( z<zEnd && z[0]=='0' ) z++, nDigits++;
+
+ /* copy max significant digits to significand */
+ while( z<zEnd && totypeIsdigit(*z) && s<((LARGEST_INT64-9)/10) ){
+ s = s*10 + (*z - '0');
+ z++, nDigits++;
+ }
+
+ /* skip non-significant significand digits
+ ** (increase exponent by d to shift decimal left) */
+ while( z<zEnd && totypeIsdigit(*z) ) z++, nDigits++, d++;
+ if( z>=zEnd ) goto totype_atof_calc;
+
+ /* if decimal point is present */
+ if( *z=='.' ){
+ z++;
+ /* copy digits from after decimal to significand
+ ** (decrease exponent by d to shift decimal right) */
+ while( z<zEnd && totypeIsdigit(*z) && s<((LARGEST_INT64-9)/10) ){
+ s = s*10 + (*z - '0');
+ z++, nDigits++, d--;
+ }
+ /* skip non-significant digits */
+ while( z<zEnd && totypeIsdigit(*z) ) z++, nDigits++;
+ }
+ if( z>=zEnd ) goto totype_atof_calc;
+
+ /* if exponent is present */
+ if( *z=='e' || *z=='E' ){
+ z++;
+ eValid = 0;
+ if( z>=zEnd ) goto totype_atof_calc;
+ /* get sign of exponent */
+ if( *z=='-' ){
+ esign = -1;
+ z++;
+ }else if( *z=='+' ){
+ z++;
+ }
+ /* copy digits to exponent */
+ while( z<zEnd && totypeIsdigit(*z) ){
+ e = e<10000 ? (e*10 + (*z - '0')) : 10000;
+ z++;
+ eValid = 1;
+ }
+ }
+
+ /* skip trailing spaces */
+ if( nDigits && eValid ){
+ while( z<zEnd && totypeIsspace(*z) ) z++;
+ }
+
+totype_atof_calc:
+ /* adjust exponent by d, and update sign */
+ e = (e*esign) + d;
+ if( e<0 ) {
+ esign = -1;
+ e *= -1;
+ } else {
+ esign = 1;
+ }
+
+ /* if 0 significand */
+ if( !s ) {
+ /* In the IEEE 754 standard, zero is signed.
+ ** Add the sign if we've seen at least one digit */
+ result = (sign<0 && nDigits) ? -(double)0 : (double)0;
+ } else {
+ /* attempt to reduce exponent */
+ if( esign>0 ){
+ while( s<(LARGEST_INT64/10) && e>0 ) e--,s*=10;
+ }else{
+ while( !(s%10) && e>0 ) e--,s/=10;
+ }
+
+ /* adjust the sign of significand */
+ s = sign<0 ? -s : s;
+
+ /* if exponent, scale significand as appropriate
+ ** and store in result. */
+ if( e ){
+ double scale = 1.0;
+ /* attempt to handle extremely small/large numbers better */
+ if( e>307 && e<342 ){
+ while( e%308 ) { scale *= 1.0e+1; e -= 1; }
+ if( esign<0 ){
+ result = s / scale;
+ result /= 1.0e+308;
+ }else{
+ result = s * scale;
+ result *= 1.0e+308;
+ }
+ }else if( e>=342 ){
+ if( esign<0 ){
+ result = 0.0*s;
+ }else{
+ result = 1e308*1e308*s; /* Infinity */
+ }
+ }else{
+ /* 1.0e+22 is the largest power of 10 than can be
+ ** represented exactly. */
+ while( e%22 ) { scale *= 1.0e+1; e -= 1; }
+ while( e>0 ) { scale *= 1.0e+22; e -= 22; }
+ if( esign<0 ){
+ result = s / scale;
+ }else{
+ result = s * scale;
+ }
+ }
+ } else {
+ result = (double)s;
+ }
+ }
+
+ /* store the result */
+ *pResult = result;
+
+ /* return true if number and no extra non-whitespace chracters after */
+ return z>=zEnd && nDigits>0 && eValid && nonNum==0;
+}
+
+/*
+** tointeger(X): If X is any value (integer, double, blob, or string) that
+** can be losslessly converted into an integer, then make the conversion and
+** return the result. Otherwise, return NULL.
+*/
+static void tointegerFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ assert( argc==1 );
+ (void)argc;
+ switch( sqlite3_value_type(argv[0]) ){
+ case SQLITE_FLOAT: {
+ double rVal = sqlite3_value_double(argv[0]);
+ sqlite3_int64 iVal = (sqlite3_int64)rVal;
+ if( rVal==(double)iVal ){
+ sqlite3_result_int64(context, iVal);
+ }
+ break;
+ }
+ case SQLITE_INTEGER: {
+ sqlite3_result_int64(context, sqlite3_value_int64(argv[0]));
+ break;
+ }
+ case SQLITE_BLOB: {
+ const unsigned char *zBlob = sqlite3_value_blob(argv[0]);
+ if( zBlob ){
+ int nBlob = sqlite3_value_bytes(argv[0]);
+ if( nBlob==sizeof(sqlite3_int64) ){
+ sqlite3_int64 iVal;
+ if( TOTYPE_BIGENDIAN ){
+ int i;
+ unsigned char zBlobRev[sizeof(sqlite3_int64)];
+ for(i=0; i<sizeof(sqlite3_int64); i++){
+ zBlobRev[i] = zBlob[sizeof(sqlite3_int64)-1-i];
+ }
+ memcpy(&iVal, zBlobRev, sizeof(sqlite3_int64));
+ }else{
+ memcpy(&iVal, zBlob, sizeof(sqlite3_int64));
+ }
+ sqlite3_result_int64(context, iVal);
+ }
+ }
+ break;
+ }
+ case SQLITE_TEXT: {
+ const unsigned char *zStr = sqlite3_value_text(argv[0]);
+ if( zStr ){
+ int nStr = sqlite3_value_bytes(argv[0]);
+ if( nStr && !totypeIsspace(zStr[0]) ){
+ sqlite3_int64 iVal;
+ if( !totypeAtoi64((const char*)zStr, &iVal, nStr) ){
+ sqlite3_result_int64(context, iVal);
+ }
+ }
+ }
+ break;
+ }
+ default: {
+ assert( sqlite3_value_type(argv[0])==SQLITE_NULL );
+ break;
+ }
+ }
+}
+
+/*
+** toreal(X): If X is any value (integer, double, blob, or string) that can
+** be losslessly converted into a real number, then do so and return that
+** real number. Otherwise return NULL.
+*/
+#if defined(_MSC_VER)
+#pragma warning(disable: 4748)
+#pragma optimize("", off)
+#endif
+static void torealFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ assert( argc==1 );
+ (void)argc;
+ switch( sqlite3_value_type(argv[0]) ){
+ case SQLITE_FLOAT: {
+ sqlite3_result_double(context, sqlite3_value_double(argv[0]));
+ break;
+ }
+ case SQLITE_INTEGER: {
+ sqlite3_int64 iVal = sqlite3_value_int64(argv[0]);
+ double rVal = (double)iVal;
+ if( iVal==(sqlite3_int64)rVal ){
+ sqlite3_result_double(context, rVal);
+ }
+ break;
+ }
+ case SQLITE_BLOB: {
+ const unsigned char *zBlob = sqlite3_value_blob(argv[0]);
+ if( zBlob ){
+ int nBlob = sqlite3_value_bytes(argv[0]);
+ if( nBlob==sizeof(double) ){
+ double rVal;
+ if( TOTYPE_LITTLEENDIAN ){
+ int i;
+ unsigned char zBlobRev[sizeof(double)];
+ for(i=0; i<sizeof(double); i++){
+ zBlobRev[i] = zBlob[sizeof(double)-1-i];
+ }
+ memcpy(&rVal, zBlobRev, sizeof(double));
+ }else{
+ memcpy(&rVal, zBlob, sizeof(double));
+ }
+ sqlite3_result_double(context, rVal);
+ }
+ }
+ break;
+ }
+ case SQLITE_TEXT: {
+ const unsigned char *zStr = sqlite3_value_text(argv[0]);
+ if( zStr ){
+ int nStr = sqlite3_value_bytes(argv[0]);
+ if( nStr && !totypeIsspace(zStr[0]) && !totypeIsspace(zStr[nStr-1]) ){
+ double rVal;
+ if( totypeAtoF((const char*)zStr, &rVal, nStr) ){
+ sqlite3_result_double(context, rVal);
+ return;
+ }
+ }
+ }
+ break;
+ }
+ default: {
+ assert( sqlite3_value_type(argv[0])==SQLITE_NULL );
+ break;
+ }
+ }
+}
+#if defined(_MSC_VER)
+#pragma optimize("", on)
+#pragma warning(default: 4748)
+#endif
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_totype_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "tointeger", 1, SQLITE_UTF8, 0,
+ tointegerFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "toreal", 1, SQLITE_UTF8, 0,
+ torealFunc, 0, 0);
+ }
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ return sqlite3_totype_init(db, pzErrMsg, pApi);
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/unionvtab.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/unionvtab.c 2019-10-08 13:42:19.237466000 +0200
@@ -0,0 +1,1391 @@
+/*
+** 2017 July 15
+**
+** 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 the implementation of the "unionvtab" and "swarmvtab"
+** virtual tables. These modules provide read-only access to multiple tables,
+** possibly in multiple database files, via a single database object.
+** The source tables must have the following characteristics:
+**
+** * They must all be rowid tables (not VIRTUAL or WITHOUT ROWID
+** tables or views).
+**
+** * Each table must have the same set of columns, declared in
+** the same order and with the same declared types.
+**
+** * The tables must not feature a user-defined column named "_rowid_".
+**
+** * Each table must contain a distinct range of rowid values.
+**
+** The difference between the two virtual table modules is that for
+** "unionvtab", all source tables must be located in the main database or
+** in databases ATTACHed to the main database by the user. For "swarmvtab",
+** the tables may be located in any database file on disk. The "swarmvtab"
+** implementation takes care of opening and closing database files
+** automatically.
+**
+** UNIONVTAB
+**
+** A "unionvtab" virtual table is created as follows:
+**
+** CREATE VIRTUAL TABLE <name> USING unionvtab(<sql-statement>);
+**
+** The implementation evalutes <sql statement> whenever a unionvtab virtual
+** table is created or opened. It should return one row for each source
+** database table. The four columns required of each row are:
+**
+** 1. The name of the database containing the table ("main" or "temp" or
+** the name of an attached database). Or NULL to indicate that all
+** databases should be searched for the table in the usual fashion.
+**
+** 2. The name of the database table.
+**
+** 3. The smallest rowid in the range of rowids that may be stored in the
+** database table (an integer).
+**
+** 4. The largest rowid in the range of rowids that may be stored in the
+** database table (an integer).
+**
+** SWARMVTAB
+**
+** LEGACY SYNTAX:
+**
+** A "swarmvtab" virtual table is created similarly to a unionvtab table:
+**
+** CREATE VIRTUAL TABLE <name>
+** USING swarmvtab(<sql-statement>, <callback>);
+**
+** The difference is that for a swarmvtab table, the first column returned
+** by the <sql statement> must return a path or URI that can be used to open
+** the database file containing the source table. The <callback> option
+** is optional. If included, it is the name of an application-defined
+** SQL function that is invoked with the URI of the file, if the file
+** does not already exist on disk when required by swarmvtab.
+**
+** NEW SYNTAX:
+**
+** Using the new syntax, a swarmvtab table is created with:
+**
+** CREATE VIRTUAL TABLE <name> USING swarmvtab(
+** <sql-statement> [, <options>]
+** );
+**
+** where valid <options> are:
+**
+** missing=<udf-function-name>
+** openclose=<udf-function-name>
+** maxopen=<integer>
+** <sql-parameter>=<text-value>
+**
+** The <sql-statement> must return the same 4 columns as for a swarmvtab
+** table in legacy mode. However, it may also return a 5th column - the
+** "context" column. The text value returned in this column is not used
+** at all by the swarmvtab implementation, except that it is passed as
+** an additional argument to the two UDF functions that may be invoked
+** (see below).
+**
+** The "missing" option, if present, specifies the name of an SQL UDF
+** function to be invoked if a database file is not already present on
+** disk when required by swarmvtab. If the <sql-statement> did not provide
+** a context column, it is invoked as:
+**
+** SELECT <missing-udf>(<database filename/uri>);
+**
+** Or, if there was a context column:
+**
+** SELECT <missing-udf>(<database filename/uri>, <context>);
+**
+** The "openclose" option may also specify a UDF function. This function
+** is invoked right before swarmvtab opens a database, and right after
+** it closes one. The first argument - or first two arguments, if
+** <sql-statement> supplied the context column - is the same as for
+** the "missing" UDF. Following this, the UDF is passed integer value
+** 0 before a db is opened, and 1 right after it is closed. If both
+** a missing and openclose UDF is supplied, the application should expect
+** the following sequence of calls (for a single database):
+**
+** SELECT <openclose-udf>(<db filename>, <context>, 0);
+** if( db not already on disk ){
+** SELECT <missing-udf>(<db filename>, <context>);
+** }
+** ... swarmvtab uses database ...
+** SELECT <openclose-udf>(<db filename>, <context>, 1);
+**
+** The "maxopen" option is used to configure the maximum number of
+** database files swarmvtab will hold open simultaneously (default 9).
+**
+** If an option name begins with a ":" character, then it is assumed
+** to be an SQL parameter. In this case, the specified text value is
+** bound to the same variable of the <sql-statement> before it is
+** executed. It is an error of the named SQL parameter does not exist.
+** For example:
+**
+** CREATE VIRTUAL TABLE swarm USING swarmvtab(
+** 'SELECT :path || localfile, tbl, min, max FROM swarmdir',
+** :path='/home/user/databases/'
+** missing='missing_func'
+** );
+*/
+
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/*
+** Largest and smallest possible 64-bit signed integers. These macros
+** copied from sqliteInt.h.
+*/
+#ifndef LARGEST_INT64
+# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
+#endif
+#ifndef SMALLEST_INT64
+# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
+#endif
+
+/*
+** The following is also copied from sqliteInt.h. To facilitate coverage
+** testing.
+*/
+#ifndef ALWAYS
+# if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
+# define ALWAYS(X) (1)
+# define NEVER(X) (0)
+# elif !defined(NDEBUG)
+# define ALWAYS(X) ((X)?1:(assert(0),0))
+# define NEVER(X) ((X)?(assert(0),1):0)
+# else
+# define ALWAYS(X) (X)
+# define NEVER(X) (X)
+# endif
+#endif
+
+/*
+** The swarmvtab module attempts to keep the number of open database files
+** at or below this limit. This may not be possible if there are too many
+** simultaneous queries.
+*/
+#define SWARMVTAB_MAX_OPEN 9
+
+typedef struct UnionCsr UnionCsr;
+typedef struct UnionTab UnionTab;
+typedef struct UnionSrc UnionSrc;
+
+/*
+** Each source table (row returned by the initialization query) is
+** represented by an instance of the following structure stored in the
+** UnionTab.aSrc[] array.
+*/
+struct UnionSrc {
+ char *zDb; /* Database containing source table */
+ char *zTab; /* Source table name */
+ sqlite3_int64 iMin; /* Minimum rowid */
+ sqlite3_int64 iMax; /* Maximum rowid */
+
+ /* Fields used by swarmvtab only */
+ char *zFile; /* Database file containing table zTab */
+ char *zContext; /* Context string, if any */
+ int nUser; /* Current number of users */
+ sqlite3 *db; /* Database handle */
+ UnionSrc *pNextClosable; /* Next in list of closable sources */
+};
+
+/*
+** Virtual table type for union vtab.
+*/
+struct UnionTab {
+ sqlite3_vtab base; /* Base class - must be first */
+ sqlite3 *db; /* Database handle */
+ int bSwarm; /* 1 for "swarmvtab", 0 for "unionvtab" */
+ int iPK; /* INTEGER PRIMARY KEY column, or -1 */
+ int nSrc; /* Number of elements in the aSrc[] array */
+ UnionSrc *aSrc; /* Array of source tables, sorted by rowid */
+
+ /* Used by swarmvtab only */
+ int bHasContext; /* Has context strings */
+ char *zSourceStr; /* Expected unionSourceToStr() value */
+ sqlite3_stmt *pNotFound; /* UDF to invoke if file not found on open */
+ sqlite3_stmt *pOpenClose; /* UDF to invoke on open and close */
+
+ UnionSrc *pClosable; /* First in list of closable sources */
+ int nOpen; /* Current number of open sources */
+ int nMaxOpen; /* Maximum number of open sources */
+};
+
+/*
+** Virtual table cursor type for union vtab.
+*/
+struct UnionCsr {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3_stmt *pStmt; /* SQL statement to run */
+
+ /* Used by swarmvtab only */
+ sqlite3_int64 iMaxRowid; /* Last rowid to visit */
+ int iTab; /* Index of table read by pStmt */
+};
+
+/*
+** Given UnionTab table pTab and UnionSrc object pSrc, return the database
+** handle that should be used to access the table identified by pSrc. This
+** is the main db handle for "unionvtab" tables, or the source-specific
+** handle for "swarmvtab".
+*/
+#define unionGetDb(pTab, pSrc) ((pTab)->bSwarm ? (pSrc)->db : (pTab)->db)
+
+/*
+** If *pRc is other than SQLITE_OK when this function is called, it
+** always returns NULL. Otherwise, it attempts to allocate and return
+** a pointer to nByte bytes of zeroed memory. If the memory allocation
+** is attempted but fails, NULL is returned and *pRc is set to
+** SQLITE_NOMEM.
+*/
+static void *unionMalloc(int *pRc, size_t nByte){
+ void *pRet;
+ assert( nByte>0 );
+ if( *pRc==SQLITE_OK ){
+ pRet = sqlite3_malloc(nByte);
+ if( pRet ){
+ memset(pRet, 0, (size_t)nByte);
+ }else{
+ *pRc = SQLITE_NOMEM;
+ }
+ }else{
+ pRet = 0;
+ }
+ return pRet;
+}
+
+/*
+** If *pRc is other than SQLITE_OK when this function is called, it
+** always returns NULL. Otherwise, it attempts to allocate and return
+** a copy of the nul-terminated string passed as the second argument.
+** If the allocation is attempted but fails, NULL is returned and *pRc is
+** set to SQLITE_NOMEM.
+*/
+static char *unionStrdup(int *pRc, const char *zIn){
+ char *zRet = 0;
+ if( zIn ){
+ sqlite3_int64 nByte = strlen(zIn) + 1;
+ zRet = unionMalloc(pRc, nByte);
+ if( zRet ){
+ memcpy(zRet, zIn, (size_t)nByte);
+ }
+ }
+ return zRet;
+}
+
+/*
+** If the first character of the string passed as the only argument to this
+** function is one of the 4 that may be used as an open quote character
+** in SQL, this function assumes that the input is a well-formed quoted SQL
+** string. In this case the string is dequoted in place.
+**
+** If the first character of the input is not an open quote, then this
+** function is a no-op.
+*/
+static void unionDequote(char *z){
+ if( z ){
+ char q = z[0];
+
+ /* Set stack variable q to the close-quote character */
+ if( q=='[' || q=='\'' || q=='"' || q=='`' ){
+ int iIn = 1;
+ int iOut = 0;
+ if( q=='[' ) q = ']';
+ while( ALWAYS(z[iIn]) ){
+ if( z[iIn]==q ){
+ if( z[iIn+1]!=q ){
+ /* Character iIn was the close quote. */
+ iIn++;
+ break;
+ }else{
+ /* Character iIn and iIn+1 form an escaped quote character. Skip
+ ** the input cursor past both and copy a single quote character
+ ** to the output buffer. */
+ iIn += 2;
+ z[iOut++] = q;
+ }
+ }else{
+ z[iOut++] = z[iIn++];
+ }
+ }
+ z[iOut] = '\0';
+ }
+ }
+}
+
+/*
+** This function is a no-op if *pRc is set to other than SQLITE_OK when it
+** is called. NULL is returned in this case.
+**
+** Otherwise, the SQL statement passed as the third argument is prepared
+** against the database handle passed as the second. If the statement is
+** successfully prepared, a pointer to the new statement handle is
+** returned. It is the responsibility of the caller to eventually free the
+** statement by calling sqlite3_finalize(). Alternatively, if statement
+** compilation fails, NULL is returned, *pRc is set to an SQLite error
+** code and *pzErr may be set to an error message buffer allocated by
+** sqlite3_malloc().
+*/
+static sqlite3_stmt *unionPrepare(
+ int *pRc, /* IN/OUT: Error code */
+ sqlite3 *db, /* Database handle */
+ const char *zSql, /* SQL statement to prepare */
+ char **pzErr /* OUT: Error message */
+){
+ sqlite3_stmt *pRet = 0;
+ assert( pzErr );
+ if( *pRc==SQLITE_OK ){
+ int rc = sqlite3_prepare_v2(db, zSql, -1, &pRet, 0);
+ if( rc!=SQLITE_OK ){
+ *pzErr = sqlite3_mprintf("sql error: %s", sqlite3_errmsg(db));
+ *pRc = rc;
+ }
+ }
+ return pRet;
+}
+
+/*
+** Like unionPrepare(), except prepare the results of vprintf(zFmt, ...)
+** instead of a constant SQL string.
+*/
+static sqlite3_stmt *unionPreparePrintf(
+ int *pRc, /* IN/OUT: Error code */
+ char **pzErr, /* OUT: Error message */
+ sqlite3 *db, /* Database handle */
+ const char *zFmt, /* printf() format string */
+ ... /* Trailing printf args */
+){
+ sqlite3_stmt *pRet = 0;
+ char *zSql;
+ va_list ap;
+ va_start(ap, zFmt);
+
+ zSql = sqlite3_vmprintf(zFmt, ap);
+ if( *pRc==SQLITE_OK ){
+ if( zSql==0 ){
+ *pRc = SQLITE_NOMEM;
+ }else{
+ pRet = unionPrepare(pRc, db, zSql, pzErr);
+ }
+ }
+ sqlite3_free(zSql);
+
+ va_end(ap);
+ return pRet;
+}
+
+
+/*
+** Call sqlite3_reset() on SQL statement pStmt. If *pRc is set to
+** SQLITE_OK when this function is called, then it is set to the
+** value returned by sqlite3_reset() before this function exits.
+** In this case, *pzErr may be set to point to an error message
+** buffer allocated by sqlite3_malloc().
+*/
+#if 0
+static void unionReset(int *pRc, sqlite3_stmt *pStmt, char **pzErr){
+ int rc = sqlite3_reset(pStmt);
+ if( *pRc==SQLITE_OK ){
+ *pRc = rc;
+ if( rc ){
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(sqlite3_db_handle(pStmt)));
+ }
+ }
+}
+#endif
+
+/*
+** Call sqlite3_finalize() on SQL statement pStmt. If *pRc is set to
+** SQLITE_OK when this function is called, then it is set to the
+** value returned by sqlite3_finalize() before this function exits.
+*/
+static void unionFinalize(int *pRc, sqlite3_stmt *pStmt, char **pzErr){
+ sqlite3 *db = sqlite3_db_handle(pStmt);
+ int rc = sqlite3_finalize(pStmt);
+ if( *pRc==SQLITE_OK ){
+ *pRc = rc;
+ if( rc ){
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ }
+ }
+}
+
+/*
+** If an "openclose" UDF was supplied when this virtual table was created,
+** invoke it now. The first argument passed is the name of the database
+** file for source pSrc. The second is integer value bClose.
+**
+** If successful, return SQLITE_OK. Otherwise an SQLite error code. In this
+** case if argument pzErr is not NULL, also set (*pzErr) to an English
+** language error message. The caller is responsible for eventually freeing
+** any error message using sqlite3_free().
+*/
+static int unionInvokeOpenClose(
+ UnionTab *pTab,
+ UnionSrc *pSrc,
+ int bClose,
+ char **pzErr
+){
+ int rc = SQLITE_OK;
+ if( pTab->pOpenClose ){
+ sqlite3_bind_text(pTab->pOpenClose, 1, pSrc->zFile, -1, SQLITE_STATIC);
+ if( pTab->bHasContext ){
+ sqlite3_bind_text(pTab->pOpenClose, 2, pSrc->zContext, -1, SQLITE_STATIC);
+ }
+ sqlite3_bind_int(pTab->pOpenClose, 2+pTab->bHasContext, bClose);
+ sqlite3_step(pTab->pOpenClose);
+ if( SQLITE_OK!=(rc = sqlite3_reset(pTab->pOpenClose)) ){
+ if( pzErr ){
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db));
+ }
+ }
+ }
+ return rc;
+}
+
+/*
+** This function is a no-op for unionvtab. For swarmvtab, it attempts to
+** close open database files until at most nMax are open. An SQLite error
+** code is returned if an error occurs, or SQLITE_OK otherwise.
+*/
+static void unionCloseSources(UnionTab *pTab, int nMax){
+ while( pTab->pClosable && pTab->nOpen>nMax ){
+ UnionSrc *p;
+ UnionSrc **pp;
+ for(pp=&pTab->pClosable; (*pp)->pNextClosable; pp=&(*pp)->pNextClosable);
+ p = *pp;
+ assert( p->db );
+ sqlite3_close(p->db);
+ p->db = 0;
+ *pp = 0;
+ pTab->nOpen--;
+ unionInvokeOpenClose(pTab, p, 1, 0);
+ }
+}
+
+/*
+** xDisconnect method.
+*/
+static int unionDisconnect(sqlite3_vtab *pVtab){
+ if( pVtab ){
+ UnionTab *pTab = (UnionTab*)pVtab;
+ int i;
+ for(i=0; i<pTab->nSrc; i++){
+ UnionSrc *pSrc = &pTab->aSrc[i];
+ int bHaveSrcDb = (pSrc->db!=0);
+ sqlite3_close(pSrc->db);
+ if( bHaveSrcDb ){
+ unionInvokeOpenClose(pTab, pSrc, 1, 0);
+ }
+ sqlite3_free(pSrc->zDb);
+ sqlite3_free(pSrc->zTab);
+ sqlite3_free(pSrc->zFile);
+ sqlite3_free(pSrc->zContext);
+ }
+ sqlite3_finalize(pTab->pNotFound);
+ sqlite3_finalize(pTab->pOpenClose);
+ sqlite3_free(pTab->zSourceStr);
+ sqlite3_free(pTab->aSrc);
+ sqlite3_free(pTab);
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Check that the table identified by pSrc is a rowid table. If not,
+** return SQLITE_ERROR and set (*pzErr) to point to an English language
+** error message. If the table is a rowid table and no error occurs,
+** return SQLITE_OK and leave (*pzErr) unmodified.
+*/
+static int unionIsIntkeyTable(
+ sqlite3 *db, /* Database handle */
+ UnionSrc *pSrc, /* Source table to test */
+ char **pzErr /* OUT: Error message */
+){
+ int bPk = 0;
+ const char *zType = 0;
+ int rc;
+
+ sqlite3_table_column_metadata(
+ db, pSrc->zDb, pSrc->zTab, "_rowid_", &zType, 0, 0, &bPk, 0
+ );
+ rc = sqlite3_errcode(db);
+ if( rc==SQLITE_ERROR
+ || (rc==SQLITE_OK && (!bPk || sqlite3_stricmp("integer", zType)))
+ ){
+ rc = SQLITE_ERROR;
+ *pzErr = sqlite3_mprintf("no such rowid table: %s%s%s",
+ (pSrc->zDb ? pSrc->zDb : ""),
+ (pSrc->zDb ? "." : ""),
+ pSrc->zTab
+ );
+ }
+ return rc;
+}
+
+/*
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** called. In this case it returns NULL.
+**
+** Otherwise, this function checks that the source table passed as the
+** second argument (a) exists, (b) is not a view and (c) has a column
+** named "_rowid_" of type "integer" that is the primary key.
+** If this is not the case, *pRc is set to SQLITE_ERROR and NULL is
+** returned.
+**
+** Finally, if the source table passes the checks above, a nul-terminated
+** string describing the column names and types belonging to the source
+** table is returned. Tables with the same set of column names and types
+** cause this function to return identical strings. Is is the responsibility
+** of the caller to free the returned string using sqlite3_free() when
+** it is no longer required.
+*/
+static char *unionSourceToStr(
+ int *pRc, /* IN/OUT: Error code */
+ UnionTab *pTab, /* Virtual table object */
+ UnionSrc *pSrc, /* Source table to test */
+ char **pzErr /* OUT: Error message */
+){
+ char *zRet = 0;
+ if( *pRc==SQLITE_OK ){
+ sqlite3 *db = unionGetDb(pTab, pSrc);
+ int rc = unionIsIntkeyTable(db, pSrc, pzErr);
+ sqlite3_stmt *pStmt = unionPrepare(&rc, db,
+ "SELECT group_concat(quote(name) || '.' || quote(type)) "
+ "FROM pragma_table_info(?, ?)", pzErr
+ );
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_text(pStmt, 1, pSrc->zTab, -1, SQLITE_STATIC);
+ sqlite3_bind_text(pStmt, 2, pSrc->zDb, -1, SQLITE_STATIC);
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ const char *z = (const char*)sqlite3_column_text(pStmt, 0);
+ zRet = unionStrdup(&rc, z);
+ }
+ unionFinalize(&rc, pStmt, pzErr);
+ }
+ *pRc = rc;
+ }
+
+ return zRet;
+}
+
+/*
+** Check that all configured source tables exist and have the same column
+** names and datatypes. If this is not the case, or if some other error
+** occurs, return an SQLite error code. In this case *pzErr may be set
+** to point to an error message buffer allocated by sqlite3_mprintf().
+** Or, if no problems regarding the source tables are detected and no
+** other error occurs, SQLITE_OK is returned.
+*/
+static int unionSourceCheck(UnionTab *pTab, char **pzErr){
+ int rc = SQLITE_OK;
+ char *z0 = 0;
+ int i;
+
+ assert( *pzErr==0 );
+ z0 = unionSourceToStr(&rc, pTab, &pTab->aSrc[0], pzErr);
+ for(i=1; i<pTab->nSrc; i++){
+ char *z = unionSourceToStr(&rc, pTab, &pTab->aSrc[i], pzErr);
+ if( rc==SQLITE_OK && sqlite3_stricmp(z, z0) ){
+ *pzErr = sqlite3_mprintf("source table schema mismatch");
+ rc = SQLITE_ERROR;
+ }
+ sqlite3_free(z);
+ }
+ sqlite3_free(z0);
+
+ return rc;
+}
+
+/*
+** Try to open the swarmvtab database. If initially unable, invoke the
+** not-found callback UDF and then try again.
+*/
+static int unionOpenDatabaseInner(UnionTab *pTab, UnionSrc *pSrc, char **pzErr){
+ static const int openFlags = SQLITE_OPEN_READONLY | SQLITE_OPEN_URI;
+ int rc;
+
+ rc = unionInvokeOpenClose(pTab, pSrc, 0, pzErr);
+ if( rc!=SQLITE_OK ) return rc;
+
+ rc = sqlite3_open_v2(pSrc->zFile, &pSrc->db, openFlags, 0);
+ if( rc==SQLITE_OK ) return rc;
+ if( pTab->pNotFound ){
+ sqlite3_close(pSrc->db);
+ pSrc->db = 0;
+ sqlite3_bind_text(pTab->pNotFound, 1, pSrc->zFile, -1, SQLITE_STATIC);
+ if( pTab->bHasContext ){
+ sqlite3_bind_text(pTab->pNotFound, 2, pSrc->zContext, -1, SQLITE_STATIC);
+ }
+ sqlite3_step(pTab->pNotFound);
+ if( SQLITE_OK!=(rc = sqlite3_reset(pTab->pNotFound)) ){
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db));
+ return rc;
+ }
+ rc = sqlite3_open_v2(pSrc->zFile, &pSrc->db, openFlags, 0);
+ }
+ if( rc!=SQLITE_OK ){
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(pSrc->db));
+ }
+ return rc;
+}
+
+/*
+** This function may only be called for swarmvtab tables. The results of
+** calling it on a unionvtab table are undefined.
+**
+** For a swarmvtab table, this function ensures that source database iSrc
+** is open. If the database is opened successfully and the schema is as
+** expected, or if it is already open when this function is called, SQLITE_OK
+** is returned.
+**
+** Alternatively If an error occurs while opening the databases, or if the
+** database schema is unsuitable, an SQLite error code is returned and (*pzErr)
+** may be set to point to an English language error message. In this case it is
+** the responsibility of the caller to eventually free the error message buffer
+** using sqlite3_free().
+*/
+static int unionOpenDatabase(UnionTab *pTab, int iSrc, char **pzErr){
+ int rc = SQLITE_OK;
+ UnionSrc *pSrc = &pTab->aSrc[iSrc];
+
+ assert( pTab->bSwarm && iSrc<pTab->nSrc );
+ if( pSrc->db==0 ){
+ unionCloseSources(pTab, pTab->nMaxOpen-1);
+ rc = unionOpenDatabaseInner(pTab, pSrc, pzErr);
+ if( rc==SQLITE_OK ){
+ char *z = unionSourceToStr(&rc, pTab, pSrc, pzErr);
+ if( rc==SQLITE_OK ){
+ if( pTab->zSourceStr==0 ){
+ pTab->zSourceStr = z;
+ }else{
+ if( sqlite3_stricmp(z, pTab->zSourceStr) ){
+ *pzErr = sqlite3_mprintf("source table schema mismatch");
+ rc = SQLITE_ERROR;
+ }
+ sqlite3_free(z);
+ }
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ pSrc->pNextClosable = pTab->pClosable;
+ pTab->pClosable = pSrc;
+ pTab->nOpen++;
+ }else{
+ sqlite3_close(pSrc->db);
+ pSrc->db = 0;
+ unionInvokeOpenClose(pTab, pSrc, 1, 0);
+ }
+ }
+
+ return rc;
+}
+
+
+/*
+** This function is a no-op for unionvtab tables. For swarmvtab, increment
+** the reference count for source table iTab. If the reference count was
+** zero before it was incremented, also remove the source from the closable
+** list.
+*/
+static void unionIncrRefcount(UnionTab *pTab, int iTab){
+ if( pTab->bSwarm ){
+ UnionSrc *pSrc = &pTab->aSrc[iTab];
+ assert( pSrc->nUser>=0 && pSrc->db );
+ if( pSrc->nUser==0 ){
+ UnionSrc **pp;
+ for(pp=&pTab->pClosable; *pp!=pSrc; pp=&(*pp)->pNextClosable);
+ *pp = pSrc->pNextClosable;
+ pSrc->pNextClosable = 0;
+ }
+ pSrc->nUser++;
+ }
+}
+
+/*
+** Finalize the SQL statement pCsr->pStmt and return the result.
+**
+** If this is a swarmvtab table (not unionvtab) and pCsr->pStmt was not
+** NULL when this function was called, also decrement the reference
+** count on the associated source table. If this means the source tables
+** refcount is now zero, add it to the closable list.
+*/
+static int unionFinalizeCsrStmt(UnionCsr *pCsr){
+ int rc = SQLITE_OK;
+ if( pCsr->pStmt ){
+ UnionTab *pTab = (UnionTab*)pCsr->base.pVtab;
+ UnionSrc *pSrc = &pTab->aSrc[pCsr->iTab];
+ rc = sqlite3_finalize(pCsr->pStmt);
+ pCsr->pStmt = 0;
+ if( pTab->bSwarm ){
+ pSrc->nUser--;
+ assert( pSrc->nUser>=0 );
+ if( pSrc->nUser==0 ){
+ pSrc->pNextClosable = pTab->pClosable;
+ pTab->pClosable = pSrc;
+ }
+ unionCloseSources(pTab, pTab->nMaxOpen);
+ }
+ }
+ return rc;
+}
+
+/*
+** Return true if the argument is a space, tab, CR or LF character.
+*/
+static int union_isspace(char c){
+ return (c==' ' || c=='\n' || c=='\r' || c=='\t');
+}
+
+/*
+** Return true if the argument is an alphanumeric character in the
+** ASCII range.
+*/
+static int union_isidchar(char c){
+ return ((c>='a' && c<='z') || (c>='A' && c<'Z') || (c>='0' && c<='9'));
+}
+
+/*
+** This function is called to handle all arguments following the first
+** (the SQL statement) passed to a swarmvtab (not unionvtab) CREATE
+** VIRTUAL TABLE statement. It may bind parameters to the SQL statement
+** or configure members of the UnionTab object passed as the second
+** argument.
+**
+** Refer to header comments at the top of this file for a description
+** of the arguments parsed.
+**
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** called. Otherwise, if an error occurs, *pRc is set to an SQLite error
+** code. In this case *pzErr may be set to point to a buffer containing
+** an English language error message. It is the responsibility of the
+** caller to eventually free the buffer using sqlite3_free().
+*/
+static void unionConfigureVtab(
+ int *pRc, /* IN/OUT: Error code */
+ UnionTab *pTab, /* Table to configure */
+ sqlite3_stmt *pStmt, /* SQL statement to find sources */
+ int nArg, /* Number of entries in azArg[] array */
+ const char * const *azArg, /* Array of arguments to consider */
+ char **pzErr /* OUT: Error message */
+){
+ int rc = *pRc;
+ int i;
+ if( rc==SQLITE_OK ){
+ pTab->bHasContext = (sqlite3_column_count(pStmt)>4);
+ }
+ for(i=0; rc==SQLITE_OK && i<nArg; i++){
+ char *zArg = unionStrdup(&rc, azArg[i]);
+ if( zArg ){
+ int nOpt = 0; /* Size of option name in bytes */
+ char *zOpt; /* Pointer to option name */
+ char *zVal; /* Pointer to value */
+
+ unionDequote(zArg);
+ zOpt = zArg;
+ while( union_isspace(*zOpt) ) zOpt++;
+ zVal = zOpt;
+ if( *zVal==':' ) zVal++;
+ while( union_isidchar(*zVal) ) zVal++;
+ nOpt = (int)(zVal-zOpt);
+
+ while( union_isspace(*zVal) ) zVal++;
+ if( *zVal=='=' ){
+ zOpt[nOpt] = '\0';
+ zVal++;
+ while( union_isspace(*zVal) ) zVal++;
+ zVal = unionStrdup(&rc, zVal);
+ if( zVal ){
+ unionDequote(zVal);
+ if( zOpt[0]==':' ){
+ /* A value to bind to the SQL statement */
+ int iParam = sqlite3_bind_parameter_index(pStmt, zOpt);
+ if( iParam==0 ){
+ *pzErr = sqlite3_mprintf(
+ "swarmvtab: no such SQL parameter: %s", zOpt
+ );
+ rc = SQLITE_ERROR;
+ }else{
+ rc = sqlite3_bind_text(pStmt, iParam, zVal, -1, SQLITE_TRANSIENT);
+ }
+ }else if( nOpt==7 && 0==sqlite3_strnicmp(zOpt, "maxopen", 7) ){
+ pTab->nMaxOpen = atoi(zVal);
+ if( pTab->nMaxOpen<=0 ){
+ *pzErr = sqlite3_mprintf("swarmvtab: illegal maxopen value");
+ rc = SQLITE_ERROR;
+ }
+ }else if( nOpt==7 && 0==sqlite3_strnicmp(zOpt, "missing", 7) ){
+ if( pTab->pNotFound ){
+ *pzErr = sqlite3_mprintf(
+ "swarmvtab: duplicate \"missing\" option");
+ rc = SQLITE_ERROR;
+ }else{
+ pTab->pNotFound = unionPreparePrintf(&rc, pzErr, pTab->db,
+ "SELECT \"%w\"(?%s)", zVal, pTab->bHasContext ? ",?" : ""
+ );
+ }
+ }else if( nOpt==9 && 0==sqlite3_strnicmp(zOpt, "openclose", 9) ){
+ if( pTab->pOpenClose ){
+ *pzErr = sqlite3_mprintf(
+ "swarmvtab: duplicate \"openclose\" option");
+ rc = SQLITE_ERROR;
+ }else{
+ pTab->pOpenClose = unionPreparePrintf(&rc, pzErr, pTab->db,
+ "SELECT \"%w\"(?,?%s)", zVal, pTab->bHasContext ? ",?" : ""
+ );
+ }
+ }else{
+ *pzErr = sqlite3_mprintf("swarmvtab: unrecognized option: %s",zOpt);
+ rc = SQLITE_ERROR;
+ }
+ sqlite3_free(zVal);
+ }
+ }else{
+ if( i==0 && nArg==1 ){
+ pTab->pNotFound = unionPreparePrintf(&rc, pzErr, pTab->db,
+ "SELECT \"%w\"(?)", zArg
+ );
+ }else{
+ *pzErr = sqlite3_mprintf( "swarmvtab: parse error: %s", azArg[i]);
+ rc = SQLITE_ERROR;
+ }
+ }
+ sqlite3_free(zArg);
+ }
+ }
+ *pRc = rc;
+}
+
+/*
+** xConnect/xCreate method.
+**
+** The argv[] array contains the following:
+**
+** argv[0] -> module name ("unionvtab" or "swarmvtab")
+** argv[1] -> database name
+** argv[2] -> table name
+** argv[3] -> SQL statement
+** argv[4] -> not-found callback UDF name
+*/
+static int unionConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ UnionTab *pTab = 0;
+ int rc = SQLITE_OK;
+ int bSwarm = (pAux==0 ? 0 : 1);
+ const char *zVtab = (bSwarm ? "swarmvtab" : "unionvtab");
+
+ if( sqlite3_stricmp("temp", argv[1]) ){
+ /* unionvtab tables may only be created in the temp schema */
+ *pzErr = sqlite3_mprintf("%s tables must be created in TEMP schema", zVtab);
+ rc = SQLITE_ERROR;
+ }else if( argc<4 || (argc>4 && bSwarm==0) ){
+ *pzErr = sqlite3_mprintf("wrong number of arguments for %s", zVtab);
+ rc = SQLITE_ERROR;
+ }else{
+ int nAlloc = 0; /* Allocated size of pTab->aSrc[] */
+ sqlite3_stmt *pStmt = 0; /* Argument statement */
+ char *zArg = unionStrdup(&rc, argv[3]); /* Copy of argument to CVT */
+
+ /* Prepare the SQL statement. Instead of executing it directly, sort
+ ** the results by the "minimum rowid" field. This makes it easier to
+ ** check that there are no rowid range overlaps between source tables
+ ** and that the UnionTab.aSrc[] array is always sorted by rowid. */
+ unionDequote(zArg);
+ pStmt = unionPreparePrintf(&rc, pzErr, db,
+ "SELECT * FROM (%z) ORDER BY 3", zArg
+ );
+
+ /* Allocate the UnionTab structure */
+ pTab = unionMalloc(&rc, sizeof(UnionTab));
+ if( pTab ){
+ assert( rc==SQLITE_OK );
+ pTab->db = db;
+ pTab->bSwarm = bSwarm;
+ pTab->nMaxOpen = SWARMVTAB_MAX_OPEN;
+ }
+
+ /* Parse other CVT arguments, if any */
+ if( bSwarm ){
+ unionConfigureVtab(&rc, pTab, pStmt, argc-4, &argv[4], pzErr);
+ }
+
+ /* Iterate through the rows returned by the SQL statement specified
+ ** as an argument to the CREATE VIRTUAL TABLE statement. */
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ const char *zDb = (const char*)sqlite3_column_text(pStmt, 0);
+ const char *zTab = (const char*)sqlite3_column_text(pStmt, 1);
+ sqlite3_int64 iMin = sqlite3_column_int64(pStmt, 2);
+ sqlite3_int64 iMax = sqlite3_column_int64(pStmt, 3);
+ UnionSrc *pSrc;
+
+ /* Grow the pTab->aSrc[] array if required. */
+ if( nAlloc<=pTab->nSrc ){
+ int nNew = nAlloc ? nAlloc*2 : 8;
+ UnionSrc *aNew = (UnionSrc*)sqlite3_realloc64(
+ pTab->aSrc, nNew*sizeof(UnionSrc)
+ );
+ if( aNew==0 ){
+ rc = SQLITE_NOMEM;
+ break;
+ }else{
+ memset(&aNew[pTab->nSrc], 0, (nNew-pTab->nSrc)*sizeof(UnionSrc));
+ pTab->aSrc = aNew;
+ nAlloc = nNew;
+ }
+ }
+
+ /* Check for problems with the specified range of rowids */
+ if( iMax<iMin || (pTab->nSrc>0 && iMin<=pTab->aSrc[pTab->nSrc-1].iMax) ){
+ *pzErr = sqlite3_mprintf("rowid range mismatch error");
+ rc = SQLITE_ERROR;
+ }
+
+ if( rc==SQLITE_OK ){
+ pSrc = &pTab->aSrc[pTab->nSrc++];
+ pSrc->zTab = unionStrdup(&rc, zTab);
+ pSrc->iMin = iMin;
+ pSrc->iMax = iMax;
+ if( bSwarm ){
+ pSrc->zFile = unionStrdup(&rc, zDb);
+ }else{
+ pSrc->zDb = unionStrdup(&rc, zDb);
+ }
+ if( pTab->bHasContext ){
+ const char *zContext = (const char*)sqlite3_column_text(pStmt, 4);
+ pSrc->zContext = unionStrdup(&rc, zContext);
+ }
+ }
+ }
+ unionFinalize(&rc, pStmt, pzErr);
+ pStmt = 0;
+
+ /* It is an error if the SELECT statement returned zero rows. If only
+ ** because there is no way to determine the schema of the virtual
+ ** table in this case. */
+ if( rc==SQLITE_OK && pTab->nSrc==0 ){
+ *pzErr = sqlite3_mprintf("no source tables configured");
+ rc = SQLITE_ERROR;
+ }
+
+ /* For unionvtab, verify that all source tables exist and have
+ ** compatible schemas. For swarmvtab, attach the first database and
+ ** check that the first table is a rowid table only. */
+ if( rc==SQLITE_OK ){
+ if( bSwarm ){
+ rc = unionOpenDatabase(pTab, 0, pzErr);
+ }else{
+ rc = unionSourceCheck(pTab, pzErr);
+ }
+ }
+
+ /* Compose a CREATE TABLE statement and pass it to declare_vtab() */
+ if( rc==SQLITE_OK ){
+ UnionSrc *pSrc = &pTab->aSrc[0];
+ sqlite3 *tdb = unionGetDb(pTab, pSrc);
+ pStmt = unionPreparePrintf(&rc, pzErr, tdb, "SELECT "
+ "'CREATE TABLE xyz('"
+ " || group_concat(quote(name) || ' ' || type, ', ')"
+ " || ')',"
+ "max((cid+1) * (type='INTEGER' COLLATE nocase AND pk=1))-1 "
+ "FROM pragma_table_info(%Q, ?)",
+ pSrc->zTab, pSrc->zDb
+ );
+ }
+ if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ const char *zDecl = (const char*)sqlite3_column_text(pStmt, 0);
+ rc = sqlite3_declare_vtab(db, zDecl);
+ pTab->iPK = sqlite3_column_int(pStmt, 1);
+ }
+
+ unionFinalize(&rc, pStmt, pzErr);
+ }
+
+ if( rc!=SQLITE_OK ){
+ unionDisconnect((sqlite3_vtab*)pTab);
+ pTab = 0;
+ }
+
+ *ppVtab = (sqlite3_vtab*)pTab;
+ return rc;
+}
+
+/*
+** xOpen
+*/
+static int unionOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ UnionCsr *pCsr;
+ int rc = SQLITE_OK;
+ (void)p; /* Suppress harmless warning */
+ pCsr = (UnionCsr*)unionMalloc(&rc, sizeof(UnionCsr));
+ *ppCursor = &pCsr->base;
+ return rc;
+}
+
+/*
+** xClose
+*/
+static int unionClose(sqlite3_vtab_cursor *cur){
+ UnionCsr *pCsr = (UnionCsr*)cur;
+ unionFinalizeCsrStmt(pCsr);
+ sqlite3_free(pCsr);
+ return SQLITE_OK;
+}
+
+/*
+** This function does the work of the xNext() method. Except that, if it
+** returns SQLITE_ROW, it should be called again within the same xNext()
+** method call. See unionNext() for details.
+*/
+static int doUnionNext(UnionCsr *pCsr){
+ int rc = SQLITE_OK;
+ assert( pCsr->pStmt );
+ if( sqlite3_step(pCsr->pStmt)!=SQLITE_ROW ){
+ UnionTab *pTab = (UnionTab*)pCsr->base.pVtab;
+ rc = unionFinalizeCsrStmt(pCsr);
+ if( rc==SQLITE_OK && pTab->bSwarm ){
+ pCsr->iTab++;
+ if( pCsr->iTab<pTab->nSrc ){
+ UnionSrc *pSrc = &pTab->aSrc[pCsr->iTab];
+ if( pCsr->iMaxRowid>=pSrc->iMin ){
+ /* It is necessary to scan the next table. */
+ rc = unionOpenDatabase(pTab, pCsr->iTab, &pTab->base.zErrMsg);
+ pCsr->pStmt = unionPreparePrintf(&rc, &pTab->base.zErrMsg, pSrc->db,
+ "SELECT rowid, * FROM %Q %s %lld",
+ pSrc->zTab,
+ (pSrc->iMax>pCsr->iMaxRowid ? "WHERE _rowid_ <=" : "-- "),
+ pCsr->iMaxRowid
+ );
+ if( rc==SQLITE_OK ){
+ assert( pCsr->pStmt );
+ unionIncrRefcount(pTab, pCsr->iTab);
+ rc = SQLITE_ROW;
+ }
+ }
+ }
+ }
+ }
+
+ return rc;
+}
+
+/*
+** xNext
+*/
+static int unionNext(sqlite3_vtab_cursor *cur){
+ int rc;
+ do {
+ rc = doUnionNext((UnionCsr*)cur);
+ }while( rc==SQLITE_ROW );
+ return rc;
+}
+
+/*
+** xColumn
+*/
+static int unionColumn(
+ sqlite3_vtab_cursor *cur,
+ sqlite3_context *ctx,
+ int i
+){
+ UnionCsr *pCsr = (UnionCsr*)cur;
+ sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pStmt, i+1));
+ return SQLITE_OK;
+}
+
+/*
+** xRowid
+*/
+static int unionRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ UnionCsr *pCsr = (UnionCsr*)cur;
+ *pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
+ return SQLITE_OK;
+}
+
+/*
+** xEof
+*/
+static int unionEof(sqlite3_vtab_cursor *cur){
+ UnionCsr *pCsr = (UnionCsr*)cur;
+ return pCsr->pStmt==0;
+}
+
+/*
+** xFilter
+*/
+static int unionFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ UnionTab *pTab = (UnionTab*)(pVtabCursor->pVtab);
+ UnionCsr *pCsr = (UnionCsr*)pVtabCursor;
+ int rc = SQLITE_OK;
+ int i;
+ char *zSql = 0;
+ int bZero = 0;
+
+ sqlite3_int64 iMin = SMALLEST_INT64;
+ sqlite3_int64 iMax = LARGEST_INT64;
+
+ assert( idxNum==0
+ || idxNum==SQLITE_INDEX_CONSTRAINT_EQ
+ || idxNum==SQLITE_INDEX_CONSTRAINT_LE
+ || idxNum==SQLITE_INDEX_CONSTRAINT_GE
+ || idxNum==SQLITE_INDEX_CONSTRAINT_LT
+ || idxNum==SQLITE_INDEX_CONSTRAINT_GT
+ || idxNum==(SQLITE_INDEX_CONSTRAINT_GE|SQLITE_INDEX_CONSTRAINT_LE)
+ );
+
+ (void)idxStr; /* Suppress harmless warning */
+
+ if( idxNum==SQLITE_INDEX_CONSTRAINT_EQ ){
+ assert( argc==1 );
+ iMin = iMax = sqlite3_value_int64(argv[0]);
+ }else{
+
+ if( idxNum & (SQLITE_INDEX_CONSTRAINT_LE|SQLITE_INDEX_CONSTRAINT_LT) ){
+ assert( argc>=1 );
+ iMax = sqlite3_value_int64(argv[0]);
+ if( idxNum & SQLITE_INDEX_CONSTRAINT_LT ){
+ if( iMax==SMALLEST_INT64 ){
+ bZero = 1;
+ }else{
+ iMax--;
+ }
+ }
+ }
+
+ if( idxNum & (SQLITE_INDEX_CONSTRAINT_GE|SQLITE_INDEX_CONSTRAINT_GT) ){
+ assert( argc>=1 );
+ iMin = sqlite3_value_int64(argv[argc-1]);
+ if( idxNum & SQLITE_INDEX_CONSTRAINT_GT ){
+ if( iMin==LARGEST_INT64 ){
+ bZero = 1;
+ }else{
+ iMin++;
+ }
+ }
+ }
+ }
+
+ unionFinalizeCsrStmt(pCsr);
+ if( bZero ){
+ return SQLITE_OK;
+ }
+
+ for(i=0; i<pTab->nSrc; i++){
+ UnionSrc *pSrc = &pTab->aSrc[i];
+ if( iMin>pSrc->iMax || iMax<pSrc->iMin ){
+ continue;
+ }
+
+ zSql = sqlite3_mprintf("%z%sSELECT rowid, * FROM %s%q%s%Q"
+ , zSql
+ , (zSql ? " UNION ALL " : "")
+ , (pSrc->zDb ? "'" : "")
+ , (pSrc->zDb ? pSrc->zDb : "")
+ , (pSrc->zDb ? "'." : "")
+ , pSrc->zTab
+ );
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ break;
+ }
+
+ if( iMin==iMax ){
+ zSql = sqlite3_mprintf("%z WHERE rowid=%lld", zSql, iMin);
+ }else{
+ const char *zWhere = "WHERE";
+ if( iMin!=SMALLEST_INT64 && iMin>pSrc->iMin ){
+ zSql = sqlite3_mprintf("%z WHERE rowid>=%lld", zSql, iMin);
+ zWhere = "AND";
+ }
+ if( iMax!=LARGEST_INT64 && iMax<pSrc->iMax ){
+ zSql = sqlite3_mprintf("%z %s rowid<=%lld", zSql, zWhere, iMax);
+ }
+ }
+
+ if( pTab->bSwarm ){
+ pCsr->iTab = i;
+ pCsr->iMaxRowid = iMax;
+ rc = unionOpenDatabase(pTab, i, &pTab->base.zErrMsg);
+ break;
+ }
+ }
+
+ if( zSql==0 ){
+ return rc;
+ }else{
+ sqlite3 *db = unionGetDb(pTab, &pTab->aSrc[pCsr->iTab]);
+ pCsr->pStmt = unionPrepare(&rc, db, zSql, &pTab->base.zErrMsg);
+ if( pCsr->pStmt ){
+ unionIncrRefcount(pTab, pCsr->iTab);
+ }
+ sqlite3_free(zSql);
+ }
+ if( rc!=SQLITE_OK ) return rc;
+ return unionNext(pVtabCursor);
+}
+
+/*
+** xBestIndex.
+**
+** This implementation searches for constraints on the rowid field. EQ,
+** LE, LT, GE and GT are handled.
+**
+** If there is an EQ comparison, then idxNum is set to INDEX_CONSTRAINT_EQ.
+** In this case the only argument passed to xFilter is the rhs of the ==
+** operator.
+**
+** Otherwise, if an LE or LT constraint is found, then the INDEX_CONSTRAINT_LE
+** or INDEX_CONSTRAINT_LT (but not both) bit is set in idxNum. The first
+** argument to xFilter is the rhs of the <= or < operator. Similarly, if
+** an GE or GT constraint is found, then the INDEX_CONSTRAINT_GE or
+** INDEX_CONSTRAINT_GT bit is set in idxNum. The rhs of the >= or > operator
+** is passed as either the first or second argument to xFilter, depending
+** on whether or not there is also a LT|LE constraint.
+*/
+static int unionBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ UnionTab *pTab = (UnionTab*)tab;
+ int iEq = -1;
+ int iLt = -1;
+ int iGt = -1;
+ int i;
+
+ for(i=0; i<pIdxInfo->nConstraint; i++){
+ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
+ if( p->usable && (p->iColumn<0 || p->iColumn==pTab->iPK) ){
+ switch( p->op ){
+ case SQLITE_INDEX_CONSTRAINT_EQ:
+ iEq = i;
+ break;
+ case SQLITE_INDEX_CONSTRAINT_LE:
+ case SQLITE_INDEX_CONSTRAINT_LT:
+ iLt = i;
+ break;
+ case SQLITE_INDEX_CONSTRAINT_GE:
+ case SQLITE_INDEX_CONSTRAINT_GT:
+ iGt = i;
+ break;
+ }
+ }
+ }
+
+ if( iEq>=0 ){
+ pIdxInfo->estimatedRows = 1;
+ pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
+ pIdxInfo->estimatedCost = 3.0;
+ pIdxInfo->idxNum = SQLITE_INDEX_CONSTRAINT_EQ;
+ pIdxInfo->aConstraintUsage[iEq].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[iEq].omit = 1;
+ }else{
+ int iCons = 1;
+ int idxNum = 0;
+ sqlite3_int64 nRow = 1000000;
+ if( iLt>=0 ){
+ nRow = nRow / 2;
+ pIdxInfo->aConstraintUsage[iLt].argvIndex = iCons++;
+ pIdxInfo->aConstraintUsage[iLt].omit = 1;
+ idxNum |= pIdxInfo->aConstraint[iLt].op;
+ }
+ if( iGt>=0 ){
+ nRow = nRow / 2;
+ pIdxInfo->aConstraintUsage[iGt].argvIndex = iCons++;
+ pIdxInfo->aConstraintUsage[iGt].omit = 1;
+ idxNum |= pIdxInfo->aConstraint[iGt].op;
+ }
+ pIdxInfo->estimatedRows = nRow;
+ pIdxInfo->estimatedCost = 3.0 * (double)nRow;
+ pIdxInfo->idxNum = idxNum;
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Register the unionvtab virtual table module with database handle db.
+*/
+static int createUnionVtab(sqlite3 *db){
+ static const sqlite3_module unionModule = {
+ 0, /* iVersion */
+ unionConnect,
+ unionConnect,
+ unionBestIndex, /* xBestIndex - query planner */
+ unionDisconnect,
+ unionDisconnect,
+ unionOpen, /* xOpen - open a cursor */
+ unionClose, /* xClose - close a cursor */
+ unionFilter, /* xFilter - configure scan constraints */
+ unionNext, /* xNext - advance a cursor */
+ unionEof, /* xEof - check for end of scan */
+ unionColumn, /* xColumn - read data */
+ unionRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
+ };
+ int rc;
+
+ rc = sqlite3_create_module(db, "unionvtab", &unionModule, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_module(db, "swarmvtab", &unionModule, (void*)db);
+ }
+ return rc;
+}
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_unionvtab_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Suppress harmless warning */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = createUnionVtab(db);
+#endif
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ return sqlite3_unionvtab_init(db, pzErrMsg, pApi);
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/vfslog.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/vfslog.c 2019-10-08 13:42:19.243313400 +0200
@@ -0,0 +1,854 @@
+/*
+** 2013-10-09
+**
+** 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 the implementation of an SQLite vfs wrapper for
+** unix that generates per-database log files of all disk activity.
+*/
+
+/*
+** This module contains code for a wrapper VFS that causes a log of
+** most VFS calls to be written into a file on disk.
+**
+** Each database connection creates a separate log file in the same
+** directory as the original database and named after the original
+** database. A unique suffix is added to avoid name collisions.
+** Separate log files are used so that concurrent processes do not
+** try to write log operations to the same file at the same instant,
+** resulting in overwritten or comingled log text.
+**
+** Each individual log file records operations by a single database
+** connection on both the original database and its associated rollback
+** journal.
+**
+** The log files are in the comma-separated-value (CSV) format. The
+** log files can be imported into an SQLite database using the ".import"
+** command of the SQLite command-line shell for analysis.
+**
+** One technique for using this module is to append the text of this
+** module to the end of a standard "sqlite3.c" amalgamation file then
+** add the following compile-time options:
+**
+** -DSQLITE_EXTRA_INIT=sqlite3_register_vfslog
+** -DSQLITE_USE_FCNTL_TRACE
+**
+** The first compile-time option causes the sqlite3_register_vfslog()
+** function, defined below, to be invoked when SQLite is initialized.
+** That causes this custom VFS to become the default VFS for all
+** subsequent connections. The SQLITE_USE_FCNTL_TRACE option causes
+** the SQLite core to issue extra sqlite3_file_control() operations
+** with SQLITE_FCNTL_TRACE to give some indication of what is going
+** on in the core.
+*/
+
+#include "sqlite3.h"
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#if SQLITE_OS_UNIX
+# include <unistd.h>
+#endif
+
+/*
+** Forward declaration of objects used by this utility
+*/
+typedef struct VLogLog VLogLog;
+typedef struct VLogVfs VLogVfs;
+typedef struct VLogFile VLogFile;
+
+/* There is a pair (an array of size 2) of the following objects for
+** each database file being logged. The first contains the filename
+** and is used to log I/O with the main database. The second has
+** a NULL filename and is used to log I/O for the journal. Both
+** out pointers are the same.
+*/
+struct VLogLog {
+ VLogLog *pNext; /* Next in a list of all active logs */
+ VLogLog **ppPrev; /* Pointer to this in the list */
+ int nRef; /* Number of references to this object */
+ int nFilename; /* Length of zFilename in bytes */
+ char *zFilename; /* Name of database file. NULL for journal */
+ FILE *out; /* Write information here */
+};
+
+struct VLogVfs {
+ sqlite3_vfs base; /* VFS methods */
+ sqlite3_vfs *pVfs; /* Parent VFS */
+};
+
+struct VLogFile {
+ sqlite3_file base; /* IO methods */
+ sqlite3_file *pReal; /* Underlying file handle */
+ VLogLog *pLog; /* The log file for this file */
+};
+
+#define REALVFS(p) (((VLogVfs*)(p))->pVfs)
+
+/*
+** Methods for VLogFile
+*/
+static int vlogClose(sqlite3_file*);
+static int vlogRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
+static int vlogWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
+static int vlogTruncate(sqlite3_file*, sqlite3_int64 size);
+static int vlogSync(sqlite3_file*, int flags);
+static int vlogFileSize(sqlite3_file*, sqlite3_int64 *pSize);
+static int vlogLock(sqlite3_file*, int);
+static int vlogUnlock(sqlite3_file*, int);
+static int vlogCheckReservedLock(sqlite3_file*, int *pResOut);
+static int vlogFileControl(sqlite3_file*, int op, void *pArg);
+static int vlogSectorSize(sqlite3_file*);
+static int vlogDeviceCharacteristics(sqlite3_file*);
+static int vlogShmMap(sqlite3_file*,int,int,int, void volatile **);
+static int vlogShmLock(sqlite3_file*, int , int, int);
+static void vlogShmBarrier(sqlite3_file*);
+static int vlogShmUnmap(sqlite3_file*, int);
+static int vlogFetch(sqlite3_file*, sqlite3_int64, int, void**);
+static int vlogUnfetch(sqlite3_file*, sqlite3_int64, void*);
+
+/*
+** Methods for VLogVfs
+*/
+static int vlogOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
+static int vlogDelete(sqlite3_vfs*, const char *zName, int syncDir);
+static int vlogAccess(sqlite3_vfs*, const char *zName, int flags, int *);
+static int vlogFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
+static void *vlogDlOpen(sqlite3_vfs*, const char *zFilename);
+static void vlogDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
+static void (*vlogDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
+static void vlogDlClose(sqlite3_vfs*, void*);
+static int vlogRandomness(sqlite3_vfs*, int nByte, char *zOut);
+static int vlogSleep(sqlite3_vfs*, int microseconds);
+static int vlogCurrentTime(sqlite3_vfs*, double*);
+static int vlogGetLastError(sqlite3_vfs*, int, char *);
+static int vlogCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
+static int vlogSetSystemCall(sqlite3_vfs*, const char *, sqlite3_syscall_ptr);
+static sqlite3_syscall_ptr vlogGetSystemCall(sqlite3_vfs *, const char *);
+static const char *vlogNextSystemCall(sqlite3_vfs *, const char *);
+
+
+static VLogVfs vlog_vfs = {
+ {
+ 0, /* iVersion (set by register_vlog()) */
+ 0, /* szOsFile (set by register_vlog()) */
+ 0, /* mxPathname (set by register_vlog()) */
+ 0, /* pNext */
+ "vfslog", /* zName */
+ 0, /* pAppData */
+ vlogOpen, /* xOpen */
+ vlogDelete, /* xDelete */
+ vlogAccess, /* xAccess */
+ vlogFullPathname, /* xFullPathname */
+ vlogDlOpen, /* xDlOpen */
+ vlogDlError, /* xDlError */
+ vlogDlSym, /* xDlSym */
+ vlogDlClose, /* xDlClose */
+ vlogRandomness, /* xRandomness */
+ vlogSleep, /* xSleep */
+ vlogCurrentTime, /* xCurrentTime */
+ vlogGetLastError, /* xGetLastError */
+ vlogCurrentTimeInt64, /* xCurrentTimeInt64 */
+ vlogSetSystemCall, /* xSetSystemCall */
+ vlogGetSystemCall, /* xGetSystemCall */
+ vlogNextSystemCall /* xNextSystemCall */
+ },
+ 0
+};
+
+static sqlite3_io_methods vlog_io_methods = {
+ 3, /* iVersion */
+ vlogClose, /* xClose */
+ vlogRead, /* xRead */
+ vlogWrite, /* xWrite */
+ vlogTruncate, /* xTruncate */
+ vlogSync, /* xSync */
+ vlogFileSize, /* xFileSize */
+ vlogLock, /* xLock */
+ vlogUnlock, /* xUnlock */
+ vlogCheckReservedLock, /* xCheckReservedLock */
+ vlogFileControl, /* xFileControl */
+ vlogSectorSize, /* xSectorSize */
+ vlogDeviceCharacteristics, /* xDeviceCharacteristics */
+ vlogShmMap, /* xShmMap */
+ vlogShmLock, /* xShmLock */
+ vlogShmBarrier, /* xShmBarrier */
+ vlogShmUnmap, /* xShmUnmap */
+ vlogFetch, /* xFetch */
+ vlogUnfetch /* xUnfecth */
+};
+
+#ifdef _WIN32
+#include <windows.h>
+#include <time.h>
+static sqlite3_uint64 vlog_time(){
+ FILETIME ft;
+ sqlite3_uint64 u64time = 0;
+
+ GetSystemTimeAsFileTime(&ft);
+
+ u64time |= ft.dwHighDateTime;
+ u64time <<= 32;
+ u64time |= ft.dwLowDateTime;
+
+ /* ft is 100-nanosecond intervals, we want microseconds */
+ return u64time /(sqlite3_uint64)10;
+}
+#elif SQLITE_OS_UNIX && !defined(NO_GETTOD)
+#include <sys/time.h>
+static sqlite3_uint64 vlog_time(){
+ struct timeval sTime;
+ gettimeofday(&sTime, 0);
+ return sTime.tv_usec + (sqlite3_uint64)sTime.tv_sec * 1000000;
+}
+#else
+static sqlite3_uint64 vlog_time(){
+ return 0;
+}
+#endif
+
+
+/*
+** Write a message to the log file
+*/
+static void vlogLogPrint(
+ VLogLog *pLog, /* The log file to write into */
+ sqlite3_int64 tStart, /* Start time of system call */
+ sqlite3_int64 tElapse, /* Elapse time of system call */
+ const char *zOp, /* Type of system call */
+ sqlite3_int64 iArg1, /* First argument */
+ sqlite3_int64 iArg2, /* Second argument */
+ const char *zArg3, /* Third argument */
+ int iRes /* Result */
+){
+ char z1[40], z2[40], z3[2000], zStart[40], zElapse[40];
+ if( pLog==0 ) return;
+ if( iArg1>=0 ){
+ sqlite3_snprintf(sizeof(z1), z1, "%lld", iArg1);
+ }else{
+ z1[0] = 0;
+ }
+ if( iArg2>=0 ){
+ sqlite3_snprintf(sizeof(z2), z2, "%lld", iArg2);
+ }else{
+ z2[0] = 0;
+ }
+ if( zArg3 ){
+ sqlite3_snprintf(sizeof(z3), z3, "\"%.*w\"", sizeof(z3)-4, zArg3);
+ }else{
+ z3[0] = 0;
+ }
+ sqlite3_snprintf(sizeof(zStart), zStart, "%lld", tStart);
+ sqlite3_snprintf(sizeof(zElapse), zElapse, "%lld", tElapse);
+ fprintf(pLog->out,"%s,%s,%s,%d,%s,%s,%s,%d\n",
+ zStart, zElapse, zOp, pLog->zFilename==0, z1, z2, z3, iRes);
+}
+
+/*
+** List of all active log connections. Protected by the master mutex.
+*/
+static VLogLog *allLogs = 0;
+
+/*
+** Close a VLogLog object
+*/
+static void vlogLogClose(VLogLog *p){
+ if( p ){
+ sqlite3_mutex *pMutex;
+ p->nRef--;
+ if( p->nRef>0 || p->zFilename==0 ) return;
+ pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex_enter(pMutex);
+ *p->ppPrev = p->pNext;
+ if( p->pNext ) p->pNext->ppPrev = p->ppPrev;
+ sqlite3_mutex_leave(pMutex);
+ fclose(p->out);
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Open a VLogLog object on the given file
+*/
+static VLogLog *vlogLogOpen(const char *zFilename){
+ int nName = (int)strlen(zFilename);
+ int isJournal = 0;
+ sqlite3_mutex *pMutex;
+ VLogLog *pLog, *pTemp;
+ sqlite3_int64 tNow = 0;
+ if( nName>4 && strcmp(zFilename+nName-4,"-wal")==0 ){
+ return 0; /* Do not log wal files */
+ }else
+ if( nName>8 && strcmp(zFilename+nName-8,"-journal")==0 ){
+ nName -= 8;
+ isJournal = 1;
+ }else if( nName>12
+ && sqlite3_strglob("-mj??????9??", zFilename+nName-12)==0 ){
+ return 0; /* Do not log master journal files */
+ }
+ pTemp = sqlite3_malloc( sizeof(*pLog)*2 + nName + 60 );
+ if( pTemp==0 ) return 0;
+ pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex_enter(pMutex);
+ for(pLog=allLogs; pLog; pLog=pLog->pNext){
+ if( pLog->nFilename==nName && !memcmp(pLog->zFilename, zFilename, nName) ){
+ break;
+ }
+ }
+ if( pLog==0 ){
+ pLog = pTemp;
+ pTemp = 0;
+ memset(pLog, 0, sizeof(*pLog)*2);
+ pLog->zFilename = (char*)&pLog[2];
+ tNow = vlog_time();
+ sqlite3_snprintf(nName+60, pLog->zFilename, "%.*s-debuglog-%lld",
+ nName, zFilename, tNow);
+ pLog->out = fopen(pLog->zFilename, "a");
+ if( pLog->out==0 ){
+ sqlite3_mutex_leave(pMutex);
+ sqlite3_free(pLog);
+ return 0;
+ }
+ pLog->nFilename = nName;
+ pLog[1].out = pLog[0].out;
+ pLog->ppPrev = &allLogs;
+ if( allLogs ) allLogs->ppPrev = &pLog->pNext;
+ pLog->pNext = allLogs;
+ allLogs = pLog;
+ }
+ sqlite3_mutex_leave(pMutex);
+ if( pTemp ){
+ sqlite3_free(pTemp);
+ }else{
+#if SQLITE_OS_UNIX || defined(__CYGWIN__)
+ char zHost[200];
+ zHost[0] = 0;
+ gethostname(zHost, sizeof(zHost)-1);
+ zHost[sizeof(zHost)-1] = 0;
+ vlogLogPrint(pLog, tNow, 0, "IDENT", getpid(), -1, zHost, 0);
+#endif
+ }
+ if( pLog && isJournal ) pLog++;
+ pLog->nRef++;
+ return pLog;
+}
+
+
+/*
+** Close an vlog-file.
+*/
+static int vlogClose(sqlite3_file *pFile){
+ sqlite3_uint64 tStart, tElapse;
+ int rc = SQLITE_OK;
+ VLogFile *p = (VLogFile *)pFile;
+
+ tStart = vlog_time();
+ if( p->pReal->pMethods ){
+ rc = p->pReal->pMethods->xClose(p->pReal);
+ }
+ tElapse = vlog_time() - tStart;
+ vlogLogPrint(p->pLog, tStart, tElapse, "CLOSE", -1, -1, 0, rc);
+ vlogLogClose(p->pLog);
+ return rc;
+}
+
+/*
+** Compute signature for a block of content.
+**
+** For blocks of 16 or fewer bytes, the signature is just a hex dump of
+** the entire block.
+**
+** For blocks of more than 16 bytes, the signature is a hex dump of the
+** first 8 bytes followed by a 64-bit has of the entire block.
+*/
+static void vlogSignature(unsigned char *p, int n, char *zCksum){
+ unsigned int s0 = 0, s1 = 0;
+ unsigned int *pI;
+ int i;
+ if( n<=16 ){
+ for(i=0; i<n; i++) sqlite3_snprintf(3, zCksum+i*2, "%02x", p[i]);
+ }else{
+ pI = (unsigned int*)p;
+ for(i=0; i<n-7; i+=8){
+ s0 += pI[0] + s1;
+ s1 += pI[1] + s0;
+ pI += 2;
+ }
+ for(i=0; i<8; i++) sqlite3_snprintf(3, zCksum+i*2, "%02x", p[i]);
+ sqlite3_snprintf(18, zCksum+i*2, "-%08x%08x", s0, s1);
+ }
+}
+
+/*
+** Convert a big-endian 32-bit integer into a native integer
+*/
+static int bigToNative(const unsigned char *x){
+ return (x[0]<<24) + (x[1]<<16) + (x[2]<<8) + x[3];
+}
+
+/*
+** Read data from an vlog-file.
+*/
+static int vlogRead(
+ sqlite3_file *pFile,
+ void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ int rc;
+ sqlite3_uint64 tStart, tElapse;
+ VLogFile *p = (VLogFile *)pFile;
+ char zSig[40];
+
+ tStart = vlog_time();
+ rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
+ tElapse = vlog_time() - tStart;
+ if( rc==SQLITE_OK ){
+ vlogSignature(zBuf, iAmt, zSig);
+ }else{
+ zSig[0] = 0;
+ }
+ vlogLogPrint(p->pLog, tStart, tElapse, "READ", iAmt, iOfst, zSig, rc);
+ if( rc==SQLITE_OK
+ && p->pLog
+ && p->pLog->zFilename
+ && iOfst<=24
+ && iOfst+iAmt>=28
+ ){
+ unsigned char *x = ((unsigned char*)zBuf)+(24-iOfst);
+ unsigned iCtr, nFree = -1;
+ char *zFree = 0;
+ char zStr[12];
+ iCtr = bigToNative(x);
+ if( iOfst+iAmt>=40 ){
+ zFree = zStr;
+ sqlite3_snprintf(sizeof(zStr), zStr, "%d", bigToNative(x+8));
+ nFree = bigToNative(x+12);
+ }
+ vlogLogPrint(p->pLog, tStart, 0, "CHNGCTR-READ", iCtr, nFree, zFree, 0);
+ }
+ return rc;
+}
+
+/*
+** Write data to an vlog-file.
+*/
+static int vlogWrite(
+ sqlite3_file *pFile,
+ const void *z,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ int rc;
+ sqlite3_uint64 tStart, tElapse;
+ VLogFile *p = (VLogFile *)pFile;
+ char zSig[40];
+
+ tStart = vlog_time();
+ vlogSignature((unsigned char*)z, iAmt, zSig);
+ rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst);
+ tElapse = vlog_time() - tStart;
+ vlogLogPrint(p->pLog, tStart, tElapse, "WRITE", iAmt, iOfst, zSig, rc);
+ if( rc==SQLITE_OK
+ && p->pLog
+ && p->pLog->zFilename
+ && iOfst<=24
+ && iOfst+iAmt>=28
+ ){
+ unsigned char *x = ((unsigned char*)z)+(24-iOfst);
+ unsigned iCtr, nFree = -1;
+ char *zFree = 0;
+ char zStr[12];
+ iCtr = bigToNative(x);
+ if( iOfst+iAmt>=40 ){
+ zFree = zStr;
+ sqlite3_snprintf(sizeof(zStr), zStr, "%d", bigToNative(x+8));
+ nFree = bigToNative(x+12);
+ }
+ vlogLogPrint(p->pLog, tStart, 0, "CHNGCTR-WRITE", iCtr, nFree, zFree, 0);
+ }
+ return rc;
+}
+
+/*
+** Truncate an vlog-file.
+*/
+static int vlogTruncate(sqlite3_file *pFile, sqlite_int64 size){
+ int rc;
+ sqlite3_uint64 tStart, tElapse;
+ VLogFile *p = (VLogFile *)pFile;
+ tStart = vlog_time();
+ rc = p->pReal->pMethods->xTruncate(p->pReal, size);
+ tElapse = vlog_time() - tStart;
+ vlogLogPrint(p->pLog, tStart, tElapse, "TRUNCATE", size, -1, 0, rc);
+ return rc;
+}
+
+/*
+** Sync an vlog-file.
+*/
+static int vlogSync(sqlite3_file *pFile, int flags){
+ int rc;
+ sqlite3_uint64 tStart, tElapse;
+ VLogFile *p = (VLogFile *)pFile;
+ tStart = vlog_time();
+ rc = p->pReal->pMethods->xSync(p->pReal, flags);
+ tElapse = vlog_time() - tStart;
+ vlogLogPrint(p->pLog, tStart, tElapse, "SYNC", flags, -1, 0, rc);
+ return rc;
+}
+
+/*
+** Return the current file-size of an vlog-file.
+*/
+static int vlogFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
+ int rc;
+ sqlite3_uint64 tStart, tElapse;
+ VLogFile *p = (VLogFile *)pFile;
+ tStart = vlog_time();
+ rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
+ tElapse = vlog_time() - tStart;
+ vlogLogPrint(p->pLog, tStart, tElapse, "FILESIZE", *pSize, -1, 0, rc);
+ return rc;
+}
+
+/*
+** Lock an vlog-file.
+*/
+static int vlogLock(sqlite3_file *pFile, int eLock){
+ int rc;
+ sqlite3_uint64 tStart, tElapse;
+ VLogFile *p = (VLogFile *)pFile;
+ tStart = vlog_time();
+ rc = p->pReal->pMethods->xLock(p->pReal, eLock);
+ tElapse = vlog_time() - tStart;
+ vlogLogPrint(p->pLog, tStart, tElapse, "LOCK", eLock, -1, 0, rc);
+ return rc;
+}
+
+/*
+** Unlock an vlog-file.
+*/
+static int vlogUnlock(sqlite3_file *pFile, int eLock){
+ int rc;
+ sqlite3_uint64 tStart;
+ VLogFile *p = (VLogFile *)pFile;
+ tStart = vlog_time();
+ vlogLogPrint(p->pLog, tStart, 0, "UNLOCK", eLock, -1, 0, 0);
+ rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
+ return rc;
+}
+
+/*
+** Check if another file-handle holds a RESERVED lock on an vlog-file.
+*/
+static int vlogCheckReservedLock(sqlite3_file *pFile, int *pResOut){
+ int rc;
+ sqlite3_uint64 tStart, tElapse;
+ VLogFile *p = (VLogFile *)pFile;
+ tStart = vlog_time();
+ rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
+ tElapse = vlog_time() - tStart;
+ vlogLogPrint(p->pLog, tStart, tElapse, "CHECKRESERVEDLOCK",
+ *pResOut, -1, "", rc);
+ return rc;
+}
+
+/*
+** File control method. For custom operations on an vlog-file.
+*/
+static int vlogFileControl(sqlite3_file *pFile, int op, void *pArg){
+ VLogFile *p = (VLogFile *)pFile;
+ sqlite3_uint64 tStart, tElapse;
+ int rc;
+ tStart = vlog_time();
+ rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
+ if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
+ *(char**)pArg = sqlite3_mprintf("vlog/%z", *(char**)pArg);
+ }
+ tElapse = vlog_time() - tStart;
+ if( op==SQLITE_FCNTL_TRACE ){
+ vlogLogPrint(p->pLog, tStart, tElapse, "TRACE", op, -1, pArg, rc);
+ }else if( op==SQLITE_FCNTL_PRAGMA ){
+ const char **azArg = (const char **)pArg;
+ vlogLogPrint(p->pLog, tStart, tElapse, "FILECONTROL", op, -1, azArg[1], rc);
+ }else if( op==SQLITE_FCNTL_SIZE_HINT ){
+ sqlite3_int64 sz = *(sqlite3_int64*)pArg;
+ vlogLogPrint(p->pLog, tStart, tElapse, "FILECONTROL", op, sz, 0, rc);
+ }else{
+ vlogLogPrint(p->pLog, tStart, tElapse, "FILECONTROL", op, -1, 0, rc);
+ }
+ return rc;
+}
+
+/*
+** Return the sector-size in bytes for an vlog-file.
+*/
+static int vlogSectorSize(sqlite3_file *pFile){
+ int rc;
+ sqlite3_uint64 tStart, tElapse;
+ VLogFile *p = (VLogFile *)pFile;
+ tStart = vlog_time();
+ rc = p->pReal->pMethods->xSectorSize(p->pReal);
+ tElapse = vlog_time() - tStart;
+ vlogLogPrint(p->pLog, tStart, tElapse, "SECTORSIZE", -1, -1, 0, rc);
+ return rc;
+}
+
+/*
+** Return the device characteristic flags supported by an vlog-file.
+*/
+static int vlogDeviceCharacteristics(sqlite3_file *pFile){
+ int rc;
+ sqlite3_uint64 tStart, tElapse;
+ VLogFile *p = (VLogFile *)pFile;
+ tStart = vlog_time();
+ rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
+ tElapse = vlog_time() - tStart;
+ vlogLogPrint(p->pLog, tStart, tElapse, "DEVCHAR", -1, -1, 0, rc);
+ return rc;
+}
+
+static int vlogShmMap(sqlite3_file*pFile,int a,int b,int c, void volatile **d){
+ int rc;
+ sqlite3_uint64 tStart, tElapse;
+ VLogFile *p = (VLogFile *)pFile;
+ tStart = vlog_time();
+ rc = p->pReal->pMethods->xShmMap(p->pReal, a, b, c, d);
+ tElapse = vlog_time() - tStart;
+ vlogLogPrint(p->pLog, tStart, tElapse, "SHMMAP", a, b, 0, rc);
+ return rc;
+}
+
+static int vlogShmLock(sqlite3_file*pFile, int a, int b, int c){
+ int rc;
+ sqlite3_uint64 tStart, tElapse;
+ VLogFile *p = (VLogFile *)pFile;
+ tStart = vlog_time();
+ rc = p->pReal->pMethods->xShmLock(p->pReal, a, b, c);
+ tElapse = vlog_time() - tStart;
+ vlogLogPrint(p->pLog, tStart, tElapse, "SHMLOCK", a, b, 0, rc);
+ return rc;
+}
+
+static void vlogShmBarrier(sqlite3_file*pFile){
+ sqlite3_uint64 tStart, tElapse;
+ VLogFile *p = (VLogFile *)pFile;
+ tStart = vlog_time();
+ p->pReal->pMethods->xShmBarrier(p->pReal);
+ tElapse = vlog_time() - tStart;
+ vlogLogPrint(p->pLog, tStart, tElapse, "SHMLOCK", -1, -1, 0, 0);
+}
+
+static int vlogShmUnmap(sqlite3_file*pFile, int a){
+ int rc;
+ sqlite3_uint64 tStart, tElapse;
+ VLogFile *p = (VLogFile *)pFile;
+ tStart = vlog_time();
+ rc = p->pReal->pMethods->xShmUnmap(p->pReal, a);
+ tElapse = vlog_time() - tStart;
+ vlogLogPrint(p->pLog, tStart, tElapse, "SHMLOCK", a, -1, 0, rc);
+ return rc;
+}
+
+static int vlogFetch(sqlite3_file*pFile, sqlite3_int64 a, int b, void** c){
+ int rc;
+ sqlite3_uint64 tStart, tElapse;
+ VLogFile *p = (VLogFile *)pFile;
+ tStart = vlog_time();
+ rc = p->pReal->pMethods->xFetch(p->pReal, a, b, c);
+ tElapse = vlog_time() - tStart;
+ vlogLogPrint(p->pLog, tStart, tElapse, "SHMLOCK", a, b, 0, rc);
+ return rc;
+}
+
+static int vlogUnfetch(sqlite3_file*pFile, sqlite3_int64 a, void* b){
+ int rc;
+ sqlite3_uint64 tStart, tElapse;
+ VLogFile *p = (VLogFile *)pFile;
+ tStart = vlog_time();
+ rc = p->pReal->pMethods->xUnfetch(p->pReal, a, b);
+ tElapse = vlog_time() - tStart;
+ vlogLogPrint(p->pLog, tStart, tElapse, "SHMLOCK", a, -1, 0, rc);
+ return rc;
+}
+
+/*
+** Open an vlog file handle.
+*/
+static int vlogOpen(
+ sqlite3_vfs *pVfs,
+ const char *zName,
+ sqlite3_file *pFile,
+ int flags,
+ int *pOutFlags
+){
+ int rc;
+ sqlite3_uint64 tStart, tElapse;
+ sqlite3_int64 iArg2;
+ VLogFile *p = (VLogFile*)pFile;
+
+ p->pReal = (sqlite3_file*)&p[1];
+ if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_MAIN_JOURNAL))!=0 ){
+ p->pLog = vlogLogOpen(zName);
+ }else{
+ p->pLog = 0;
+ }
+ tStart = vlog_time();
+ rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags);
+ tElapse = vlog_time() - tStart;
+ iArg2 = pOutFlags ? *pOutFlags : -1;
+ vlogLogPrint(p->pLog, tStart, tElapse, "OPEN", flags, iArg2, 0, rc);
+ if( rc==SQLITE_OK ){
+ pFile->pMethods = &vlog_io_methods;
+ }else{
+ if( p->pLog ) vlogLogClose(p->pLog);
+ p->pLog = 0;
+ }
+ return rc;
+}
+
+/*
+** Delete the file located at zPath. If the dirSync argument is true,
+** ensure the file-system modifications are synced to disk before
+** returning.
+*/
+static int vlogDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+ int rc;
+ sqlite3_uint64 tStart, tElapse;
+ VLogLog *pLog;
+ tStart = vlog_time();
+ rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync);
+ tElapse = vlog_time() - tStart;
+ pLog = vlogLogOpen(zPath);
+ vlogLogPrint(pLog, tStart, tElapse, "DELETE", dirSync, -1, 0, rc);
+ vlogLogClose(pLog);
+ return rc;
+}
+
+/*
+** Test for access permissions. Return true if the requested permission
+** is available, or false otherwise.
+*/
+static int vlogAccess(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int flags,
+ int *pResOut
+){
+ int rc;
+ sqlite3_uint64 tStart, tElapse;
+ VLogLog *pLog;
+ tStart = vlog_time();
+ rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut);
+ tElapse = vlog_time() - tStart;
+ pLog = vlogLogOpen(zPath);
+ vlogLogPrint(pLog, tStart, tElapse, "ACCESS", flags, *pResOut, 0, rc);
+ vlogLogClose(pLog);
+ return rc;
+}
+
+/*
+** Populate buffer zOut with the full canonical pathname corresponding
+** to the pathname in zPath. zOut is guaranteed to point to a buffer
+** of at least (INST_MAX_PATHNAME+1) bytes.
+*/
+static int vlogFullPathname(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int nOut,
+ char *zOut
+){
+ return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut);
+}
+
+/*
+** Open the dynamic library located at zPath and return a handle.
+*/
+static void *vlogDlOpen(sqlite3_vfs *pVfs, const char *zPath){
+ return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath);
+}
+
+/*
+** Populate the buffer zErrMsg (size nByte bytes) with a human readable
+** utf-8 string describing the most recent error encountered associated
+** with dynamic libraries.
+*/
+static void vlogDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
+ REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg);
+}
+
+/*
+** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
+*/
+static void (*vlogDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
+ return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym);
+}
+
+/*
+** Close the dynamic library handle pHandle.
+*/
+static void vlogDlClose(sqlite3_vfs *pVfs, void *pHandle){
+ REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle);
+}
+
+/*
+** Populate the buffer pointed to by zBufOut with nByte bytes of
+** random data.
+*/
+static int vlogRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
+ return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut);
+}
+
+/*
+** Sleep for nMicro microseconds. Return the number of microseconds
+** actually slept.
+*/
+static int vlogSleep(sqlite3_vfs *pVfs, int nMicro){
+ return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro);
+}
+
+/*
+** Return the current time as a Julian Day number in *pTimeOut.
+*/
+static int vlogCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
+ return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut);
+}
+
+static int vlogGetLastError(sqlite3_vfs *pVfs, int a, char *b){
+ return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), a, b);
+}
+static int vlogCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
+ return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), p);
+}
+static int vlogSetSystemCall(sqlite3_vfs*pVfs, const char *zName, sqlite3_syscall_ptr p){
+ return REALVFS(pVfs)->xSetSystemCall(REALVFS(pVfs), zName, p);
+}
+static sqlite3_syscall_ptr vlogGetSystemCall(sqlite3_vfs *pVfs, const char *zName){
+ return REALVFS(pVfs)->xGetSystemCall(REALVFS(pVfs), zName);
+}
+static const char *vlogNextSystemCall(sqlite3_vfs *pVfs, const char *zName){
+ return REALVFS(pVfs)->xNextSystemCall(REALVFS(pVfs), zName);
+}
+
+/*
+** Register vfslog as the default VFS for this process.
+*/
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_register_vfslog(const char *zArg){
+ vlog_vfs.pVfs = sqlite3_vfs_find(0);
+ if( vlog_vfs.pVfs==&vlog_vfs.base ) return 0; /* Already registered. */
+ vlog_vfs.base.iVersion = vlog_vfs.pVfs->iVersion;
+ vlog_vfs.base.szOsFile = sizeof(VLogFile) + vlog_vfs.pVfs->szOsFile;
+ vlog_vfs.base.mxPathname = vlog_vfs.pVfs->mxPathname;
+ return sqlite3_vfs_register(&vlog_vfs.base, 1);
+}
--- origsrc/sqlite-autoconf-3300000/vfsstat.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/vfsstat.c 2019-10-08 13:42:19.247229900 +0200
@@ -0,0 +1,828 @@
+/*
+** 2016-05-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 the implementation of an SQLite vfs shim that
+** tracks I/O. Access to the accumulated status counts is provided using
+** an eponymous virtual table.
+*/
+#include <sqlite3ext.h>
+SQLITE_EXTENSION_INIT1
+
+/*
+** This module contains code for a wrapper VFS that cause stats for
+** most VFS calls to be recorded.
+**
+** To use this module, first compile it as a loadable extension. See
+** https://www.sqlite.org/loadext.html#build for compilations instructions.
+**
+** After compliing, load this extension, then open database connections to be
+** measured. Query usages status using the vfsstat virtual table:
+**
+** SELECT * FROM vfsstat;
+**
+** Reset counters using UPDATE statements against vfsstat:
+**
+** UPDATE vfsstat SET count=0;
+**
+** EXAMPLE SCRIPT:
+**
+** .load ./vfsstat
+** .open test.db
+** DROP TABLE IF EXISTS t1;
+** CREATE TABLE t1(x,y);
+** INSERT INTO t1 VALUES(123, randomblob(5000));
+** CREATE INDEX t1x ON t1(x);
+** DROP TABLE t1;
+** VACUUM;
+** SELECT * FROM vfsstat WHERE count>0;
+**
+** LIMITATIONS:
+**
+** This module increments counters without using mutex protection. So if
+** two or more threads try to use this module at the same time, race conditions
+** may occur which mess up the counts. This is harmless, other than giving
+** incorrect statistics.
+*/
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+/*
+** File types
+*/
+#define VFSSTAT_MAIN 0 /* Main database file */
+#define VFSSTAT_JOURNAL 1 /* Rollback journal */
+#define VFSSTAT_WAL 2 /* Write-ahead log file */
+#define VFSSTAT_MASTERJRNL 3 /* Master journal */
+#define VFSSTAT_SUBJRNL 4 /* Subjournal */
+#define VFSSTAT_TEMPDB 5 /* TEMP database */
+#define VFSSTAT_TEMPJRNL 6 /* Journal for TEMP database */
+#define VFSSTAT_TRANSIENT 7 /* Transient database */
+#define VFSSTAT_ANY 8 /* Unspecified file type */
+#define VFSSTAT_nFile 9 /* This many file types */
+
+/* Names of the file types. These are allowed values for the
+** first column of the vfsstat virtual table.
+*/
+static const char *const azFile[] = {
+ "database", "journal", "wal", "master-journal", "sub-journal",
+ "temp-database", "temp-journal", "transient-db", "*"
+};
+
+/*
+** Stat types
+*/
+#define VFSSTAT_BYTESIN 0 /* Bytes read in */
+#define VFSSTAT_BYTESOUT 1 /* Bytes written out */
+#define VFSSTAT_READ 2 /* Read requests */
+#define VFSSTAT_WRITE 3 /* Write requests */
+#define VFSSTAT_SYNC 4 /* Syncs */
+#define VFSSTAT_OPEN 5 /* File opens */
+#define VFSSTAT_LOCK 6 /* Lock requests */
+#define VFSSTAT_ACCESS 0 /* xAccess calls. filetype==ANY only */
+#define VFSSTAT_DELETE 1 /* xDelete calls. filetype==ANY only */
+#define VFSSTAT_FULLPATH 2 /* xFullPathname calls. ANY only */
+#define VFSSTAT_RANDOM 3 /* xRandomness calls. ANY only */
+#define VFSSTAT_SLEEP 4 /* xSleep calls. ANY only */
+#define VFSSTAT_CURTIME 5 /* xCurrentTime calls. ANY only */
+#define VFSSTAT_nStat 7 /* This many stat types */
+
+
+/* Names for the second column of the vfsstat virtual table for all
+** cases except when the first column is "*" or VFSSTAT_ANY. */
+static const char *const azStat[] = {
+ "bytes-in", "bytes-out", "read", "write", "sync", "open", "lock",
+};
+static const char *const azStatAny[] = {
+ "access", "delete", "fullpathname", "randomness", "sleep", "currenttimestamp",
+ "not-used"
+};
+
+/* Total number of counters */
+#define VFSSTAT_MXCNT (VFSSTAT_nStat*VFSSTAT_nFile)
+
+/*
+** Performance stats are collected in an instance of the following
+** global array.
+*/
+static sqlite3_uint64 aVfsCnt[VFSSTAT_MXCNT];
+
+/*
+** Access to a specific counter
+*/
+#define STATCNT(filetype,stat) (aVfsCnt[(filetype)*VFSSTAT_nStat+(stat)])
+
+/*
+** Forward declaration of objects used by this utility
+*/
+typedef struct VStatVfs VStatVfs;
+typedef struct VStatFile VStatFile;
+
+/* An instance of the VFS */
+struct VStatVfs {
+ sqlite3_vfs base; /* VFS methods */
+ sqlite3_vfs *pVfs; /* Parent VFS */
+};
+
+/* An open file */
+struct VStatFile {
+ sqlite3_file base; /* IO methods */
+ sqlite3_file *pReal; /* Underlying file handle */
+ unsigned char eFiletype; /* What type of file is this */
+};
+
+#define REALVFS(p) (((VStatVfs*)(p))->pVfs)
+
+/*
+** Methods for VStatFile
+*/
+static int vstatClose(sqlite3_file*);
+static int vstatRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
+static int vstatWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
+static int vstatTruncate(sqlite3_file*, sqlite3_int64 size);
+static int vstatSync(sqlite3_file*, int flags);
+static int vstatFileSize(sqlite3_file*, sqlite3_int64 *pSize);
+static int vstatLock(sqlite3_file*, int);
+static int vstatUnlock(sqlite3_file*, int);
+static int vstatCheckReservedLock(sqlite3_file*, int *pResOut);
+static int vstatFileControl(sqlite3_file*, int op, void *pArg);
+static int vstatSectorSize(sqlite3_file*);
+static int vstatDeviceCharacteristics(sqlite3_file*);
+static int vstatShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
+static int vstatShmLock(sqlite3_file*, int offset, int n, int flags);
+static void vstatShmBarrier(sqlite3_file*);
+static int vstatShmUnmap(sqlite3_file*, int deleteFlag);
+static int vstatFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
+static int vstatUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
+
+/*
+** Methods for VStatVfs
+*/
+static int vstatOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
+static int vstatDelete(sqlite3_vfs*, const char *zName, int syncDir);
+static int vstatAccess(sqlite3_vfs*, const char *zName, int flags, int *);
+static int vstatFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
+static void *vstatDlOpen(sqlite3_vfs*, const char *zFilename);
+static void vstatDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
+static void (*vstatDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
+static void vstatDlClose(sqlite3_vfs*, void*);
+static int vstatRandomness(sqlite3_vfs*, int nByte, char *zOut);
+static int vstatSleep(sqlite3_vfs*, int microseconds);
+static int vstatCurrentTime(sqlite3_vfs*, double*);
+static int vstatGetLastError(sqlite3_vfs*, int, char *);
+static int vstatCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
+
+static VStatVfs vstat_vfs = {
+ {
+ 2, /* iVersion */
+ 0, /* szOsFile (set by register_vstat()) */
+ 1024, /* mxPathname */
+ 0, /* pNext */
+ "vfslog", /* zName */
+ 0, /* pAppData */
+ vstatOpen, /* xOpen */
+ vstatDelete, /* xDelete */
+ vstatAccess, /* xAccess */
+ vstatFullPathname, /* xFullPathname */
+ vstatDlOpen, /* xDlOpen */
+ vstatDlError, /* xDlError */
+ vstatDlSym, /* xDlSym */
+ vstatDlClose, /* xDlClose */
+ vstatRandomness, /* xRandomness */
+ vstatSleep, /* xSleep */
+ vstatCurrentTime, /* xCurrentTime */
+ vstatGetLastError, /* xGetLastError */
+ vstatCurrentTimeInt64 /* xCurrentTimeInt64 */
+ },
+ 0
+};
+
+static const sqlite3_io_methods vstat_io_methods = {
+ 3, /* iVersion */
+ vstatClose, /* xClose */
+ vstatRead, /* xRead */
+ vstatWrite, /* xWrite */
+ vstatTruncate, /* xTruncate */
+ vstatSync, /* xSync */
+ vstatFileSize, /* xFileSize */
+ vstatLock, /* xLock */
+ vstatUnlock, /* xUnlock */
+ vstatCheckReservedLock, /* xCheckReservedLock */
+ vstatFileControl, /* xFileControl */
+ vstatSectorSize, /* xSectorSize */
+ vstatDeviceCharacteristics, /* xDeviceCharacteristics */
+ vstatShmMap, /* xShmMap */
+ vstatShmLock, /* xShmLock */
+ vstatShmBarrier, /* xShmBarrier */
+ vstatShmUnmap, /* xShmUnmap */
+ vstatFetch, /* xFetch */
+ vstatUnfetch /* xUnfetch */
+};
+
+
+
+/*
+** Close an vstat-file.
+*/
+static int vstatClose(sqlite3_file *pFile){
+ VStatFile *p = (VStatFile *)pFile;
+ int rc = SQLITE_OK;
+
+ if( p->pReal->pMethods ){
+ rc = p->pReal->pMethods->xClose(p->pReal);
+ }
+ return rc;
+}
+
+
+/*
+** Read data from an vstat-file.
+*/
+static int vstatRead(
+ sqlite3_file *pFile,
+ void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ int rc;
+ VStatFile *p = (VStatFile *)pFile;
+
+ rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
+ STATCNT(p->eFiletype,VFSSTAT_READ)++;
+ if( rc==SQLITE_OK ){
+ STATCNT(p->eFiletype,VFSSTAT_BYTESIN) += iAmt;
+ }
+ return rc;
+}
+
+/*
+** Write data to an vstat-file.
+*/
+static int vstatWrite(
+ sqlite3_file *pFile,
+ const void *z,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ int rc;
+ VStatFile *p = (VStatFile *)pFile;
+
+ rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst);
+ STATCNT(p->eFiletype,VFSSTAT_WRITE)++;
+ if( rc==SQLITE_OK ){
+ STATCNT(p->eFiletype,VFSSTAT_BYTESOUT) += iAmt;
+ }
+ return rc;
+}
+
+/*
+** Truncate an vstat-file.
+*/
+static int vstatTruncate(sqlite3_file *pFile, sqlite_int64 size){
+ int rc;
+ VStatFile *p = (VStatFile *)pFile;
+ rc = p->pReal->pMethods->xTruncate(p->pReal, size);
+ return rc;
+}
+
+/*
+** Sync an vstat-file.
+*/
+static int vstatSync(sqlite3_file *pFile, int flags){
+ int rc;
+ VStatFile *p = (VStatFile *)pFile;
+ rc = p->pReal->pMethods->xSync(p->pReal, flags);
+ STATCNT(p->eFiletype,VFSSTAT_SYNC)++;
+ return rc;
+}
+
+/*
+** Return the current file-size of an vstat-file.
+*/
+static int vstatFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
+ int rc;
+ VStatFile *p = (VStatFile *)pFile;
+ rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
+ return rc;
+}
+
+/*
+** Lock an vstat-file.
+*/
+static int vstatLock(sqlite3_file *pFile, int eLock){
+ int rc;
+ VStatFile *p = (VStatFile *)pFile;
+ rc = p->pReal->pMethods->xLock(p->pReal, eLock);
+ STATCNT(p->eFiletype,VFSSTAT_LOCK)++;
+ return rc;
+}
+
+/*
+** Unlock an vstat-file.
+*/
+static int vstatUnlock(sqlite3_file *pFile, int eLock){
+ int rc;
+ VStatFile *p = (VStatFile *)pFile;
+ rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
+ STATCNT(p->eFiletype,VFSSTAT_LOCK)++;
+ return rc;
+}
+
+/*
+** Check if another file-handle holds a RESERVED lock on an vstat-file.
+*/
+static int vstatCheckReservedLock(sqlite3_file *pFile, int *pResOut){
+ int rc;
+ VStatFile *p = (VStatFile *)pFile;
+ rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
+ STATCNT(p->eFiletype,VFSSTAT_LOCK)++;
+ return rc;
+}
+
+/*
+** File control method. For custom operations on an vstat-file.
+*/
+static int vstatFileControl(sqlite3_file *pFile, int op, void *pArg){
+ VStatFile *p = (VStatFile *)pFile;
+ int rc;
+ rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
+ if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
+ *(char**)pArg = sqlite3_mprintf("vstat/%z", *(char**)pArg);
+ }
+ return rc;
+}
+
+/*
+** Return the sector-size in bytes for an vstat-file.
+*/
+static int vstatSectorSize(sqlite3_file *pFile){
+ int rc;
+ VStatFile *p = (VStatFile *)pFile;
+ rc = p->pReal->pMethods->xSectorSize(p->pReal);
+ return rc;
+}
+
+/*
+** Return the device characteristic flags supported by an vstat-file.
+*/
+static int vstatDeviceCharacteristics(sqlite3_file *pFile){
+ int rc;
+ VStatFile *p = (VStatFile *)pFile;
+ rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
+ return rc;
+}
+
+/* Create a shared memory file mapping */
+static int vstatShmMap(
+ sqlite3_file *pFile,
+ int iPg,
+ int pgsz,
+ int bExtend,
+ void volatile **pp
+){
+ VStatFile *p = (VStatFile *)pFile;
+ return p->pReal->pMethods->xShmMap(p->pReal, iPg, pgsz, bExtend, pp);
+}
+
+/* Perform locking on a shared-memory segment */
+static int vstatShmLock(sqlite3_file *pFile, int offset, int n, int flags){
+ VStatFile *p = (VStatFile *)pFile;
+ return p->pReal->pMethods->xShmLock(p->pReal, offset, n, flags);
+}
+
+/* Memory barrier operation on shared memory */
+static void vstatShmBarrier(sqlite3_file *pFile){
+ VStatFile *p = (VStatFile *)pFile;
+ p->pReal->pMethods->xShmBarrier(p->pReal);
+}
+
+/* Unmap a shared memory segment */
+static int vstatShmUnmap(sqlite3_file *pFile, int deleteFlag){
+ VStatFile *p = (VStatFile *)pFile;
+ return p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag);
+}
+
+/* Fetch a page of a memory-mapped file */
+static int vstatFetch(
+ sqlite3_file *pFile,
+ sqlite3_int64 iOfst,
+ int iAmt,
+ void **pp
+){
+ VStatFile *p = (VStatFile *)pFile;
+ return p->pReal->pMethods->xFetch(p->pReal, iOfst, iAmt, pp);
+}
+
+/* Release a memory-mapped page */
+static int vstatUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
+ VStatFile *p = (VStatFile *)pFile;
+ return p->pReal->pMethods->xUnfetch(p->pReal, iOfst, pPage);
+}
+
+/*
+** Open an vstat file handle.
+*/
+static int vstatOpen(
+ sqlite3_vfs *pVfs,
+ const char *zName,
+ sqlite3_file *pFile,
+ int flags,
+ int *pOutFlags
+){
+ int rc;
+ VStatFile *p = (VStatFile*)pFile;
+
+ p->pReal = (sqlite3_file*)&p[1];
+ rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags);
+ if( flags & SQLITE_OPEN_MAIN_DB ){
+ p->eFiletype = VFSSTAT_MAIN;
+ }else if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
+ p->eFiletype = VFSSTAT_JOURNAL;
+ }else if( flags & SQLITE_OPEN_WAL ){
+ p->eFiletype = VFSSTAT_WAL;
+ }else if( flags & SQLITE_OPEN_MASTER_JOURNAL ){
+ p->eFiletype = VFSSTAT_MASTERJRNL;
+ }else if( flags & SQLITE_OPEN_SUBJOURNAL ){
+ p->eFiletype = VFSSTAT_SUBJRNL;
+ }else if( flags & SQLITE_OPEN_TEMP_DB ){
+ p->eFiletype = VFSSTAT_TEMPDB;
+ }else if( flags & SQLITE_OPEN_TEMP_JOURNAL ){
+ p->eFiletype = VFSSTAT_TEMPJRNL;
+ }else{
+ p->eFiletype = VFSSTAT_TRANSIENT;
+ }
+ STATCNT(p->eFiletype,VFSSTAT_OPEN)++;
+ pFile->pMethods = rc ? 0 : &vstat_io_methods;
+ return rc;
+}
+
+/*
+** Delete the file located at zPath. If the dirSync argument is true,
+** ensure the file-system modifications are synced to disk before
+** returning.
+*/
+static int vstatDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+ int rc;
+ rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync);
+ STATCNT(VFSSTAT_ANY,VFSSTAT_DELETE)++;
+ return rc;
+}
+
+/*
+** Test for access permissions. Return true if the requested permission
+** is available, or false otherwise.
+*/
+static int vstatAccess(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int flags,
+ int *pResOut
+){
+ int rc;
+ rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut);
+ STATCNT(VFSSTAT_ANY,VFSSTAT_ACCESS)++;
+ return rc;
+}
+
+/*
+** Populate buffer zOut with the full canonical pathname corresponding
+** to the pathname in zPath. zOut is guaranteed to point to a buffer
+** of at least (INST_MAX_PATHNAME+1) bytes.
+*/
+static int vstatFullPathname(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int nOut,
+ char *zOut
+){
+ STATCNT(VFSSTAT_ANY,VFSSTAT_FULLPATH)++;
+ return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut);
+}
+
+/*
+** Open the dynamic library located at zPath and return a handle.
+*/
+static void *vstatDlOpen(sqlite3_vfs *pVfs, const char *zPath){
+ return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath);
+}
+
+/*
+** Populate the buffer zErrMsg (size nByte bytes) with a human readable
+** utf-8 string describing the most recent error encountered associated
+** with dynamic libraries.
+*/
+static void vstatDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
+ REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg);
+}
+
+/*
+** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
+*/
+static void (*vstatDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
+ return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym);
+}
+
+/*
+** Close the dynamic library handle pHandle.
+*/
+static void vstatDlClose(sqlite3_vfs *pVfs, void *pHandle){
+ REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle);
+}
+
+/*
+** Populate the buffer pointed to by zBufOut with nByte bytes of
+** random data.
+*/
+static int vstatRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
+ STATCNT(VFSSTAT_ANY,VFSSTAT_RANDOM)++;
+ return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut);
+}
+
+/*
+** Sleep for nMicro microseconds. Return the number of microseconds
+** actually slept.
+*/
+static int vstatSleep(sqlite3_vfs *pVfs, int nMicro){
+ STATCNT(VFSSTAT_ANY,VFSSTAT_SLEEP)++;
+ return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro);
+}
+
+/*
+** Return the current time as a Julian Day number in *pTimeOut.
+*/
+static int vstatCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
+ STATCNT(VFSSTAT_ANY,VFSSTAT_CURTIME)++;
+ return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut);
+}
+
+static int vstatGetLastError(sqlite3_vfs *pVfs, int a, char *b){
+ return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), a, b);
+}
+static int vstatCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
+ STATCNT(VFSSTAT_ANY,VFSSTAT_CURTIME)++;
+ return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), p);
+}
+
+/*
+** A virtual table for accessing the stats collected by this VFS shim
+*/
+static int vstattabConnect(sqlite3*, void*, int, const char*const*,
+ sqlite3_vtab**,char**);
+static int vstattabBestIndex(sqlite3_vtab*,sqlite3_index_info*);
+static int vstattabDisconnect(sqlite3_vtab*);
+static int vstattabOpen(sqlite3_vtab*, sqlite3_vtab_cursor**);
+static int vstattabClose(sqlite3_vtab_cursor*);
+static int vstattabFilter(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv);
+static int vstattabNext(sqlite3_vtab_cursor*);
+static int vstattabEof(sqlite3_vtab_cursor*);
+static int vstattabColumn(sqlite3_vtab_cursor*,sqlite3_context*,int);
+static int vstattabRowid(sqlite3_vtab_cursor*,sqlite3_int64*);
+static int vstattabUpdate(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*);
+
+/* A cursor for the vfsstat virtual table */
+typedef struct VfsStatCursor {
+ sqlite3_vtab_cursor base; /* Base class. Must be first */
+ int i; /* Pointing to this aVfsCnt[] value */
+} VfsStatCursor;
+
+
+static int vstattabConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ sqlite3_vtab *pNew;
+ int rc;
+
+/* Column numbers */
+#define VSTAT_COLUMN_FILE 0
+#define VSTAT_COLUMN_STAT 1
+#define VSTAT_COLUMN_COUNT 2
+
+ rc = sqlite3_declare_vtab(db,"CREATE TABLE x(file,stat,count)");
+ if( rc==SQLITE_OK ){
+ pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for vstat table object.
+*/
+static int vstattabDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new vstat table cursor object.
+*/
+static int vstattabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ VfsStatCursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+
+/*
+** Destructor for a VfsStatCursor.
+*/
+static int vstattabClose(sqlite3_vtab_cursor *cur){
+ sqlite3_free(cur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a VfsStatCursor to its next row of output.
+*/
+static int vstattabNext(sqlite3_vtab_cursor *cur){
+ ((VfsStatCursor*)cur)->i++;
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the VfsStatCursor
+** is currently pointing.
+*/
+static int vstattabColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ VfsStatCursor *pCur = (VfsStatCursor*)cur;
+ switch( i ){
+ case VSTAT_COLUMN_FILE: {
+ sqlite3_result_text(ctx, azFile[pCur->i/VFSSTAT_nStat], -1, SQLITE_STATIC);
+ break;
+ }
+ case VSTAT_COLUMN_STAT: {
+ const char *const *az;
+ az = (pCur->i/VFSSTAT_nStat)==VFSSTAT_ANY ? azStatAny : azStat;
+ sqlite3_result_text(ctx, az[pCur->i%VFSSTAT_nStat], -1, SQLITE_STATIC);
+ break;
+ }
+ case VSTAT_COLUMN_COUNT: {
+ sqlite3_result_int64(ctx, aVfsCnt[pCur->i]);
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row.
+*/
+static int vstattabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ VfsStatCursor *pCur = (VfsStatCursor*)cur;
+ *pRowid = pCur->i;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int vstattabEof(sqlite3_vtab_cursor *cur){
+ VfsStatCursor *pCur = (VfsStatCursor*)cur;
+ return pCur->i >= VFSSTAT_MXCNT;
+}
+
+/*
+** Only a full table scan is supported. So xFilter simply rewinds to
+** the beginning.
+*/
+static int vstattabFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ VfsStatCursor *pCur = (VfsStatCursor*)pVtabCursor;
+ pCur->i = 0;
+ return SQLITE_OK;
+}
+
+/*
+** Only a forwards full table scan is supported. xBestIndex is a no-op.
+*/
+static int vstattabBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ return SQLITE_OK;
+}
+
+/*
+** Any VSTAT_COLUMN_COUNT can be changed to a positive integer.
+** No deletions or insertions are allowed. No changes to other
+** columns are allowed.
+*/
+static int vstattabUpdate(
+ sqlite3_vtab *tab,
+ int argc, sqlite3_value **argv,
+ sqlite3_int64 *pRowid
+){
+ sqlite3_int64 iRowid, x;
+ if( argc==1 ) return SQLITE_ERROR;
+ if( sqlite3_value_type(argv[0])!=SQLITE_INTEGER ) return SQLITE_ERROR;
+ iRowid = sqlite3_value_int64(argv[0]);
+ if( iRowid!=sqlite3_value_int64(argv[1]) ) return SQLITE_ERROR;
+ if( iRowid<0 || iRowid>=VFSSTAT_MXCNT ) return SQLITE_ERROR;
+ if( sqlite3_value_type(argv[VSTAT_COLUMN_COUNT+2])!=SQLITE_INTEGER ){
+ return SQLITE_ERROR;
+ }
+ x = sqlite3_value_int64(argv[VSTAT_COLUMN_COUNT+2]);
+ if( x<0 ) return SQLITE_ERROR;
+ aVfsCnt[iRowid] = x;
+ return SQLITE_OK;
+}
+
+static const sqlite3_module VfsStatModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ vstattabConnect, /* xConnect */
+ vstattabBestIndex, /* xBestIndex */
+ vstattabDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ vstattabOpen, /* xOpen - open a cursor */
+ vstattabClose, /* xClose - close a cursor */
+ vstattabFilter, /* xFilter - configure scan constraints */
+ vstattabNext, /* xNext - advance a cursor */
+ vstattabEof, /* xEof - check for end of scan */
+ vstattabColumn, /* xColumn - read data */
+ vstattabRowid, /* xRowid - read data */
+ vstattabUpdate, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+};
+
+/*
+** This routine is an sqlite3_auto_extension() callback, invoked to register
+** the vfsstat virtual table for all new database connections.
+*/
+static int vstatRegister(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pThunk
+){
+ return sqlite3_create_module(db, "vfsstat", &VfsStatModule, 0);
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+/*
+** This routine is called when the extension is loaded.
+**
+** Register the new VFS. Make arrangement to register the virtual table
+** for each new database connection.
+*/
+int sqlite3_vfsstat_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ vstat_vfs.pVfs = sqlite3_vfs_find(0);
+ vstat_vfs.base.szOsFile = sizeof(VStatFile) + vstat_vfs.pVfs->szOsFile;
+ rc = sqlite3_vfs_register(&vstat_vfs.base, 1);
+ if( rc==SQLITE_OK ){
+ rc = vstatRegister(db, pzErrMsg, pApi);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_auto_extension((void(*)(void))vstatRegister);
+ }
+ }
+ if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ return sqlite3_vfsstat_init(db, pzErrMsg, pApi);
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/vtablog.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/vtablog.c 2019-10-08 13:42:19.252099400 +0200
@@ -0,0 +1,519 @@
+/*
+** 2017-08-10
+**
+** 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 implements a virtual table that prints diagnostic information
+** on stdout when its key interfaces are called. This is intended for
+** interactive analysis and debugging of virtual table interfaces.
+**
+** Usage example:
+**
+** .load ./vtablog
+** CREATE VIRTUAL TABLE temp.log USING vtablog(
+** schema='CREATE TABLE x(a,b,c)',
+** rows=25
+** );
+** SELECT * FROM log;
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+
+
+/* vtablog_vtab is a subclass of sqlite3_vtab which will
+** serve as the underlying representation of a vtablog virtual table
+*/
+typedef struct vtablog_vtab vtablog_vtab;
+struct vtablog_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ int nRow; /* Number of rows in the table */
+ int iInst; /* Instance number for this vtablog table */
+ int nCursor; /* Number of cursors created */
+};
+
+/* vtablog_cursor is a subclass of sqlite3_vtab_cursor which will
+** serve as the underlying representation of a cursor that scans
+** over rows of the result
+*/
+typedef struct vtablog_cursor vtablog_cursor;
+struct vtablog_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ int iCursor; /* Cursor number */
+ sqlite3_int64 iRowid; /* The rowid */
+};
+
+/* Skip leading whitespace. Return a pointer to the first non-whitespace
+** character, or to the zero terminator if the string has only whitespace */
+static const char *vtablog_skip_whitespace(const char *z){
+ while( isspace((unsigned char)z[0]) ) z++;
+ return z;
+}
+
+/* Remove trailing whitespace from the end of string z[] */
+static void vtablog_trim_whitespace(char *z){
+ size_t n = strlen(z);
+ while( n>0 && isspace((unsigned char)z[n]) ) n--;
+ z[n] = 0;
+}
+
+/* Dequote the string */
+static void vtablog_dequote(char *z){
+ int j;
+ char cQuote = z[0];
+ size_t i, n;
+
+ if( cQuote!='\'' && cQuote!='"' ) return;
+ n = strlen(z);
+ if( n<2 || z[n-1]!=z[0] ) return;
+ for(i=1, j=0; i<n-1; i++){
+ if( z[i]==cQuote && z[i+1]==cQuote ) i++;
+ z[j++] = z[i];
+ }
+ z[j] = 0;
+}
+
+/* Check to see if the string is of the form: "TAG = VALUE" with optional
+** whitespace before and around tokens. If it is, return a pointer to the
+** first character of VALUE. If it is not, return NULL.
+*/
+static const char *vtablog_parameter(const char *zTag, int nTag, const char *z){
+ z = vtablog_skip_whitespace(z);
+ if( strncmp(zTag, z, nTag)!=0 ) return 0;
+ z = vtablog_skip_whitespace(z+nTag);
+ if( z[0]!='=' ) return 0;
+ return vtablog_skip_whitespace(z+1);
+}
+
+/* Decode a parameter that requires a dequoted string.
+**
+** Return non-zero on an error.
+*/
+static int vtablog_string_parameter(
+ char **pzErr, /* Leave the error message here, if there is one */
+ const char *zParam, /* Parameter we are checking for */
+ const char *zArg, /* Raw text of the virtual table argment */
+ char **pzVal /* Write the dequoted string value here */
+){
+ const char *zValue;
+ zValue = vtablog_parameter(zParam,(int)strlen(zParam),zArg);
+ if( zValue==0 ) return 0;
+ if( *pzVal ){
+ *pzErr = sqlite3_mprintf("more than one '%s' parameter", zParam);
+ return 1;
+ }
+ *pzVal = sqlite3_mprintf("%s", zValue);
+ if( *pzVal==0 ){
+ *pzErr = sqlite3_mprintf("out of memory");
+ return 1;
+ }
+ vtablog_trim_whitespace(*pzVal);
+ vtablog_dequote(*pzVal);
+ return 0;
+}
+
+#if 0 /* not used - yet */
+/* Return 0 if the argument is false and 1 if it is true. Return -1 if
+** we cannot really tell.
+*/
+static int vtablog_boolean(const char *z){
+ if( sqlite3_stricmp("yes",z)==0
+ || sqlite3_stricmp("on",z)==0
+ || sqlite3_stricmp("true",z)==0
+ || (z[0]=='1' && z[1]==0)
+ ){
+ return 1;
+ }
+ if( sqlite3_stricmp("no",z)==0
+ || sqlite3_stricmp("off",z)==0
+ || sqlite3_stricmp("false",z)==0
+ || (z[0]=='0' && z[1]==0)
+ ){
+ return 0;
+ }
+ return -1;
+}
+#endif
+
+/*
+** The vtablogConnect() method is invoked to create a new
+** vtablog_vtab that describes the vtablog virtual table.
+**
+** Think of this routine as the constructor for vtablog_vtab objects.
+**
+** All this routine needs to do is:
+**
+** (1) Allocate the vtablog_vtab object and initialize all fields.
+**
+** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
+** result set of queries against vtablog will look like.
+*/
+static int vtablogConnectCreate(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr,
+ int isCreate
+){
+ static int nInst = 0;
+ vtablog_vtab *pNew;
+ int i;
+ int rc;
+ int iInst = ++nInst;
+ char *zSchema = 0;
+ char *zNRow = 0;
+
+ printf("vtablog%s(tab=%d):\n", isCreate ? "Create" : "Connect", iInst);
+ printf(" argc=%d\n", argc);
+ for(i=0; i<argc; i++){
+ printf(" argv[%d] = ", i);
+ if( argv[i] ){
+ printf("[%s]\n", argv[i]);
+ }else{
+ printf("NULL\n");
+ }
+ }
+
+ for(i=3; i<argc; i++){
+ const char *z = argv[i];
+ if( vtablog_string_parameter(pzErr, "schema", z, &zSchema) ){
+ return SQLITE_ERROR;
+ }
+ if( vtablog_string_parameter(pzErr, "rows", z, &zNRow) ){
+ return SQLITE_ERROR;
+ }
+ }
+
+ if( zSchema==0 ){
+ *pzErr = sqlite3_mprintf("no schema defined");
+ return SQLITE_ERROR;
+ }
+ rc = sqlite3_declare_vtab(db, zSchema);
+ if( rc==SQLITE_OK ){
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->nRow = 10;
+ if( zNRow ) pNew->nRow = atoi(zNRow);
+ pNew->iInst = iInst;
+ }
+ return rc;
+}
+static int vtablogCreate(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ return vtablogConnectCreate(db,pAux,argc,argv,ppVtab,pzErr,1);
+}
+static int vtablogConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ return vtablogConnectCreate(db,pAux,argc,argv,ppVtab,pzErr,0);
+}
+
+
+/*
+** This method is the destructor for vtablog_cursor objects.
+*/
+static int vtablogDisconnect(sqlite3_vtab *pVtab){
+ vtablog_vtab *pTab = (vtablog_vtab*)pVtab;
+ printf("vtablogDisconnect(%d)\n", pTab->iInst);
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** This method is the destructor for vtablog_cursor objects.
+*/
+static int vtablogDestroy(sqlite3_vtab *pVtab){
+ vtablog_vtab *pTab = (vtablog_vtab*)pVtab;
+ printf("vtablogDestroy(%d)\n", pTab->iInst);
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new vtablog_cursor object.
+*/
+static int vtablogOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ vtablog_vtab *pTab = (vtablog_vtab*)p;
+ vtablog_cursor *pCur;
+ printf("vtablogOpen(tab=%d, cursor=%d)\n", pTab->iInst, ++pTab->nCursor);
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ pCur->iCursor = pTab->nCursor;
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Destructor for a vtablog_cursor.
+*/
+static int vtablogClose(sqlite3_vtab_cursor *cur){
+ vtablog_cursor *pCur = (vtablog_cursor*)cur;
+ vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
+ printf("vtablogClose(tab=%d, cursor=%d)\n", pTab->iInst, pCur->iCursor);
+ sqlite3_free(cur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a vtablog_cursor to its next row of output.
+*/
+static int vtablogNext(sqlite3_vtab_cursor *cur){
+ vtablog_cursor *pCur = (vtablog_cursor*)cur;
+ vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
+ printf("vtablogNext(tab=%d, cursor=%d) rowid %d -> %d\n",
+ pTab->iInst, pCur->iCursor, (int)pCur->iRowid, (int)pCur->iRowid+1);
+ pCur->iRowid++;
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the vtablog_cursor
+** is currently pointing.
+*/
+static int vtablogColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ vtablog_cursor *pCur = (vtablog_cursor*)cur;
+ vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
+ char zVal[50];
+
+ if( i<26 ){
+ sqlite3_snprintf(sizeof(zVal),zVal,"%c%d",
+ "abcdefghijklmnopqrstuvwyz"[i], pCur->iRowid);
+ }else{
+ sqlite3_snprintf(sizeof(zVal),zVal,"{%d}%d", i, pCur->iRowid);
+ }
+ printf("vtablogColumn(tab=%d, cursor=%d, i=%d): [%s]\n",
+ pTab->iInst, pCur->iCursor, i, zVal);
+ sqlite3_result_text(ctx, zVal, -1, SQLITE_TRANSIENT);
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** rowid is the same as the output value.
+*/
+static int vtablogRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ vtablog_cursor *pCur = (vtablog_cursor*)cur;
+ vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
+ printf("vtablogRowid(tab=%d, cursor=%d): %d\n",
+ pTab->iInst, pCur->iCursor, (int)pCur->iRowid);
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int vtablogEof(sqlite3_vtab_cursor *cur){
+ vtablog_cursor *pCur = (vtablog_cursor*)cur;
+ vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
+ int rc = pCur->iRowid >= pTab->nRow;
+ printf("vtablogEof(tab=%d, cursor=%d): %d\n",
+ pTab->iInst, pCur->iCursor, rc);
+ return rc;
+}
+
+/*
+** Output an sqlite3_value object's value as an SQL literal.
+*/
+static void vtablogQuote(sqlite3_value *p){
+ char z[50];
+ switch( sqlite3_value_type(p) ){
+ case SQLITE_NULL: {
+ printf("NULL");
+ break;
+ }
+ case SQLITE_INTEGER: {
+ sqlite3_snprintf(50,z,"%lld", sqlite3_value_int64(p));
+ printf("%s", z);
+ break;
+ }
+ case SQLITE_FLOAT: {
+ sqlite3_snprintf(50,z,"%!.20g", sqlite3_value_double(p));
+ printf("%s", z);
+ break;
+ }
+ case SQLITE_BLOB: {
+ int n = sqlite3_value_bytes(p);
+ const unsigned char *z = (const unsigned char*)sqlite3_value_blob(p);
+ int i;
+ printf("x'");
+ for(i=0; i<n; i++) printf("%02x", z[i]);
+ printf("'");
+ break;
+ }
+ case SQLITE_TEXT: {
+ const char *z = (const char*)sqlite3_value_text(p);
+ int i;
+ char c;
+ for(i=0; (c = z[i])!=0 && c!='\''; i++){}
+ if( c==0 ){
+ printf("'%s'",z);
+ }else{
+ printf("'");
+ while( *z ){
+ for(i=0; (c = z[i])!=0 && c!='\''; i++){}
+ if( c=='\'' ) i++;
+ if( i ){
+ printf("%.*s", i, z);
+ z += i;
+ }
+ if( c=='\'' ){
+ printf("'");
+ continue;
+ }
+ if( c==0 ){
+ break;
+ }
+ z++;
+ }
+ printf("'");
+ }
+ break;
+ }
+ }
+}
+
+
+/*
+** This method is called to "rewind" the vtablog_cursor object back
+** to the first row of output. This method is always called at least
+** once prior to any call to vtablogColumn() or vtablogRowid() or
+** vtablogEof().
+*/
+static int vtablogFilter(
+ sqlite3_vtab_cursor *cur,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ vtablog_cursor *pCur = (vtablog_cursor *)cur;
+ vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
+ printf("vtablogFilter(tab=%d, cursor=%d):\n", pTab->iInst, pCur->iCursor);
+ pCur->iRowid = 0;
+ return SQLITE_OK;
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the vtablog virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+*/
+static int vtablogBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ vtablog_vtab *pTab = (vtablog_vtab*)tab;
+ printf("vtablogBestIndex(tab=%d):\n", pTab->iInst);
+ pIdxInfo->estimatedCost = (double)500;
+ pIdxInfo->estimatedRows = 500;
+ return SQLITE_OK;
+}
+
+/*
+** SQLite invokes this method to INSERT, UPDATE, or DELETE content from
+** the table.
+**
+** This implementation does not actually make any changes to the table
+** content. It merely logs the fact that the method was invoked
+*/
+static int vtablogUpdate(
+ sqlite3_vtab *tab,
+ int argc,
+ sqlite3_value **argv,
+ sqlite_int64 *pRowid
+){
+ vtablog_vtab *pTab = (vtablog_vtab*)tab;
+ int i;
+ printf("vtablogUpdate(tab=%d):\n", pTab->iInst);
+ printf(" argc=%d\n", argc);
+ for(i=0; i<argc; i++){
+ printf(" argv[%d]=", i);
+ vtablogQuote(argv[i]);
+ printf("\n");
+ }
+ return SQLITE_OK;
+}
+
+/*
+** This following structure defines all the methods for the
+** vtablog virtual table.
+*/
+static const sqlite3_module vtablogModule = {
+ 0, /* iVersion */
+ vtablogCreate, /* xCreate */
+ vtablogConnect, /* xConnect */
+ vtablogBestIndex, /* xBestIndex */
+ vtablogDisconnect, /* xDisconnect */
+ vtablogDestroy, /* xDestroy */
+ vtablogOpen, /* xOpen - open a cursor */
+ vtablogClose, /* xClose - close a cursor */
+ vtablogFilter, /* xFilter - configure scan constraints */
+ vtablogNext, /* xNext - advance a cursor */
+ vtablogEof, /* xEof - check for end of scan */
+ vtablogColumn, /* xColumn - read data */
+ vtablogRowid, /* xRowid - read data */
+ vtablogUpdate, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0, /* xShadowName */
+};
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_vtablog_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc;
+ SQLITE_EXTENSION_INIT2(pApi);
+ rc = sqlite3_create_module(db, "vtablog", &vtablogModule, 0);
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ return sqlite3_vtablog_init(db, pzErrMsg, pApi);
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/vtshim.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/vtshim.c 2019-10-08 13:42:19.256981500 +0200
@@ -0,0 +1,562 @@
+/*
+** 2013-06-12
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** A shim that sits between the SQLite virtual table interface and
+** runtimes with garbage collector based memory management.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/* Forward references */
+typedef struct vtshim_aux vtshim_aux;
+typedef struct vtshim_vtab vtshim_vtab;
+typedef struct vtshim_cursor vtshim_cursor;
+
+
+/* The vtshim_aux argument is the auxiliary parameter that is passed
+** into sqlite3_create_module_v2().
+*/
+struct vtshim_aux {
+ void *pChildAux; /* pAux for child virtual tables */
+ void (*xChildDestroy)(void*); /* Destructor for pChildAux */
+ sqlite3_module *pMod; /* Methods for child virtual tables */
+ sqlite3 *db; /* The database to which we are attached */
+ char *zName; /* Name of the module */
+ int bDisposed; /* True if disposed */
+ vtshim_vtab *pAllVtab; /* List of all vtshim_vtab objects */
+ sqlite3_module sSelf; /* Methods used by this shim */
+};
+
+/* A vtshim virtual table object */
+struct vtshim_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ sqlite3_vtab *pChild; /* Child virtual table */
+ vtshim_aux *pAux; /* Pointer to vtshim_aux object */
+ vtshim_cursor *pAllCur; /* List of all cursors */
+ vtshim_vtab **ppPrev; /* Previous on list */
+ vtshim_vtab *pNext; /* Next on list */
+};
+
+/* A vtshim cursor object */
+struct vtshim_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3_vtab_cursor *pChild; /* Cursor generated by the managed subclass */
+ vtshim_cursor **ppPrev; /* Previous on list of all cursors */
+ vtshim_cursor *pNext; /* Next on list of all cursors */
+};
+
+/* Macro used to copy the child vtable error message to outer vtable */
+#define VTSHIM_COPY_ERRMSG() \
+ do { \
+ sqlite3_free(pVtab->base.zErrMsg); \
+ pVtab->base.zErrMsg = sqlite3_mprintf("%s", pVtab->pChild->zErrMsg); \
+ } while (0)
+
+/* Methods for the vtshim module */
+static int vtshimCreate(
+ sqlite3 *db,
+ void *ppAux,
+ int argc,
+ const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ vtshim_aux *pAux = (vtshim_aux*)ppAux;
+ vtshim_vtab *pNew;
+ int rc;
+
+ assert( db==pAux->db );
+ if( pAux->bDisposed ){
+ if( pzErr ){
+ *pzErr = sqlite3_mprintf("virtual table was disposed: \"%s\"",
+ pAux->zName);
+ }
+ return SQLITE_ERROR;
+ }
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ rc = pAux->pMod->xCreate(db, pAux->pChildAux, argc, argv,
+ &pNew->pChild, pzErr);
+ if( rc ){
+ sqlite3_free(pNew);
+ *ppVtab = 0;
+ return rc;
+ }
+ pNew->pAux = pAux;
+ pNew->ppPrev = &pAux->pAllVtab;
+ pNew->pNext = pAux->pAllVtab;
+ if( pAux->pAllVtab ) pAux->pAllVtab->ppPrev = &pNew->pNext;
+ pAux->pAllVtab = pNew;
+ return rc;
+}
+
+static int vtshimConnect(
+ sqlite3 *db,
+ void *ppAux,
+ int argc,
+ const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ vtshim_aux *pAux = (vtshim_aux*)ppAux;
+ vtshim_vtab *pNew;
+ int rc;
+
+ assert( db==pAux->db );
+ if( pAux->bDisposed ){
+ if( pzErr ){
+ *pzErr = sqlite3_mprintf("virtual table was disposed: \"%s\"",
+ pAux->zName);
+ }
+ return SQLITE_ERROR;
+ }
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ rc = pAux->pMod->xConnect(db, pAux->pChildAux, argc, argv,
+ &pNew->pChild, pzErr);
+ if( rc ){
+ sqlite3_free(pNew);
+ *ppVtab = 0;
+ return rc;
+ }
+ pNew->pAux = pAux;
+ pNew->ppPrev = &pAux->pAllVtab;
+ pNew->pNext = pAux->pAllVtab;
+ if( pAux->pAllVtab ) pAux->pAllVtab->ppPrev = &pNew->pNext;
+ pAux->pAllVtab = pNew;
+ return rc;
+}
+
+static int vtshimBestIndex(
+ sqlite3_vtab *pBase,
+ sqlite3_index_info *pIdxInfo
+){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xBestIndex(pVtab->pChild, pIdxInfo);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimDisconnect(sqlite3_vtab *pBase){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc = SQLITE_OK;
+ if( !pAux->bDisposed ){
+ rc = pAux->pMod->xDisconnect(pVtab->pChild);
+ }
+ if( pVtab->pNext ) pVtab->pNext->ppPrev = pVtab->ppPrev;
+ *pVtab->ppPrev = pVtab->pNext;
+ sqlite3_free(pVtab);
+ return rc;
+}
+
+static int vtshimDestroy(sqlite3_vtab *pBase){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc = SQLITE_OK;
+ if( !pAux->bDisposed ){
+ rc = pAux->pMod->xDestroy(pVtab->pChild);
+ }
+ if( pVtab->pNext ) pVtab->pNext->ppPrev = pVtab->ppPrev;
+ *pVtab->ppPrev = pVtab->pNext;
+ sqlite3_free(pVtab);
+ return rc;
+}
+
+static int vtshimOpen(sqlite3_vtab *pBase, sqlite3_vtab_cursor **ppCursor){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ vtshim_cursor *pCur;
+ int rc;
+ *ppCursor = 0;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ rc = pAux->pMod->xOpen(pVtab->pChild, &pCur->pChild);
+ if( rc ){
+ sqlite3_free(pCur);
+ VTSHIM_COPY_ERRMSG();
+ return rc;
+ }
+ pCur->pChild->pVtab = pVtab->pChild;
+ *ppCursor = &pCur->base;
+ pCur->ppPrev = &pVtab->pAllCur;
+ if( pVtab->pAllCur ) pVtab->pAllCur->ppPrev = &pCur->pNext;
+ pCur->pNext = pVtab->pAllCur;
+ pVtab->pAllCur = pCur;
+ return SQLITE_OK;
+}
+
+static int vtshimClose(sqlite3_vtab_cursor *pX){
+ vtshim_cursor *pCur = (vtshim_cursor*)pX;
+ vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc = SQLITE_OK;
+ if( !pAux->bDisposed ){
+ rc = pAux->pMod->xClose(pCur->pChild);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ }
+ if( pCur->pNext ) pCur->pNext->ppPrev = pCur->ppPrev;
+ *pCur->ppPrev = pCur->pNext;
+ sqlite3_free(pCur);
+ return rc;
+}
+
+static int vtshimFilter(
+ sqlite3_vtab_cursor *pX,
+ int idxNum,
+ const char *idxStr,
+ int argc,
+ sqlite3_value **argv
+){
+ vtshim_cursor *pCur = (vtshim_cursor*)pX;
+ vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xFilter(pCur->pChild, idxNum, idxStr, argc, argv);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimNext(sqlite3_vtab_cursor *pX){
+ vtshim_cursor *pCur = (vtshim_cursor*)pX;
+ vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xNext(pCur->pChild);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimEof(sqlite3_vtab_cursor *pX){
+ vtshim_cursor *pCur = (vtshim_cursor*)pX;
+ vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return 1;
+ rc = pAux->pMod->xEof(pCur->pChild);
+ VTSHIM_COPY_ERRMSG();
+ return rc;
+}
+
+static int vtshimColumn(sqlite3_vtab_cursor *pX, sqlite3_context *ctx, int i){
+ vtshim_cursor *pCur = (vtshim_cursor*)pX;
+ vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xColumn(pCur->pChild, ctx, i);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimRowid(sqlite3_vtab_cursor *pX, sqlite3_int64 *pRowid){
+ vtshim_cursor *pCur = (vtshim_cursor*)pX;
+ vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xRowid(pCur->pChild, pRowid);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimUpdate(
+ sqlite3_vtab *pBase,
+ int argc,
+ sqlite3_value **argv,
+ sqlite3_int64 *pRowid
+){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xUpdate(pVtab->pChild, argc, argv, pRowid);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimBegin(sqlite3_vtab *pBase){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xBegin(pVtab->pChild);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimSync(sqlite3_vtab *pBase){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xSync(pVtab->pChild);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimCommit(sqlite3_vtab *pBase){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xCommit(pVtab->pChild);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimRollback(sqlite3_vtab *pBase){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xRollback(pVtab->pChild);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimFindFunction(
+ sqlite3_vtab *pBase,
+ int nArg,
+ const char *zName,
+ void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
+ void **ppArg
+){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return 0;
+ rc = pAux->pMod->xFindFunction(pVtab->pChild, nArg, zName, pxFunc, ppArg);
+ VTSHIM_COPY_ERRMSG();
+ return rc;
+}
+
+static int vtshimRename(sqlite3_vtab *pBase, const char *zNewName){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xRename(pVtab->pChild, zNewName);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimSavepoint(sqlite3_vtab *pBase, int n){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xSavepoint(pVtab->pChild, n);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimRelease(sqlite3_vtab *pBase, int n){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xRelease(pVtab->pChild, n);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+static int vtshimRollbackTo(sqlite3_vtab *pBase, int n){
+ vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
+ vtshim_aux *pAux = pVtab->pAux;
+ int rc;
+ if( pAux->bDisposed ) return SQLITE_ERROR;
+ rc = pAux->pMod->xRollbackTo(pVtab->pChild, n);
+ if( rc!=SQLITE_OK ){
+ VTSHIM_COPY_ERRMSG();
+ }
+ return rc;
+}
+
+/* The destructor function for a disposible module */
+static void vtshimAuxDestructor(void *pXAux){
+ vtshim_aux *pAux = (vtshim_aux*)pXAux;
+ assert( pAux->pAllVtab==0 );
+ if( !pAux->bDisposed && pAux->xChildDestroy ){
+ pAux->xChildDestroy(pAux->pChildAux);
+ pAux->xChildDestroy = 0;
+ }
+ sqlite3_free(pAux->zName);
+ sqlite3_free(pAux->pMod);
+ sqlite3_free(pAux);
+}
+
+static int vtshimCopyModule(
+ const sqlite3_module *pMod, /* Source module to be copied */
+ sqlite3_module **ppMod /* Destination for copied module */
+){
+ sqlite3_module *p;
+ if( !pMod || !ppMod ) return SQLITE_ERROR;
+ p = sqlite3_malloc( sizeof(*p) );
+ if( p==0 ) return SQLITE_NOMEM;
+ memcpy(p, pMod, sizeof(*p));
+ *ppMod = p;
+ return SQLITE_OK;
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+void *sqlite3_create_disposable_module(
+ sqlite3 *db, /* SQLite connection to register module with */
+ const char *zName, /* Name of the module */
+ const sqlite3_module *p, /* Methods for the module */
+ void *pClientData, /* Client data for xCreate/xConnect */
+ void(*xDestroy)(void*) /* Module destructor function */
+){
+ vtshim_aux *pAux;
+ sqlite3_module *pMod;
+ int rc;
+ pAux = sqlite3_malloc( sizeof(*pAux) );
+ if( pAux==0 ){
+ if( xDestroy ) xDestroy(pClientData);
+ return 0;
+ }
+ rc = vtshimCopyModule(p, &pMod);
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(pAux);
+ return 0;
+ }
+ pAux->pChildAux = pClientData;
+ pAux->xChildDestroy = xDestroy;
+ pAux->pMod = pMod;
+ pAux->db = db;
+ pAux->zName = sqlite3_mprintf("%s", zName);
+ pAux->bDisposed = 0;
+ pAux->pAllVtab = 0;
+ pAux->sSelf.iVersion = p->iVersion<=2 ? p->iVersion : 2;
+ pAux->sSelf.xCreate = p->xCreate ? vtshimCreate : 0;
+ pAux->sSelf.xConnect = p->xConnect ? vtshimConnect : 0;
+ pAux->sSelf.xBestIndex = p->xBestIndex ? vtshimBestIndex : 0;
+ pAux->sSelf.xDisconnect = p->xDisconnect ? vtshimDisconnect : 0;
+ pAux->sSelf.xDestroy = p->xDestroy ? vtshimDestroy : 0;
+ pAux->sSelf.xOpen = p->xOpen ? vtshimOpen : 0;
+ pAux->sSelf.xClose = p->xClose ? vtshimClose : 0;
+ pAux->sSelf.xFilter = p->xFilter ? vtshimFilter : 0;
+ pAux->sSelf.xNext = p->xNext ? vtshimNext : 0;
+ pAux->sSelf.xEof = p->xEof ? vtshimEof : 0;
+ pAux->sSelf.xColumn = p->xColumn ? vtshimColumn : 0;
+ pAux->sSelf.xRowid = p->xRowid ? vtshimRowid : 0;
+ pAux->sSelf.xUpdate = p->xUpdate ? vtshimUpdate : 0;
+ pAux->sSelf.xBegin = p->xBegin ? vtshimBegin : 0;
+ pAux->sSelf.xSync = p->xSync ? vtshimSync : 0;
+ pAux->sSelf.xCommit = p->xCommit ? vtshimCommit : 0;
+ pAux->sSelf.xRollback = p->xRollback ? vtshimRollback : 0;
+ pAux->sSelf.xFindFunction = p->xFindFunction ? vtshimFindFunction : 0;
+ pAux->sSelf.xRename = p->xRename ? vtshimRename : 0;
+ if( p->iVersion>=2 ){
+ pAux->sSelf.xSavepoint = p->xSavepoint ? vtshimSavepoint : 0;
+ pAux->sSelf.xRelease = p->xRelease ? vtshimRelease : 0;
+ pAux->sSelf.xRollbackTo = p->xRollbackTo ? vtshimRollbackTo : 0;
+ }else{
+ pAux->sSelf.xSavepoint = 0;
+ pAux->sSelf.xRelease = 0;
+ pAux->sSelf.xRollbackTo = 0;
+ }
+ rc = sqlite3_create_module_v2(db, zName, &pAux->sSelf,
+ pAux, vtshimAuxDestructor);
+ return rc==SQLITE_OK ? (void*)pAux : 0;
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+void sqlite3_dispose_module(void *pX){
+ vtshim_aux *pAux = (vtshim_aux*)pX;
+ if( !pAux->bDisposed ){
+ vtshim_vtab *pVtab;
+ vtshim_cursor *pCur;
+ for(pVtab=pAux->pAllVtab; pVtab; pVtab=pVtab->pNext){
+ for(pCur=pVtab->pAllCur; pCur; pCur=pCur->pNext){
+ pAux->pMod->xClose(pCur->pChild);
+ }
+ pAux->pMod->xDisconnect(pVtab->pChild);
+ }
+ pAux->bDisposed = 1;
+ if( pAux->xChildDestroy ){
+ pAux->xChildDestroy(pAux->pChildAux);
+ pAux->xChildDestroy = 0;
+ }
+ }
+}
+
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_vtshim_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi);
+ return SQLITE_OK;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ return sqlite3_vtshim_init(db, pzErrMsg, pApi);
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/wholenumber.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/wholenumber.c 2019-10-08 13:42:19.260886400 +0200
@@ -0,0 +1,283 @@
+/*
+** 2011 April 02
+**
+** 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 implements a virtual table that returns the whole numbers
+** between 1 and 4294967295, inclusive.
+**
+** Example:
+**
+** CREATE VIRTUAL TABLE nums USING wholenumber;
+** SELECT value FROM nums WHERE value<10;
+**
+** Results in:
+**
+** 1 2 3 4 5 6 7 8 9
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+
+/* A wholenumber cursor object */
+typedef struct wholenumber_cursor wholenumber_cursor;
+struct wholenumber_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3_int64 iValue; /* Current value */
+ sqlite3_int64 mxValue; /* Maximum value */
+};
+
+/* Methods for the wholenumber module */
+static int wholenumberConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ sqlite3_vtab *pNew;
+ pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
+ if( pNew==0 ) return SQLITE_NOMEM;
+ sqlite3_declare_vtab(db, "CREATE TABLE x(value)");
+ memset(pNew, 0, sizeof(*pNew));
+ return SQLITE_OK;
+}
+/* Note that for this virtual table, the xCreate and xConnect
+** methods are identical. */
+
+static int wholenumberDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+/* The xDisconnect and xDestroy methods are also the same */
+
+
+/*
+** Open a new wholenumber cursor.
+*/
+static int wholenumberOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ wholenumber_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Close a wholenumber cursor.
+*/
+static int wholenumberClose(sqlite3_vtab_cursor *cur){
+ sqlite3_free(cur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a cursor to its next row of output
+*/
+static int wholenumberNext(sqlite3_vtab_cursor *cur){
+ wholenumber_cursor *pCur = (wholenumber_cursor*)cur;
+ pCur->iValue++;
+ return SQLITE_OK;
+}
+
+/*
+** Return the value associated with a wholenumber.
+*/
+static int wholenumberColumn(
+ sqlite3_vtab_cursor *cur,
+ sqlite3_context *ctx,
+ int i
+){
+ wholenumber_cursor *pCur = (wholenumber_cursor*)cur;
+ sqlite3_result_int64(ctx, pCur->iValue);
+ return SQLITE_OK;
+}
+
+/*
+** The rowid.
+*/
+static int wholenumberRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ wholenumber_cursor *pCur = (wholenumber_cursor*)cur;
+ *pRowid = pCur->iValue;
+ return SQLITE_OK;
+}
+
+/*
+** When the wholenumber_cursor.rLimit value is 0 or less, that is a signal
+** that the cursor has nothing more to output.
+*/
+static int wholenumberEof(sqlite3_vtab_cursor *cur){
+ wholenumber_cursor *pCur = (wholenumber_cursor*)cur;
+ return pCur->iValue>pCur->mxValue || pCur->iValue==0;
+}
+
+/*
+** Called to "rewind" a cursor back to the beginning so that
+** it starts its output over again. Always called at least once
+** prior to any wholenumberColumn, wholenumberRowid, or wholenumberEof call.
+**
+** idxNum Constraints
+** ------ ---------------------
+** 0 (none)
+** 1 value > $argv0
+** 2 value >= $argv0
+** 4 value < $argv0
+** 8 value <= $argv0
+**
+** 5 value > $argv0 AND value < $argv1
+** 6 value >= $argv0 AND value < $argv1
+** 9 value > $argv0 AND value <= $argv1
+** 10 value >= $argv0 AND value <= $argv1
+*/
+static int wholenumberFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ wholenumber_cursor *pCur = (wholenumber_cursor *)pVtabCursor;
+ sqlite3_int64 v;
+ int i = 0;
+ pCur->iValue = 1;
+ pCur->mxValue = 0xffffffff; /* 4294967295 */
+ if( idxNum & 3 ){
+ v = sqlite3_value_int64(argv[0]) + (idxNum&1);
+ if( v>pCur->iValue && v<=pCur->mxValue ) pCur->iValue = v;
+ i++;
+ }
+ if( idxNum & 12 ){
+ v = sqlite3_value_int64(argv[i]) - ((idxNum>>2)&1);
+ if( v>=pCur->iValue && v<pCur->mxValue ) pCur->mxValue = v;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Search for terms of these forms:
+**
+** (1) value > $value
+** (2) value >= $value
+** (4) value < $value
+** (8) value <= $value
+**
+** idxNum is an ORed combination of 1 or 2 with 4 or 8.
+*/
+static int wholenumberBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int i;
+ int idxNum = 0;
+ int argvIdx = 1;
+ int ltIdx = -1;
+ int gtIdx = -1;
+ const struct sqlite3_index_constraint *pConstraint;
+ pConstraint = pIdxInfo->aConstraint;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
+ if( pConstraint->usable==0 ) continue;
+ if( (idxNum & 3)==0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_GT ){
+ idxNum |= 1;
+ ltIdx = i;
+ }
+ if( (idxNum & 3)==0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_GE ){
+ idxNum |= 2;
+ ltIdx = i;
+ }
+ if( (idxNum & 12)==0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ){
+ idxNum |= 4;
+ gtIdx = i;
+ }
+ if( (idxNum & 12)==0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE ){
+ idxNum |= 8;
+ gtIdx = i;
+ }
+ }
+ pIdxInfo->idxNum = idxNum;
+ if( ltIdx>=0 ){
+ pIdxInfo->aConstraintUsage[ltIdx].argvIndex = argvIdx++;
+ pIdxInfo->aConstraintUsage[ltIdx].omit = 1;
+ }
+ if( gtIdx>=0 ){
+ pIdxInfo->aConstraintUsage[gtIdx].argvIndex = argvIdx;
+ pIdxInfo->aConstraintUsage[gtIdx].omit = 1;
+ }
+ if( pIdxInfo->nOrderBy==1
+ && pIdxInfo->aOrderBy[0].desc==0
+ ){
+ pIdxInfo->orderByConsumed = 1;
+ }
+ if( (idxNum & 12)==0 ){
+ pIdxInfo->estimatedCost = (double)100000000;
+ }else if( (idxNum & 3)==0 ){
+ pIdxInfo->estimatedCost = (double)5;
+ }else{
+ pIdxInfo->estimatedCost = (double)1;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** A virtual table module that provides read-only access to a
+** Tcl global variable namespace.
+*/
+static const sqlite3_module wholenumberModule = {
+ 0, /* iVersion */
+ wholenumberConnect,
+ wholenumberConnect,
+ wholenumberBestIndex,
+ wholenumberDisconnect,
+ wholenumberDisconnect,
+ wholenumberOpen, /* xOpen - open a cursor */
+ wholenumberClose, /* xClose - close a cursor */
+ wholenumberFilter, /* xFilter - configure scan constraints */
+ wholenumberNext, /* xNext - advance a cursor */
+ wholenumberEof, /* xEof - check for end of scan */
+ wholenumberColumn, /* xColumn - read data */
+ wholenumberRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+};
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_wholenumber_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3_create_module(db, "wholenumber", &wholenumberModule, 0);
+#endif
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ return sqlite3_wholenumber_init(db, pzErrMsg, pApi);
+}
+#endif
--- origsrc/sqlite-autoconf-3300000/zipfile.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/zipfile.c 2019-10-08 13:42:19.264803400 +0200
@@ -0,0 +1,2183 @@
+/*
+** 2017-12-26
+**
+** 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 implements a virtual table for reading and writing ZIP archive
+** files.
+**
+** Usage example:
+**
+** SELECT name, sz, datetime(mtime,'unixepoch') FROM zipfile($filename);
+**
+** Current limitations:
+**
+** * No support for encryption
+** * No support for ZIP archives spanning multiple files
+** * No support for zip64 extensions
+** * Only the "inflate/deflate" (zlib) compression method is supported
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <zlib.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+#ifndef SQLITE_AMALGAMATION
+
+typedef sqlite3_int64 i64;
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+#ifndef MIN
+# define MIN(A,B) ((A)<(B)?(A):(B))
+#endif
+#ifndef MAX
+# define MAX(A,B) ((A)>(B)?(A):(B))
+#endif
+
+#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
+# define ALWAYS(X) (1)
+# define NEVER(X) (0)
+#elif !defined(NDEBUG)
+# define ALWAYS(X) ((X)?1:(assert(0),0))
+# define NEVER(X) ((X)?(assert(0),1):0)
+#else
+# define ALWAYS(X) (X)
+# define NEVER(X) (X)
+#endif
+
+#endif /* SQLITE_AMALGAMATION */
+
+/*
+** Definitions for mode bitmasks S_IFDIR, S_IFREG and S_IFLNK.
+**
+** In some ways it would be better to obtain these values from system
+** header files. But, the dependency is undesirable and (a) these
+** have been stable for decades, (b) the values are part of POSIX and
+** are also made explicit in [man stat], and (c) are part of the
+** file format for zip archives.
+*/
+#ifndef S_IFDIR
+# define S_IFDIR 0040000
+#endif
+#ifndef S_IFREG
+# define S_IFREG 0100000
+#endif
+#ifndef S_IFLNK
+# define S_IFLNK 0120000
+#endif
+
+static const char ZIPFILE_SCHEMA[] =
+ "CREATE TABLE y("
+ "name PRIMARY KEY," /* 0: Name of file in zip archive */
+ "mode," /* 1: POSIX mode for file */
+ "mtime," /* 2: Last modification time (secs since 1970)*/
+ "sz," /* 3: Size of object */
+ "rawdata," /* 4: Raw data */
+ "data," /* 5: Uncompressed data */
+ "method," /* 6: Compression method (integer) */
+ "z HIDDEN" /* 7: Name of zip file */
+ ") WITHOUT ROWID;";
+
+#define ZIPFILE_F_COLUMN_IDX 7 /* Index of column "file" in the above */
+#define ZIPFILE_BUFFER_SIZE (64*1024)
+
+
+/*
+** Magic numbers used to read and write zip files.
+**
+** ZIPFILE_NEWENTRY_MADEBY:
+** Use this value for the "version-made-by" field in new zip file
+** entries. The upper byte indicates "unix", and the lower byte
+** indicates that the zip file matches pkzip specification 3.0.
+** This is what info-zip seems to do.
+**
+** ZIPFILE_NEWENTRY_REQUIRED:
+** Value for "version-required-to-extract" field of new entries.
+** Version 2.0 is required to support folders and deflate compression.
+**
+** ZIPFILE_NEWENTRY_FLAGS:
+** Value for "general-purpose-bit-flags" field of new entries. Bit
+** 11 means "utf-8 filename and comment".
+**
+** ZIPFILE_SIGNATURE_CDS:
+** First 4 bytes of a valid CDS record.
+**
+** ZIPFILE_SIGNATURE_LFH:
+** First 4 bytes of a valid LFH record.
+**
+** ZIPFILE_SIGNATURE_EOCD
+** First 4 bytes of a valid EOCD record.
+*/
+#define ZIPFILE_EXTRA_TIMESTAMP 0x5455
+#define ZIPFILE_NEWENTRY_MADEBY ((3<<8) + 30)
+#define ZIPFILE_NEWENTRY_REQUIRED 20
+#define ZIPFILE_NEWENTRY_FLAGS 0x800
+#define ZIPFILE_SIGNATURE_CDS 0x02014b50
+#define ZIPFILE_SIGNATURE_LFH 0x04034b50
+#define ZIPFILE_SIGNATURE_EOCD 0x06054b50
+
+/*
+** The sizes of the fixed-size part of each of the three main data
+** structures in a zip archive.
+*/
+#define ZIPFILE_LFH_FIXED_SZ 30
+#define ZIPFILE_EOCD_FIXED_SZ 22
+#define ZIPFILE_CDS_FIXED_SZ 46
+
+/*
+*** 4.3.16 End of central directory record:
+***
+*** end of central dir signature 4 bytes (0x06054b50)
+*** number of this disk 2 bytes
+*** number of the disk with the
+*** start of the central directory 2 bytes
+*** total number of entries in the
+*** central directory on this disk 2 bytes
+*** total number of entries in
+*** the central directory 2 bytes
+*** size of the central directory 4 bytes
+*** offset of start of central
+*** directory with respect to
+*** the starting disk number 4 bytes
+*** .ZIP file comment length 2 bytes
+*** .ZIP file comment (variable size)
+*/
+typedef struct ZipfileEOCD ZipfileEOCD;
+struct ZipfileEOCD {
+ u16 iDisk;
+ u16 iFirstDisk;
+ u16 nEntry;
+ u16 nEntryTotal;
+ u32 nSize;
+ u32 iOffset;
+};
+
+/*
+*** 4.3.12 Central directory structure:
+***
+*** ...
+***
+*** central file header signature 4 bytes (0x02014b50)
+*** version made by 2 bytes
+*** version needed to extract 2 bytes
+*** general purpose bit flag 2 bytes
+*** compression method 2 bytes
+*** last mod file time 2 bytes
+*** last mod file date 2 bytes
+*** crc-32 4 bytes
+*** compressed size 4 bytes
+*** uncompressed size 4 bytes
+*** file name length 2 bytes
+*** extra field length 2 bytes
+*** file comment length 2 bytes
+*** disk number start 2 bytes
+*** internal file attributes 2 bytes
+*** external file attributes 4 bytes
+*** relative offset of local header 4 bytes
+*/
+typedef struct ZipfileCDS ZipfileCDS;
+struct ZipfileCDS {
+ u16 iVersionMadeBy;
+ u16 iVersionExtract;
+ u16 flags;
+ u16 iCompression;
+ u16 mTime;
+ u16 mDate;
+ u32 crc32;
+ u32 szCompressed;
+ u32 szUncompressed;
+ u16 nFile;
+ u16 nExtra;
+ u16 nComment;
+ u16 iDiskStart;
+ u16 iInternalAttr;
+ u32 iExternalAttr;
+ u32 iOffset;
+ char *zFile; /* Filename (sqlite3_malloc()) */
+};
+
+/*
+*** 4.3.7 Local file header:
+***
+*** local file header signature 4 bytes (0x04034b50)
+*** version needed to extract 2 bytes
+*** general purpose bit flag 2 bytes
+*** compression method 2 bytes
+*** last mod file time 2 bytes
+*** last mod file date 2 bytes
+*** crc-32 4 bytes
+*** compressed size 4 bytes
+*** uncompressed size 4 bytes
+*** file name length 2 bytes
+*** extra field length 2 bytes
+***
+*/
+typedef struct ZipfileLFH ZipfileLFH;
+struct ZipfileLFH {
+ u16 iVersionExtract;
+ u16 flags;
+ u16 iCompression;
+ u16 mTime;
+ u16 mDate;
+ u32 crc32;
+ u32 szCompressed;
+ u32 szUncompressed;
+ u16 nFile;
+ u16 nExtra;
+};
+
+typedef struct ZipfileEntry ZipfileEntry;
+struct ZipfileEntry {
+ ZipfileCDS cds; /* Parsed CDS record */
+ u32 mUnixTime; /* Modification time, in UNIX format */
+ u8 *aExtra; /* cds.nExtra+cds.nComment bytes of extra data */
+ i64 iDataOff; /* Offset to data in file (if aData==0) */
+ u8 *aData; /* cds.szCompressed bytes of compressed data */
+ ZipfileEntry *pNext; /* Next element in in-memory CDS */
+};
+
+/*
+** Cursor type for zipfile tables.
+*/
+typedef struct ZipfileCsr ZipfileCsr;
+struct ZipfileCsr {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ i64 iId; /* Cursor ID */
+ u8 bEof; /* True when at EOF */
+ u8 bNoop; /* If next xNext() call is no-op */
+
+ /* Used outside of write transactions */
+ FILE *pFile; /* Zip file */
+ i64 iNextOff; /* Offset of next record in central directory */
+ ZipfileEOCD eocd; /* Parse of central directory record */
+
+ ZipfileEntry *pFreeEntry; /* Free this list when cursor is closed or reset */
+ ZipfileEntry *pCurrent; /* Current entry */
+ ZipfileCsr *pCsrNext; /* Next cursor on same virtual table */
+};
+
+typedef struct ZipfileTab ZipfileTab;
+struct ZipfileTab {
+ sqlite3_vtab base; /* Base class - must be first */
+ char *zFile; /* Zip file this table accesses (may be NULL) */
+ sqlite3 *db; /* Host database connection */
+ u8 *aBuffer; /* Temporary buffer used for various tasks */
+
+ ZipfileCsr *pCsrList; /* List of cursors */
+ i64 iNextCsrid;
+
+ /* The following are used by write transactions only */
+ ZipfileEntry *pFirstEntry; /* Linked list of all files (if pWriteFd!=0) */
+ ZipfileEntry *pLastEntry; /* Last element in pFirstEntry list */
+ FILE *pWriteFd; /* File handle open on zip archive */
+ i64 szCurrent; /* Current size of zip archive */
+ i64 szOrig; /* Size of archive at start of transaction */
+};
+
+/*
+** Set the error message contained in context ctx to the results of
+** vprintf(zFmt, ...).
+*/
+static void zipfileCtxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){
+ char *zMsg = 0;
+ va_list ap;
+ va_start(ap, zFmt);
+ zMsg = sqlite3_vmprintf(zFmt, ap);
+ sqlite3_result_error(ctx, zMsg, -1);
+ sqlite3_free(zMsg);
+ va_end(ap);
+}
+
+/*
+** If string zIn is quoted, dequote it in place. Otherwise, if the string
+** is not quoted, do nothing.
+*/
+static void zipfileDequote(char *zIn){
+ char q = zIn[0];
+ if( q=='"' || q=='\'' || q=='`' || q=='[' ){
+ int iIn = 1;
+ int iOut = 0;
+ if( q=='[' ) q = ']';
+ while( ALWAYS(zIn[iIn]) ){
+ char c = zIn[iIn++];
+ if( c==q && zIn[iIn++]!=q ) break;
+ zIn[iOut++] = c;
+ }
+ zIn[iOut] = '\0';
+ }
+}
+
+/*
+** Construct a new ZipfileTab virtual table object.
+**
+** argv[0] -> module name ("zipfile")
+** argv[1] -> database name
+** argv[2] -> table name
+** argv[...] -> "column name" and other module argument fields.
+*/
+static int zipfileConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ size_t nByte = sizeof(ZipfileTab) + ZIPFILE_BUFFER_SIZE;
+ size_t nFile = 0;
+ const char *zFile = 0;
+ ZipfileTab *pNew = 0;
+ int rc;
+
+ /* If the table name is not "zipfile", require that the argument be
+ ** specified. This stops zipfile tables from being created as:
+ **
+ ** CREATE VIRTUAL TABLE zzz USING zipfile();
+ **
+ ** It does not prevent:
+ **
+ ** CREATE VIRTUAL TABLE zipfile USING zipfile();
+ */
+ assert( 0==sqlite3_stricmp(argv[0], "zipfile") );
+ if( (0!=sqlite3_stricmp(argv[2], "zipfile") && argc<4) || argc>4 ){
+ *pzErr = sqlite3_mprintf("zipfile constructor requires one argument");
+ return SQLITE_ERROR;
+ }
+
+ if( argc>3 ){
+ zFile = argv[3];
+ nFile = strlen(zFile)+1;
+ }
+
+ rc = sqlite3_declare_vtab(db, ZIPFILE_SCHEMA);
+ if( rc==SQLITE_OK ){
+ pNew = (ZipfileTab*)sqlite3_malloc(nByte+nFile);
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, nByte+nFile);
+ pNew->db = db;
+ pNew->aBuffer = (u8*)&pNew[1];
+ if( zFile ){
+ pNew->zFile = (char*)&pNew->aBuffer[ZIPFILE_BUFFER_SIZE];
+ memcpy(pNew->zFile, zFile, nFile);
+ zipfileDequote(pNew->zFile);
+ }
+ }
+ *ppVtab = (sqlite3_vtab*)pNew;
+ return rc;
+}
+
+/*
+** Free the ZipfileEntry structure indicated by the only argument.
+*/
+static void zipfileEntryFree(ZipfileEntry *p){
+ if( p ){
+ sqlite3_free(p->cds.zFile);
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Release resources that should be freed at the end of a write
+** transaction.
+*/
+static void zipfileCleanupTransaction(ZipfileTab *pTab){
+ ZipfileEntry *pEntry;
+ ZipfileEntry *pNext;
+
+ if( pTab->pWriteFd ){
+ fclose(pTab->pWriteFd);
+ pTab->pWriteFd = 0;
+ }
+ for(pEntry=pTab->pFirstEntry; pEntry; pEntry=pNext){
+ pNext = pEntry->pNext;
+ zipfileEntryFree(pEntry);
+ }
+ pTab->pFirstEntry = 0;
+ pTab->pLastEntry = 0;
+ pTab->szCurrent = 0;
+ pTab->szOrig = 0;
+}
+
+/*
+** This method is the destructor for zipfile vtab objects.
+*/
+static int zipfileDisconnect(sqlite3_vtab *pVtab){
+ zipfileCleanupTransaction((ZipfileTab*)pVtab);
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new ZipfileCsr object.
+*/
+static int zipfileOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCsr){
+ ZipfileTab *pTab = (ZipfileTab*)p;
+ ZipfileCsr *pCsr;
+ pCsr = sqlite3_malloc(sizeof(*pCsr));
+ *ppCsr = (sqlite3_vtab_cursor*)pCsr;
+ if( pCsr==0 ){
+ return SQLITE_NOMEM;
+ }
+ memset(pCsr, 0, sizeof(*pCsr));
+ pCsr->iId = ++pTab->iNextCsrid;
+ pCsr->pCsrNext = pTab->pCsrList;
+ pTab->pCsrList = pCsr;
+ return SQLITE_OK;
+}
+
+/*
+** Reset a cursor back to the state it was in when first returned
+** by zipfileOpen().
+*/
+static void zipfileResetCursor(ZipfileCsr *pCsr){
+ ZipfileEntry *p;
+ ZipfileEntry *pNext;
+
+ pCsr->bEof = 0;
+ if( pCsr->pFile ){
+ fclose(pCsr->pFile);
+ pCsr->pFile = 0;
+ zipfileEntryFree(pCsr->pCurrent);
+ pCsr->pCurrent = 0;
+ }
+
+ for(p=pCsr->pFreeEntry; p; p=pNext){
+ pNext = p->pNext;
+ zipfileEntryFree(p);
+ }
+}
+
+/*
+** Destructor for an ZipfileCsr.
+*/
+static int zipfileClose(sqlite3_vtab_cursor *cur){
+ ZipfileCsr *pCsr = (ZipfileCsr*)cur;
+ ZipfileTab *pTab = (ZipfileTab*)(pCsr->base.pVtab);
+ ZipfileCsr **pp;
+ zipfileResetCursor(pCsr);
+
+ /* Remove this cursor from the ZipfileTab.pCsrList list. */
+ for(pp=&pTab->pCsrList; *pp!=pCsr; pp=&((*pp)->pCsrNext));
+ *pp = pCsr->pCsrNext;
+
+ sqlite3_free(pCsr);
+ return SQLITE_OK;
+}
+
+/*
+** Set the error message for the virtual table associated with cursor
+** pCsr to the results of vprintf(zFmt, ...).
+*/
+static void zipfileTableErr(ZipfileTab *pTab, const char *zFmt, ...){
+ va_list ap;
+ va_start(ap, zFmt);
+ sqlite3_free(pTab->base.zErrMsg);
+ pTab->base.zErrMsg = sqlite3_vmprintf(zFmt, ap);
+ va_end(ap);
+}
+static void zipfileCursorErr(ZipfileCsr *pCsr, const char *zFmt, ...){
+ va_list ap;
+ va_start(ap, zFmt);
+ sqlite3_free(pCsr->base.pVtab->zErrMsg);
+ pCsr->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap);
+ va_end(ap);
+}
+
+/*
+** Read nRead bytes of data from offset iOff of file pFile into buffer
+** aRead[]. Return SQLITE_OK if successful, or an SQLite error code
+** otherwise.
+**
+** If an error does occur, output variable (*pzErrmsg) may be set to point
+** to an English language error message. It is the responsibility of the
+** caller to eventually free this buffer using
+** sqlite3_free().
+*/
+static int zipfileReadData(
+ FILE *pFile, /* Read from this file */
+ u8 *aRead, /* Read into this buffer */
+ int nRead, /* Number of bytes to read */
+ i64 iOff, /* Offset to read from */
+ char **pzErrmsg /* OUT: Error message (from sqlite3_malloc) */
+){
+ size_t n;
+ fseek(pFile, (long)iOff, SEEK_SET);
+ n = fread(aRead, 1, nRead, pFile);
+ if( (int)n!=nRead ){
+ *pzErrmsg = sqlite3_mprintf("error in fread()");
+ return SQLITE_ERROR;
+ }
+ return SQLITE_OK;
+}
+
+static int zipfileAppendData(
+ ZipfileTab *pTab,
+ const u8 *aWrite,
+ int nWrite
+){
+ size_t n;
+ fseek(pTab->pWriteFd, (long)pTab->szCurrent, SEEK_SET);
+ n = fwrite(aWrite, 1, nWrite, pTab->pWriteFd);
+ if( (int)n!=nWrite ){
+ pTab->base.zErrMsg = sqlite3_mprintf("error in fwrite()");
+ return SQLITE_ERROR;
+ }
+ pTab->szCurrent += nWrite;
+ return SQLITE_OK;
+}
+
+/*
+** Read and return a 16-bit little-endian unsigned integer from buffer aBuf.
+*/
+static u16 zipfileGetU16(const u8 *aBuf){
+ return (aBuf[1] << 8) + aBuf[0];
+}
+
+/*
+** Read and return a 32-bit little-endian unsigned integer from buffer aBuf.
+*/
+static u32 zipfileGetU32(const u8 *aBuf){
+ return ((u32)(aBuf[3]) << 24)
+ + ((u32)(aBuf[2]) << 16)
+ + ((u32)(aBuf[1]) << 8)
+ + ((u32)(aBuf[0]) << 0);
+}
+
+/*
+** Write a 16-bit little endiate integer into buffer aBuf.
+*/
+static void zipfilePutU16(u8 *aBuf, u16 val){
+ aBuf[0] = val & 0xFF;
+ aBuf[1] = (val>>8) & 0xFF;
+}
+
+/*
+** Write a 32-bit little endiate integer into buffer aBuf.
+*/
+static void zipfilePutU32(u8 *aBuf, u32 val){
+ aBuf[0] = val & 0xFF;
+ aBuf[1] = (val>>8) & 0xFF;
+ aBuf[2] = (val>>16) & 0xFF;
+ aBuf[3] = (val>>24) & 0xFF;
+}
+
+#define zipfileRead32(aBuf) ( aBuf+=4, zipfileGetU32(aBuf-4) )
+#define zipfileRead16(aBuf) ( aBuf+=2, zipfileGetU16(aBuf-2) )
+
+#define zipfileWrite32(aBuf,val) { zipfilePutU32(aBuf,val); aBuf+=4; }
+#define zipfileWrite16(aBuf,val) { zipfilePutU16(aBuf,val); aBuf+=2; }
+
+/*
+** Magic numbers used to read CDS records.
+*/
+#define ZIPFILE_CDS_NFILE_OFF 28
+#define ZIPFILE_CDS_SZCOMPRESSED_OFF 20
+
+/*
+** Decode the CDS record in buffer aBuf into (*pCDS). Return SQLITE_ERROR
+** if the record is not well-formed, or SQLITE_OK otherwise.
+*/
+static int zipfileReadCDS(u8 *aBuf, ZipfileCDS *pCDS){
+ u8 *aRead = aBuf;
+ u32 sig = zipfileRead32(aRead);
+ int rc = SQLITE_OK;
+ if( sig!=ZIPFILE_SIGNATURE_CDS ){
+ rc = SQLITE_ERROR;
+ }else{
+ pCDS->iVersionMadeBy = zipfileRead16(aRead);
+ pCDS->iVersionExtract = zipfileRead16(aRead);
+ pCDS->flags = zipfileRead16(aRead);
+ pCDS->iCompression = zipfileRead16(aRead);
+ pCDS->mTime = zipfileRead16(aRead);
+ pCDS->mDate = zipfileRead16(aRead);
+ pCDS->crc32 = zipfileRead32(aRead);
+ pCDS->szCompressed = zipfileRead32(aRead);
+ pCDS->szUncompressed = zipfileRead32(aRead);
+ assert( aRead==&aBuf[ZIPFILE_CDS_NFILE_OFF] );
+ pCDS->nFile = zipfileRead16(aRead);
+ pCDS->nExtra = zipfileRead16(aRead);
+ pCDS->nComment = zipfileRead16(aRead);
+ pCDS->iDiskStart = zipfileRead16(aRead);
+ pCDS->iInternalAttr = zipfileRead16(aRead);
+ pCDS->iExternalAttr = zipfileRead32(aRead);
+ pCDS->iOffset = zipfileRead32(aRead);
+ assert( aRead==&aBuf[ZIPFILE_CDS_FIXED_SZ] );
+ }
+
+ return rc;
+}
+
+/*
+** Decode the LFH record in buffer aBuf into (*pLFH). Return SQLITE_ERROR
+** if the record is not well-formed, or SQLITE_OK otherwise.
+*/
+static int zipfileReadLFH(
+ u8 *aBuffer,
+ ZipfileLFH *pLFH
+){
+ u8 *aRead = aBuffer;
+ int rc = SQLITE_OK;
+
+ u32 sig = zipfileRead32(aRead);
+ if( sig!=ZIPFILE_SIGNATURE_LFH ){
+ rc = SQLITE_ERROR;
+ }else{
+ pLFH->iVersionExtract = zipfileRead16(aRead);
+ pLFH->flags = zipfileRead16(aRead);
+ pLFH->iCompression = zipfileRead16(aRead);
+ pLFH->mTime = zipfileRead16(aRead);
+ pLFH->mDate = zipfileRead16(aRead);
+ pLFH->crc32 = zipfileRead32(aRead);
+ pLFH->szCompressed = zipfileRead32(aRead);
+ pLFH->szUncompressed = zipfileRead32(aRead);
+ pLFH->nFile = zipfileRead16(aRead);
+ pLFH->nExtra = zipfileRead16(aRead);
+ }
+ return rc;
+}
+
+
+/*
+** Buffer aExtra (size nExtra bytes) contains zip archive "extra" fields.
+** Scan through this buffer to find an "extra-timestamp" field. If one
+** exists, extract the 32-bit modification-timestamp from it and store
+** the value in output parameter *pmTime.
+**
+** Zero is returned if no extra-timestamp record could be found (and so
+** *pmTime is left unchanged), or non-zero otherwise.
+**
+** The general format of an extra field is:
+**
+** Header ID 2 bytes
+** Data Size 2 bytes
+** Data N bytes
+*/
+static int zipfileScanExtra(u8 *aExtra, int nExtra, u32 *pmTime){
+ int ret = 0;
+ u8 *p = aExtra;
+ u8 *pEnd = &aExtra[nExtra];
+
+ while( p<pEnd ){
+ u16 id = zipfileRead16(p);
+ u16 nByte = zipfileRead16(p);
+
+ switch( id ){
+ case ZIPFILE_EXTRA_TIMESTAMP: {
+ u8 b = p[0];
+ if( b & 0x01 ){ /* 0x01 -> modtime is present */
+ *pmTime = zipfileGetU32(&p[1]);
+ ret = 1;
+ }
+ break;
+ }
+ }
+
+ p += nByte;
+ }
+ return ret;
+}
+
+/*
+** Convert the standard MS-DOS timestamp stored in the mTime and mDate
+** fields of the CDS structure passed as the only argument to a 32-bit
+** UNIX seconds-since-the-epoch timestamp. Return the result.
+**
+** "Standard" MS-DOS time format:
+**
+** File modification time:
+** Bits 00-04: seconds divided by 2
+** Bits 05-10: minute
+** Bits 11-15: hour
+** File modification date:
+** Bits 00-04: day
+** Bits 05-08: month (1-12)
+** Bits 09-15: years from 1980
+**
+** https://msdn.microsoft.com/en-us/library/9kkf9tah.aspx
+*/
+static u32 zipfileMtime(ZipfileCDS *pCDS){
+ int Y = (1980 + ((pCDS->mDate >> 9) & 0x7F));
+ int M = ((pCDS->mDate >> 5) & 0x0F);
+ int D = (pCDS->mDate & 0x1F);
+ int B = -13;
+
+ int sec = (pCDS->mTime & 0x1F)*2;
+ int min = (pCDS->mTime >> 5) & 0x3F;
+ int hr = (pCDS->mTime >> 11) & 0x1F;
+ i64 JD;
+
+ /* JD = INT(365.25 * (Y+4716)) + INT(30.6001 * (M+1)) + D + B - 1524.5 */
+
+ /* Calculate the JD in seconds for noon on the day in question */
+ if( M<3 ){
+ Y = Y-1;
+ M = M+12;
+ }
+ JD = (i64)(24*60*60) * (
+ (int)(365.25 * (Y + 4716))
+ + (int)(30.6001 * (M + 1))
+ + D + B - 1524
+ );
+
+ /* Correct the JD for the time within the day */
+ JD += (hr-12) * 3600 + min * 60 + sec;
+
+ /* Convert JD to unix timestamp (the JD epoch is 2440587.5) */
+ return (u32)(JD - (i64)(24405875) * 24*60*6);
+}
+
+/*
+** The opposite of zipfileMtime(). This function populates the mTime and
+** mDate fields of the CDS structure passed as the first argument according
+** to the UNIX timestamp value passed as the second.
+*/
+static void zipfileMtimeToDos(ZipfileCDS *pCds, u32 mUnixTime){
+ /* Convert unix timestamp to JD (2440588 is noon on 1/1/1970) */
+ i64 JD = (i64)2440588 + mUnixTime / (24*60*60);
+
+ int A, B, C, D, E;
+ int yr, mon, day;
+ int hr, min, sec;
+
+ A = (int)((JD - 1867216.25)/36524.25);
+ A = (int)(JD + 1 + A - (A/4));
+ B = A + 1524;
+ C = (int)((B - 122.1)/365.25);
+ D = (36525*(C&32767))/100;
+ E = (int)((B-D)/30.6001);
+
+ day = B - D - (int)(30.6001*E);
+ mon = (E<14 ? E-1 : E-13);
+ yr = mon>2 ? C-4716 : C-4715;
+
+ hr = (mUnixTime % (24*60*60)) / (60*60);
+ min = (mUnixTime % (60*60)) / 60;
+ sec = (mUnixTime % 60);
+
+ if( yr>=1980 ){
+ pCds->mDate = (u16)(day + (mon << 5) + ((yr-1980) << 9));
+ pCds->mTime = (u16)(sec/2 + (min<<5) + (hr<<11));
+ }else{
+ pCds->mDate = pCds->mTime = 0;
+ }
+
+ assert( mUnixTime<315507600
+ || mUnixTime==zipfileMtime(pCds)
+ || ((mUnixTime % 2) && mUnixTime-1==zipfileMtime(pCds))
+ /* || (mUnixTime % 2) */
+ );
+}
+
+/*
+** If aBlob is not NULL, then it is a pointer to a buffer (nBlob bytes in
+** size) containing an entire zip archive image. Or, if aBlob is NULL,
+** then pFile is a file-handle open on a zip file. In either case, this
+** function creates a ZipfileEntry object based on the zip archive entry
+** for which the CDS record is at offset iOff.
+**
+** If successful, SQLITE_OK is returned and (*ppEntry) set to point to
+** the new object. Otherwise, an SQLite error code is returned and the
+** final value of (*ppEntry) undefined.
+*/
+static int zipfileGetEntry(
+ ZipfileTab *pTab, /* Store any error message here */
+ const u8 *aBlob, /* Pointer to in-memory file image */
+ int nBlob, /* Size of aBlob[] in bytes */
+ FILE *pFile, /* If aBlob==0, read from this file */
+ i64 iOff, /* Offset of CDS record */
+ ZipfileEntry **ppEntry /* OUT: Pointer to new object */
+){
+ u8 *aRead;
+ char **pzErr = &pTab->base.zErrMsg;
+ int rc = SQLITE_OK;
+
+ if( aBlob==0 ){
+ aRead = pTab->aBuffer;
+ rc = zipfileReadData(pFile, aRead, ZIPFILE_CDS_FIXED_SZ, iOff, pzErr);
+ }else{
+ aRead = (u8*)&aBlob[iOff];
+ }
+
+ if( rc==SQLITE_OK ){
+ size_t nAlloc;
+ ZipfileEntry *pNew;
+
+ int nFile = zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF]);
+ int nExtra = zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF+2]);
+ nExtra += zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF+4]);
+
+ nAlloc = sizeof(ZipfileEntry) + nExtra;
+ if( aBlob ){
+ nAlloc += zipfileGetU32(&aRead[ZIPFILE_CDS_SZCOMPRESSED_OFF]);
+ }
+
+ pNew = (ZipfileEntry*)sqlite3_malloc(nAlloc);
+ if( pNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(pNew, 0, sizeof(ZipfileEntry));
+ rc = zipfileReadCDS(aRead, &pNew->cds);
+ if( rc!=SQLITE_OK ){
+ *pzErr = sqlite3_mprintf("failed to read CDS at offset %lld", iOff);
+ }else if( aBlob==0 ){
+ rc = zipfileReadData(
+ pFile, aRead, nExtra+nFile, iOff+ZIPFILE_CDS_FIXED_SZ, pzErr
+ );
+ }else{
+ aRead = (u8*)&aBlob[iOff + ZIPFILE_CDS_FIXED_SZ];
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ u32 *pt = &pNew->mUnixTime;
+ pNew->cds.zFile = sqlite3_mprintf("%.*s", nFile, aRead);
+ pNew->aExtra = (u8*)&pNew[1];
+ memcpy(pNew->aExtra, &aRead[nFile], nExtra);
+ if( pNew->cds.zFile==0 ){
+ rc = SQLITE_NOMEM;
+ }else if( 0==zipfileScanExtra(&aRead[nFile], pNew->cds.nExtra, pt) ){
+ pNew->mUnixTime = zipfileMtime(&pNew->cds);
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ static const int szFix = ZIPFILE_LFH_FIXED_SZ;
+ ZipfileLFH lfh;
+ if( pFile ){
+ rc = zipfileReadData(pFile, aRead, szFix, pNew->cds.iOffset, pzErr);
+ }else{
+ aRead = (u8*)&aBlob[pNew->cds.iOffset];
+ }
+
+ rc = zipfileReadLFH(aRead, &lfh);
+ if( rc==SQLITE_OK ){
+ pNew->iDataOff = pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ;
+ pNew->iDataOff += lfh.nFile + lfh.nExtra;
+ if( aBlob && pNew->cds.szCompressed ){
+ pNew->aData = &pNew->aExtra[nExtra];
+ memcpy(pNew->aData, &aBlob[pNew->iDataOff], pNew->cds.szCompressed);
+ }
+ }else{
+ *pzErr = sqlite3_mprintf("failed to read LFH at offset %d",
+ (int)pNew->cds.iOffset
+ );
+ }
+ }
+
+ if( rc!=SQLITE_OK ){
+ zipfileEntryFree(pNew);
+ }else{
+ *ppEntry = pNew;
+ }
+ }
+
+ return rc;
+}
+
+/*
+** Advance an ZipfileCsr to its next row of output.
+*/
+static int zipfileNext(sqlite3_vtab_cursor *cur){
+ ZipfileCsr *pCsr = (ZipfileCsr*)cur;
+ int rc = SQLITE_OK;
+
+ if( pCsr->pFile ){
+ i64 iEof = pCsr->eocd.iOffset + pCsr->eocd.nSize;
+ zipfileEntryFree(pCsr->pCurrent);
+ pCsr->pCurrent = 0;
+ if( pCsr->iNextOff>=iEof ){
+ pCsr->bEof = 1;
+ }else{
+ ZipfileEntry *p = 0;
+ ZipfileTab *pTab = (ZipfileTab*)(cur->pVtab);
+ rc = zipfileGetEntry(pTab, 0, 0, pCsr->pFile, pCsr->iNextOff, &p);
+ if( rc==SQLITE_OK ){
+ pCsr->iNextOff += ZIPFILE_CDS_FIXED_SZ;
+ pCsr->iNextOff += (int)p->cds.nExtra + p->cds.nFile + p->cds.nComment;
+ }
+ pCsr->pCurrent = p;
+ }
+ }else{
+ if( !pCsr->bNoop ){
+ pCsr->pCurrent = pCsr->pCurrent->pNext;
+ }
+ if( pCsr->pCurrent==0 ){
+ pCsr->bEof = 1;
+ }
+ }
+
+ pCsr->bNoop = 0;
+ return rc;
+}
+
+static void zipfileFree(void *p) {
+ sqlite3_free(p);
+}
+
+/*
+** Buffer aIn (size nIn bytes) contains compressed data. Uncompressed, the
+** size is nOut bytes. This function uncompresses the data and sets the
+** return value in context pCtx to the result (a blob).
+**
+** If an error occurs, an error code is left in pCtx instead.
+*/
+static void zipfileInflate(
+ sqlite3_context *pCtx, /* Store result here */
+ const u8 *aIn, /* Compressed data */
+ int nIn, /* Size of buffer aIn[] in bytes */
+ int nOut /* Expected output size */
+){
+ u8 *aRes = sqlite3_malloc(nOut);
+ if( aRes==0 ){
+ sqlite3_result_error_nomem(pCtx);
+ }else{
+ int err;
+ z_stream str;
+ memset(&str, 0, sizeof(str));
+
+ str.next_in = (Byte*)aIn;
+ str.avail_in = nIn;
+ str.next_out = (Byte*)aRes;
+ str.avail_out = nOut;
+
+ err = inflateInit2(&str, -15);
+ if( err!=Z_OK ){
+ zipfileCtxErrorMsg(pCtx, "inflateInit2() failed (%d)", err);
+ }else{
+ err = inflate(&str, Z_NO_FLUSH);
+ if( err!=Z_STREAM_END ){
+ zipfileCtxErrorMsg(pCtx, "inflate() failed (%d)", err);
+ }else{
+ sqlite3_result_blob(pCtx, aRes, nOut, zipfileFree);
+ aRes = 0;
+ }
+ }
+ sqlite3_free(aRes);
+ inflateEnd(&str);
+ }
+}
+
+/*
+** Buffer aIn (size nIn bytes) contains uncompressed data. This function
+** compresses it and sets (*ppOut) to point to a buffer containing the
+** compressed data. The caller is responsible for eventually calling
+** sqlite3_free() to release buffer (*ppOut). Before returning, (*pnOut)
+** is set to the size of buffer (*ppOut) in bytes.
+**
+** If no error occurs, SQLITE_OK is returned. Otherwise, an SQLite error
+** code is returned and an error message left in virtual-table handle
+** pTab. The values of (*ppOut) and (*pnOut) are left unchanged in this
+** case.
+*/
+static int zipfileDeflate(
+ const u8 *aIn, size_t nIn, /* Input */
+ u8 **ppOut, size_t *pnOut, /* Output */
+ char **pzErr /* OUT: Error message */
+){
+ size_t nAlloc = compressBound(nIn);
+ u8 *aOut;
+ int rc = SQLITE_OK;
+
+ aOut = (u8*)sqlite3_malloc(nAlloc);
+ if( aOut==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ int res;
+ z_stream str;
+ memset(&str, 0, sizeof(str));
+ str.next_in = (Bytef*)aIn;
+ str.avail_in = nIn;
+ str.next_out = aOut;
+ str.avail_out = nAlloc;
+
+ deflateInit2(&str, 9, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
+ res = deflate(&str, Z_FINISH);
+
+ if( res==Z_STREAM_END ){
+ *ppOut = aOut;
+ *pnOut = str.total_out;
+ }else{
+ sqlite3_free(aOut);
+ *pzErr = sqlite3_mprintf("zipfile: deflate() error");
+ rc = SQLITE_ERROR;
+ }
+ deflateEnd(&str);
+ }
+
+ return rc;
+}
+
+
+/*
+** Return values of columns for the row at which the series_cursor
+** is currently pointing.
+*/
+static int zipfileColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ ZipfileCsr *pCsr = (ZipfileCsr*)cur;
+ ZipfileCDS *pCDS = &pCsr->pCurrent->cds;
+ int rc = SQLITE_OK;
+ switch( i ){
+ case 0: /* name */
+ sqlite3_result_text(ctx, pCDS->zFile, -1, SQLITE_TRANSIENT);
+ break;
+ case 1: /* mode */
+ /* TODO: Whether or not the following is correct surely depends on
+ ** the platform on which the archive was created. */
+ sqlite3_result_int(ctx, pCDS->iExternalAttr >> 16);
+ break;
+ case 2: { /* mtime */
+ sqlite3_result_int64(ctx, pCsr->pCurrent->mUnixTime);
+ break;
+ }
+ case 3: { /* sz */
+ if( sqlite3_vtab_nochange(ctx)==0 ){
+ sqlite3_result_int64(ctx, pCDS->szUncompressed);
+ }
+ break;
+ }
+ case 4: /* rawdata */
+ if( sqlite3_vtab_nochange(ctx) ) break;
+ case 5: { /* data */
+ if( i==4 || pCDS->iCompression==0 || pCDS->iCompression==8 ){
+ size_t sz = pCDS->szCompressed;
+ size_t szFinal = pCDS->szUncompressed;
+ if( szFinal>0 ){
+ u8 *aBuf;
+ u8 *aFree = 0;
+ if( pCsr->pCurrent->aData ){
+ aBuf = pCsr->pCurrent->aData;
+ }else{
+ aBuf = aFree = sqlite3_malloc(sz);
+ if( aBuf==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ FILE *pFile = pCsr->pFile;
+ if( pFile==0 ){
+ pFile = ((ZipfileTab*)(pCsr->base.pVtab))->pWriteFd;
+ }
+ rc = zipfileReadData(pFile, aBuf, sz, pCsr->pCurrent->iDataOff,
+ &pCsr->base.pVtab->zErrMsg
+ );
+ }
+ }
+ if( rc==SQLITE_OK ){
+ if( i==5 && pCDS->iCompression ){
+ zipfileInflate(ctx, aBuf, sz, szFinal);
+ }else{
+ sqlite3_result_blob(ctx, aBuf, sz, SQLITE_TRANSIENT);
+ }
+ }
+ sqlite3_free(aFree);
+ }else{
+ /* Figure out if this is a directory or a zero-sized file. Consider
+ ** it to be a directory either if the mode suggests so, or if
+ ** the final character in the name is '/'. */
+ u32 mode = pCDS->iExternalAttr >> 16;
+ if( !(mode & S_IFDIR) && pCDS->zFile[pCDS->nFile-1]!='/' ){
+ sqlite3_result_blob(ctx, "", 0, SQLITE_STATIC);
+ }
+ }
+ }
+ break;
+ }
+ case 6: /* method */
+ sqlite3_result_int(ctx, pCDS->iCompression);
+ break;
+ default: /* z */
+ assert( i==7 );
+ sqlite3_result_int64(ctx, pCsr->iId);
+ break;
+ }
+
+ return rc;
+}
+
+/*
+** Return TRUE if the cursor is at EOF.
+*/
+static int zipfileEof(sqlite3_vtab_cursor *cur){
+ ZipfileCsr *pCsr = (ZipfileCsr*)cur;
+ return pCsr->bEof;
+}
+
+/*
+** If aBlob is not NULL, then it points to a buffer nBlob bytes in size
+** containing an entire zip archive image. Or, if aBlob is NULL, then pFile
+** is guaranteed to be a file-handle open on a zip file.
+**
+** This function attempts to locate the EOCD record within the zip archive
+** and populate *pEOCD with the results of decoding it. SQLITE_OK is
+** returned if successful. Otherwise, an SQLite error code is returned and
+** an English language error message may be left in virtual-table pTab.
+*/
+static int zipfileReadEOCD(
+ ZipfileTab *pTab, /* Return errors here */
+ const u8 *aBlob, /* Pointer to in-memory file image */
+ int nBlob, /* Size of aBlob[] in bytes */
+ FILE *pFile, /* Read from this file if aBlob==0 */
+ ZipfileEOCD *pEOCD /* Object to populate */
+){
+ u8 *aRead = pTab->aBuffer; /* Temporary buffer */
+ int nRead; /* Bytes to read from file */
+ int rc = SQLITE_OK;
+
+ if( aBlob==0 ){
+ i64 iOff; /* Offset to read from */
+ i64 szFile; /* Total size of file in bytes */
+ fseek(pFile, 0, SEEK_END);
+ szFile = (i64)ftell(pFile);
+ if( szFile==0 ){
+ memset(pEOCD, 0, sizeof(ZipfileEOCD));
+ return SQLITE_OK;
+ }
+ nRead = (int)(MIN(szFile, ZIPFILE_BUFFER_SIZE));
+ iOff = szFile - nRead;
+ rc = zipfileReadData(pFile, aRead, nRead, iOff, &pTab->base.zErrMsg);
+ }else{
+ nRead = (int)(MIN(nBlob, ZIPFILE_BUFFER_SIZE));
+ aRead = (u8*)&aBlob[nBlob-nRead];
+ }
+
+ if( rc==SQLITE_OK ){
+ int i;
+
+ /* Scan backwards looking for the signature bytes */
+ for(i=nRead-20; i>=0; i--){
+ if( aRead[i]==0x50 && aRead[i+1]==0x4b
+ && aRead[i+2]==0x05 && aRead[i+3]==0x06
+ ){
+ break;
+ }
+ }
+ if( i<0 ){
+ pTab->base.zErrMsg = sqlite3_mprintf(
+ "cannot find end of central directory record"
+ );
+ return SQLITE_ERROR;
+ }
+
+ aRead += i+4;
+ pEOCD->iDisk = zipfileRead16(aRead);
+ pEOCD->iFirstDisk = zipfileRead16(aRead);
+ pEOCD->nEntry = zipfileRead16(aRead);
+ pEOCD->nEntryTotal = zipfileRead16(aRead);
+ pEOCD->nSize = zipfileRead32(aRead);
+ pEOCD->iOffset = zipfileRead32(aRead);
+ }
+
+ return rc;
+}
+
+/*
+** Add object pNew to the linked list that begins at ZipfileTab.pFirstEntry
+** and ends with pLastEntry. If argument pBefore is NULL, then pNew is added
+** to the end of the list. Otherwise, it is added to the list immediately
+** before pBefore (which is guaranteed to be a part of said list).
+*/
+static void zipfileAddEntry(
+ ZipfileTab *pTab,
+ ZipfileEntry *pBefore,
+ ZipfileEntry *pNew
+){
+ assert( (pTab->pFirstEntry==0)==(pTab->pLastEntry==0) );
+ assert( pNew->pNext==0 );
+ if( pBefore==0 ){
+ if( pTab->pFirstEntry==0 ){
+ pTab->pFirstEntry = pTab->pLastEntry = pNew;
+ }else{
+ assert( pTab->pLastEntry->pNext==0 );
+ pTab->pLastEntry->pNext = pNew;
+ pTab->pLastEntry = pNew;
+ }
+ }else{
+ ZipfileEntry **pp;
+ for(pp=&pTab->pFirstEntry; *pp!=pBefore; pp=&((*pp)->pNext));
+ pNew->pNext = pBefore;
+ *pp = pNew;
+ }
+}
+
+static int zipfileLoadDirectory(ZipfileTab *pTab, const u8 *aBlob, int nBlob){
+ ZipfileEOCD eocd;
+ int rc;
+ int i;
+ i64 iOff;
+
+ rc = zipfileReadEOCD(pTab, aBlob, nBlob, pTab->pWriteFd, &eocd);
+ iOff = eocd.iOffset;
+ for(i=0; rc==SQLITE_OK && i<eocd.nEntry; i++){
+ ZipfileEntry *pNew = 0;
+ rc = zipfileGetEntry(pTab, aBlob, nBlob, pTab->pWriteFd, iOff, &pNew);
+
+ if( rc==SQLITE_OK ){
+ zipfileAddEntry(pTab, 0, pNew);
+ iOff += ZIPFILE_CDS_FIXED_SZ;
+ iOff += (int)pNew->cds.nExtra + pNew->cds.nFile + pNew->cds.nComment;
+ }
+ }
+ return rc;
+}
+
+/*
+** xFilter callback.
+*/
+static int zipfileFilter(
+ sqlite3_vtab_cursor *cur,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ ZipfileTab *pTab = (ZipfileTab*)cur->pVtab;
+ ZipfileCsr *pCsr = (ZipfileCsr*)cur;
+ const char *zFile = 0; /* Zip file to scan */
+ int rc = SQLITE_OK; /* Return Code */
+ int bInMemory = 0; /* True for an in-memory zipfile */
+
+ zipfileResetCursor(pCsr);
+
+ if( pTab->zFile ){
+ zFile = pTab->zFile;
+ }else if( idxNum==0 ){
+ zipfileCursorErr(pCsr, "zipfile() function requires an argument");
+ return SQLITE_ERROR;
+ }else if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
+ const u8 *aBlob = (const u8*)sqlite3_value_blob(argv[0]);
+ int nBlob = sqlite3_value_bytes(argv[0]);
+ assert( pTab->pFirstEntry==0 );
+ rc = zipfileLoadDirectory(pTab, aBlob, nBlob);
+ pCsr->pFreeEntry = pTab->pFirstEntry;
+ pTab->pFirstEntry = pTab->pLastEntry = 0;
+ if( rc!=SQLITE_OK ) return rc;
+ bInMemory = 1;
+ }else{
+ zFile = (const char*)sqlite3_value_text(argv[0]);
+ }
+
+ if( 0==pTab->pWriteFd && 0==bInMemory ){
+ pCsr->pFile = fopen(zFile, "rb");
+ if( pCsr->pFile==0 ){
+ zipfileCursorErr(pCsr, "cannot open file: %s", zFile);
+ rc = SQLITE_ERROR;
+ }else{
+ rc = zipfileReadEOCD(pTab, 0, 0, pCsr->pFile, &pCsr->eocd);
+ if( rc==SQLITE_OK ){
+ if( pCsr->eocd.nEntry==0 ){
+ pCsr->bEof = 1;
+ }else{
+ pCsr->iNextOff = pCsr->eocd.iOffset;
+ rc = zipfileNext(cur);
+ }
+ }
+ }
+ }else{
+ pCsr->bNoop = 1;
+ pCsr->pCurrent = pCsr->pFreeEntry ? pCsr->pFreeEntry : pTab->pFirstEntry;
+ rc = zipfileNext(cur);
+ }
+
+ return rc;
+}
+
+/*
+** xBestIndex callback.
+*/
+static int zipfileBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int i;
+ int idx = -1;
+ int unusable = 0;
+
+ for(i=0; i<pIdxInfo->nConstraint; i++){
+ const struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i];
+ if( pCons->iColumn!=ZIPFILE_F_COLUMN_IDX ) continue;
+ if( pCons->usable==0 ){
+ unusable = 1;
+ }else if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ idx = i;
+ }
+ }
+ if( idx>=0 ){
+ pIdxInfo->aConstraintUsage[idx].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[idx].omit = 1;
+ pIdxInfo->estimatedCost = 1000.0;
+ pIdxInfo->idxNum = 1;
+ }else if( unusable ){
+ return SQLITE_CONSTRAINT;
+ }
+ return SQLITE_OK;
+}
+
+static ZipfileEntry *zipfileNewEntry(const char *zPath){
+ ZipfileEntry *pNew;
+ pNew = sqlite3_malloc(sizeof(ZipfileEntry));
+ if( pNew ){
+ memset(pNew, 0, sizeof(ZipfileEntry));
+ pNew->cds.zFile = sqlite3_mprintf("%s", zPath);
+ if( pNew->cds.zFile==0 ){
+ sqlite3_free(pNew);
+ pNew = 0;
+ }
+ }
+ return pNew;
+}
+
+static int zipfileSerializeLFH(ZipfileEntry *pEntry, u8 *aBuf){
+ ZipfileCDS *pCds = &pEntry->cds;
+ u8 *a = aBuf;
+
+ pCds->nExtra = 9;
+
+ /* Write the LFH itself */
+ zipfileWrite32(a, ZIPFILE_SIGNATURE_LFH);
+ zipfileWrite16(a, pCds->iVersionExtract);
+ zipfileWrite16(a, pCds->flags);
+ zipfileWrite16(a, pCds->iCompression);
+ zipfileWrite16(a, pCds->mTime);
+ zipfileWrite16(a, pCds->mDate);
+ zipfileWrite32(a, pCds->crc32);
+ zipfileWrite32(a, pCds->szCompressed);
+ zipfileWrite32(a, pCds->szUncompressed);
+ zipfileWrite16(a, (u16)pCds->nFile);
+ zipfileWrite16(a, pCds->nExtra);
+ assert( a==&aBuf[ZIPFILE_LFH_FIXED_SZ] );
+
+ /* Add the file name */
+ memcpy(a, pCds->zFile, (int)pCds->nFile);
+ a += (int)pCds->nFile;
+
+ /* The "extra" data */
+ zipfileWrite16(a, ZIPFILE_EXTRA_TIMESTAMP);
+ zipfileWrite16(a, 5);
+ *a++ = 0x01;
+ zipfileWrite32(a, pEntry->mUnixTime);
+
+ return a-aBuf;
+}
+
+static int zipfileAppendEntry(
+ ZipfileTab *pTab,
+ ZipfileEntry *pEntry,
+ const u8 *pData,
+ int nData
+){
+ u8 *aBuf = pTab->aBuffer;
+ int nBuf;
+ int rc;
+
+ nBuf = zipfileSerializeLFH(pEntry, aBuf);
+ rc = zipfileAppendData(pTab, aBuf, nBuf);
+ if( rc==SQLITE_OK ){
+ pEntry->iDataOff = pTab->szCurrent;
+ rc = zipfileAppendData(pTab, pData, nData);
+ }
+
+ return rc;
+}
+
+static int zipfileGetMode(
+ sqlite3_value *pVal,
+ int bIsDir, /* If true, default to directory */
+ u32 *pMode, /* OUT: Mode value */
+ char **pzErr /* OUT: Error message */
+){
+ const char *z = (const char*)sqlite3_value_text(pVal);
+ u32 mode = 0;
+ if( z==0 ){
+ mode = (bIsDir ? (S_IFDIR + 0755) : (S_IFREG + 0644));
+ }else if( z[0]>='0' && z[0]<='9' ){
+ mode = (unsigned int)sqlite3_value_int(pVal);
+ }else{
+ const char zTemplate[11] = "-rwxrwxrwx";
+ int i;
+ if( strlen(z)!=10 ) goto parse_error;
+ switch( z[0] ){
+ case '-': mode |= S_IFREG; break;
+ case 'd': mode |= S_IFDIR; break;
+ case 'l': mode |= S_IFLNK; break;
+ default: goto parse_error;
+ }
+ for(i=1; i<10; i++){
+ if( z[i]==zTemplate[i] ) mode |= 1 << (9-i);
+ else if( z[i]!='-' ) goto parse_error;
+ }
+ }
+ if( ((mode & S_IFDIR)==0)==bIsDir ){
+ /* The "mode" attribute is a directory, but data has been specified.
+ ** Or vice-versa - no data but "mode" is a file or symlink. */
+ *pzErr = sqlite3_mprintf("zipfile: mode does not match data");
+ return SQLITE_CONSTRAINT;
+ }
+ *pMode = mode;
+ return SQLITE_OK;
+
+ parse_error:
+ *pzErr = sqlite3_mprintf("zipfile: parse error in mode: %s", z);
+ return SQLITE_ERROR;
+}
+
+/*
+** Both (const char*) arguments point to nul-terminated strings. Argument
+** nB is the value of strlen(zB). This function returns 0 if the strings are
+** identical, ignoring any trailing '/' character in either path. */
+static int zipfileComparePath(const char *zA, const char *zB, int nB){
+ int nA = (int)strlen(zA);
+ if( zA[nA-1]=='/' ) nA--;
+ if( zB[nB-1]=='/' ) nB--;
+ if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0;
+ return 1;
+}
+
+static int zipfileBegin(sqlite3_vtab *pVtab){
+ ZipfileTab *pTab = (ZipfileTab*)pVtab;
+ int rc = SQLITE_OK;
+
+ assert( pTab->pWriteFd==0 );
+
+ /* Open a write fd on the file. Also load the entire central directory
+ ** structure into memory. During the transaction any new file data is
+ ** appended to the archive file, but the central directory is accumulated
+ ** in main-memory until the transaction is committed. */
+ pTab->pWriteFd = fopen(pTab->zFile, "ab+");
+ if( pTab->pWriteFd==0 ){
+ pTab->base.zErrMsg = sqlite3_mprintf(
+ "zipfile: failed to open file %s for writing", pTab->zFile
+ );
+ rc = SQLITE_ERROR;
+ }else{
+ fseek(pTab->pWriteFd, 0, SEEK_END);
+ pTab->szCurrent = pTab->szOrig = (i64)ftell(pTab->pWriteFd);
+ rc = zipfileLoadDirectory(pTab, 0, 0);
+ }
+
+ if( rc!=SQLITE_OK ){
+ zipfileCleanupTransaction(pTab);
+ }
+
+ return rc;
+}
+
+/*
+** Return the current time as a 32-bit timestamp in UNIX epoch format (like
+** time(2)).
+*/
+static u32 zipfileTime(void){
+ sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
+ u32 ret;
+ if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){
+ i64 ms;
+ pVfs->xCurrentTimeInt64(pVfs, &ms);
+ ret = (u32)((ms/1000) - ((i64)24405875 * 8640));
+ }else{
+ double day;
+ pVfs->xCurrentTime(pVfs, &day);
+ ret = (u32)((day - 2440587.5) * 86400);
+ }
+ return ret;
+}
+
+/*
+** Return a 32-bit timestamp in UNIX epoch format.
+**
+** If the value passed as the only argument is either NULL or an SQL NULL,
+** return the current time. Otherwise, return the value stored in (*pVal)
+** cast to a 32-bit unsigned integer.
+*/
+static u32 zipfileGetTime(sqlite3_value *pVal){
+ if( pVal==0 || sqlite3_value_type(pVal)==SQLITE_NULL ){
+ return zipfileTime();
+ }
+ return (u32)sqlite3_value_int64(pVal);
+}
+
+/*
+** Unless it is NULL, entry pOld is currently part of the pTab->pFirstEntry
+** linked list. Remove it from the list and free the object.
+*/
+static void zipfileRemoveEntryFromList(ZipfileTab *pTab, ZipfileEntry *pOld){
+ if( pOld ){
+ ZipfileEntry **pp;
+ for(pp=&pTab->pFirstEntry; (*pp)!=pOld; pp=&((*pp)->pNext));
+ *pp = (*pp)->pNext;
+ zipfileEntryFree(pOld);
+ }
+}
+
+/*
+** xUpdate method.
+*/
+static int zipfileUpdate(
+ sqlite3_vtab *pVtab,
+ int nVal,
+ sqlite3_value **apVal,
+ sqlite_int64 *pRowid
+){
+ ZipfileTab *pTab = (ZipfileTab*)pVtab;
+ int rc = SQLITE_OK; /* Return Code */
+ ZipfileEntry *pNew = 0; /* New in-memory CDS entry */
+
+ u32 mode = 0; /* Mode for new entry */
+ u32 mTime = 0; /* Modification time for new entry */
+ i64 sz = 0; /* Uncompressed size */
+ const char *zPath = 0; /* Path for new entry */
+ int nPath = 0; /* strlen(zPath) */
+ const u8 *pData = 0; /* Pointer to buffer containing content */
+ size_t nData = 0; /* Size of pData buffer in bytes */
+ int iMethod = 0; /* Compression method for new entry */
+ u8 *pFree = 0; /* Free this */
+ char *zFree = 0; /* Also free this */
+ ZipfileEntry *pOld = 0;
+ ZipfileEntry *pOld2 = 0;
+ int bUpdate = 0; /* True for an update that modifies "name" */
+ int bIsDir = 0;
+ u32 iCrc32 = 0;
+
+ if( pTab->pWriteFd==0 ){
+ rc = zipfileBegin(pVtab);
+ if( rc!=SQLITE_OK ) return rc;
+ }
+
+ /* If this is a DELETE or UPDATE, find the archive entry to delete. */
+ if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
+ const char *zDelete = (const char*)sqlite3_value_text(apVal[0]);
+ int nDelete = (int)strlen(zDelete);
+ if( nVal>1 ){
+ const char *zUpdate = (const char*)sqlite3_value_text(apVal[1]);
+ if( zUpdate && zipfileComparePath(zUpdate, zDelete, nDelete)!=0 ){
+ bUpdate = 1;
+ }
+ }
+ for(pOld=pTab->pFirstEntry; 1; pOld=pOld->pNext){
+ if( zipfileComparePath(pOld->cds.zFile, zDelete, nDelete)==0 ){
+ break;
+ }
+ assert( pOld->pNext );
+ }
+ }
+
+ if( nVal>1 ){
+ /* Check that "sz" and "rawdata" are both NULL: */
+ if( sqlite3_value_type(apVal[5])!=SQLITE_NULL ){
+ zipfileTableErr(pTab, "sz must be NULL");
+ rc = SQLITE_CONSTRAINT;
+ }
+ if( sqlite3_value_type(apVal[6])!=SQLITE_NULL ){
+ zipfileTableErr(pTab, "rawdata must be NULL");
+ rc = SQLITE_CONSTRAINT;
+ }
+
+ if( rc==SQLITE_OK ){
+ if( sqlite3_value_type(apVal[7])==SQLITE_NULL ){
+ /* data=NULL. A directory */
+ bIsDir = 1;
+ }else{
+ /* Value specified for "data", and possibly "method". This must be
+ ** a regular file or a symlink. */
+ const u8 *aIn = sqlite3_value_blob(apVal[7]);
+ size_t nIn = sqlite3_value_bytes(apVal[7]);
+ int bAuto = sqlite3_value_type(apVal[8])==SQLITE_NULL;
+
+ iMethod = sqlite3_value_int(apVal[8]);
+ sz = nIn;
+ pData = aIn;
+ nData = nIn;
+ if( iMethod!=0 && iMethod!=8 ){
+ zipfileTableErr(pTab, "unknown compression method: %d", iMethod);
+ rc = SQLITE_CONSTRAINT;
+ }else{
+ if( bAuto || iMethod ){
+ size_t nCmp;
+ rc = zipfileDeflate(aIn, nIn, &pFree, &nCmp, &pTab->base.zErrMsg);
+ if( rc==SQLITE_OK ){
+ if( iMethod || nCmp<nIn ){
+ iMethod = 8;
+ pData = pFree;
+ nData = nCmp;
+ }
+ }
+ }
+ iCrc32 = crc32(0, aIn, nIn);
+ }
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ rc = zipfileGetMode(apVal[3], bIsDir, &mode, &pTab->base.zErrMsg);
+ }
+
+ if( rc==SQLITE_OK ){
+ zPath = (const char*)sqlite3_value_text(apVal[2]);
+ nPath = (int)strlen(zPath);
+ mTime = zipfileGetTime(apVal[4]);
+ }
+
+ if( rc==SQLITE_OK && bIsDir ){
+ /* For a directory, check that the last character in the path is a
+ ** '/'. This appears to be required for compatibility with info-zip
+ ** (the unzip command on unix). It does not create directories
+ ** otherwise. */
+ if( zPath[nPath-1]!='/' ){
+ zFree = sqlite3_mprintf("%s/", zPath);
+ if( zFree==0 ){ rc = SQLITE_NOMEM; }
+ zPath = (const char*)zFree;
+ nPath++;
+ }
+ }
+
+ /* Check that we're not inserting a duplicate entry -OR- updating an
+ ** entry with a path, thereby making it into a duplicate. */
+ if( (pOld==0 || bUpdate) && rc==SQLITE_OK ){
+ ZipfileEntry *p;
+ for(p=pTab->pFirstEntry; p; p=p->pNext){
+ if( zipfileComparePath(p->cds.zFile, zPath, nPath)==0 ){
+ switch( sqlite3_vtab_on_conflict(pTab->db) ){
+ case SQLITE_IGNORE: {
+ goto zipfile_update_done;
+ }
+ case SQLITE_REPLACE: {
+ pOld2 = p;
+ break;
+ }
+ default: {
+ zipfileTableErr(pTab, "duplicate name: \"%s\"", zPath);
+ rc = SQLITE_CONSTRAINT;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ /* Create the new CDS record. */
+ pNew = zipfileNewEntry(zPath);
+ if( pNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ pNew->cds.iVersionMadeBy = ZIPFILE_NEWENTRY_MADEBY;
+ pNew->cds.iVersionExtract = ZIPFILE_NEWENTRY_REQUIRED;
+ pNew->cds.flags = ZIPFILE_NEWENTRY_FLAGS;
+ pNew->cds.iCompression = (u16)iMethod;
+ zipfileMtimeToDos(&pNew->cds, mTime);
+ pNew->cds.crc32 = iCrc32;
+ pNew->cds.szCompressed = nData;
+ pNew->cds.szUncompressed = (u32)sz;
+ pNew->cds.iExternalAttr = (mode<<16);
+ pNew->cds.iOffset = (u32)pTab->szCurrent;
+ pNew->cds.nFile = (u16)nPath;
+ pNew->mUnixTime = (u32)mTime;
+ rc = zipfileAppendEntry(pTab, pNew, pData, nData);
+ zipfileAddEntry(pTab, pOld, pNew);
+ }
+ }
+ }
+
+ if( rc==SQLITE_OK && (pOld || pOld2) ){
+ ZipfileCsr *pCsr;
+ for(pCsr=pTab->pCsrList; pCsr; pCsr=pCsr->pCsrNext){
+ if( pCsr->pCurrent && (pCsr->pCurrent==pOld || pCsr->pCurrent==pOld2) ){
+ pCsr->pCurrent = pCsr->pCurrent->pNext;
+ pCsr->bNoop = 1;
+ }
+ }
+
+ zipfileRemoveEntryFromList(pTab, pOld);
+ zipfileRemoveEntryFromList(pTab, pOld2);
+ }
+
+zipfile_update_done:
+ sqlite3_free(pFree);
+ sqlite3_free(zFree);
+ return rc;
+}
+
+static int zipfileSerializeEOCD(ZipfileEOCD *p, u8 *aBuf){
+ u8 *a = aBuf;
+ zipfileWrite32(a, ZIPFILE_SIGNATURE_EOCD);
+ zipfileWrite16(a, p->iDisk);
+ zipfileWrite16(a, p->iFirstDisk);
+ zipfileWrite16(a, p->nEntry);
+ zipfileWrite16(a, p->nEntryTotal);
+ zipfileWrite32(a, p->nSize);
+ zipfileWrite32(a, p->iOffset);
+ zipfileWrite16(a, 0); /* Size of trailing comment in bytes*/
+
+ return a-aBuf;
+}
+
+static int zipfileAppendEOCD(ZipfileTab *pTab, ZipfileEOCD *p){
+ int nBuf = zipfileSerializeEOCD(p, pTab->aBuffer);
+ assert( nBuf==ZIPFILE_EOCD_FIXED_SZ );
+ return zipfileAppendData(pTab, pTab->aBuffer, nBuf);
+}
+
+/*
+** Serialize the CDS structure into buffer aBuf[]. Return the number
+** of bytes written.
+*/
+static int zipfileSerializeCDS(ZipfileEntry *pEntry, u8 *aBuf){
+ u8 *a = aBuf;
+ ZipfileCDS *pCDS = &pEntry->cds;
+
+ if( pEntry->aExtra==0 ){
+ pCDS->nExtra = 9;
+ }
+
+ zipfileWrite32(a, ZIPFILE_SIGNATURE_CDS);
+ zipfileWrite16(a, pCDS->iVersionMadeBy);
+ zipfileWrite16(a, pCDS->iVersionExtract);
+ zipfileWrite16(a, pCDS->flags);
+ zipfileWrite16(a, pCDS->iCompression);
+ zipfileWrite16(a, pCDS->mTime);
+ zipfileWrite16(a, pCDS->mDate);
+ zipfileWrite32(a, pCDS->crc32);
+ zipfileWrite32(a, pCDS->szCompressed);
+ zipfileWrite32(a, pCDS->szUncompressed);
+ assert( a==&aBuf[ZIPFILE_CDS_NFILE_OFF] );
+ zipfileWrite16(a, pCDS->nFile);
+ zipfileWrite16(a, pCDS->nExtra);
+ zipfileWrite16(a, pCDS->nComment);
+ zipfileWrite16(a, pCDS->iDiskStart);
+ zipfileWrite16(a, pCDS->iInternalAttr);
+ zipfileWrite32(a, pCDS->iExternalAttr);
+ zipfileWrite32(a, pCDS->iOffset);
+
+ memcpy(a, pCDS->zFile, pCDS->nFile);
+ a += pCDS->nFile;
+
+ if( pEntry->aExtra ){
+ int n = (int)pCDS->nExtra + (int)pCDS->nComment;
+ memcpy(a, pEntry->aExtra, n);
+ a += n;
+ }else{
+ assert( pCDS->nExtra==9 );
+ zipfileWrite16(a, ZIPFILE_EXTRA_TIMESTAMP);
+ zipfileWrite16(a, 5);
+ *a++ = 0x01;
+ zipfileWrite32(a, pEntry->mUnixTime);
+ }
+
+ return a-aBuf;
+}
+
+static int zipfileCommit(sqlite3_vtab *pVtab){
+ ZipfileTab *pTab = (ZipfileTab*)pVtab;
+ int rc = SQLITE_OK;
+ if( pTab->pWriteFd ){
+ i64 iOffset = pTab->szCurrent;
+ ZipfileEntry *p;
+ ZipfileEOCD eocd;
+ int nEntry = 0;
+
+ /* Write out all entries */
+ for(p=pTab->pFirstEntry; rc==SQLITE_OK && p; p=p->pNext){
+ int n = zipfileSerializeCDS(p, pTab->aBuffer);
+ rc = zipfileAppendData(pTab, pTab->aBuffer, n);
+ nEntry++;
+ }
+
+ /* Write out the EOCD record */
+ eocd.iDisk = 0;
+ eocd.iFirstDisk = 0;
+ eocd.nEntry = (u16)nEntry;
+ eocd.nEntryTotal = (u16)nEntry;
+ eocd.nSize = (u32)(pTab->szCurrent - iOffset);
+ eocd.iOffset = (u32)iOffset;
+ rc = zipfileAppendEOCD(pTab, &eocd);
+
+ zipfileCleanupTransaction(pTab);
+ }
+ return rc;
+}
+
+static int zipfileRollback(sqlite3_vtab *pVtab){
+ return zipfileCommit(pVtab);
+}
+
+static ZipfileCsr *zipfileFindCursor(ZipfileTab *pTab, i64 iId){
+ ZipfileCsr *pCsr;
+ for(pCsr=pTab->pCsrList; pCsr; pCsr=pCsr->pCsrNext){
+ if( iId==pCsr->iId ) break;
+ }
+ return pCsr;
+}
+
+static void zipfileFunctionCds(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ ZipfileCsr *pCsr;
+ ZipfileTab *pTab = (ZipfileTab*)sqlite3_user_data(context);
+ assert( argc>0 );
+
+ pCsr = zipfileFindCursor(pTab, sqlite3_value_int64(argv[0]));
+ if( pCsr ){
+ ZipfileCDS *p = &pCsr->pCurrent->cds;
+ char *zRes = sqlite3_mprintf("{"
+ "\"version-made-by\" : %u, "
+ "\"version-to-extract\" : %u, "
+ "\"flags\" : %u, "
+ "\"compression\" : %u, "
+ "\"time\" : %u, "
+ "\"date\" : %u, "
+ "\"crc32\" : %u, "
+ "\"compressed-size\" : %u, "
+ "\"uncompressed-size\" : %u, "
+ "\"file-name-length\" : %u, "
+ "\"extra-field-length\" : %u, "
+ "\"file-comment-length\" : %u, "
+ "\"disk-number-start\" : %u, "
+ "\"internal-attr\" : %u, "
+ "\"external-attr\" : %u, "
+ "\"offset\" : %u }",
+ (u32)p->iVersionMadeBy, (u32)p->iVersionExtract,
+ (u32)p->flags, (u32)p->iCompression,
+ (u32)p->mTime, (u32)p->mDate,
+ (u32)p->crc32, (u32)p->szCompressed,
+ (u32)p->szUncompressed, (u32)p->nFile,
+ (u32)p->nExtra, (u32)p->nComment,
+ (u32)p->iDiskStart, (u32)p->iInternalAttr,
+ (u32)p->iExternalAttr, (u32)p->iOffset
+ );
+
+ if( zRes==0 ){
+ sqlite3_result_error_nomem(context);
+ }else{
+ sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT);
+ sqlite3_free(zRes);
+ }
+ }
+}
+
+/*
+** xFindFunction method.
+*/
+static int zipfileFindFunction(
+ sqlite3_vtab *pVtab, /* Virtual table handle */
+ int nArg, /* Number of SQL function arguments */
+ const char *zName, /* Name of SQL function */
+ void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */
+ void **ppArg /* OUT: User data for *pxFunc */
+){
+ if( sqlite3_stricmp("zipfile_cds", zName)==0 ){
+ *pxFunc = zipfileFunctionCds;
+ *ppArg = (void*)pVtab;
+ return 1;
+ }
+ return 0;
+}
+
+typedef struct ZipfileBuffer ZipfileBuffer;
+struct ZipfileBuffer {
+ u8 *a; /* Pointer to buffer */
+ size_t n; /* Size of buffer in bytes */
+ size_t nAlloc; /* Byte allocated at a[] */
+};
+
+typedef struct ZipfileCtx ZipfileCtx;
+struct ZipfileCtx {
+ int nEntry;
+ ZipfileBuffer body;
+ ZipfileBuffer cds;
+};
+
+static int zipfileBufferGrow(ZipfileBuffer *pBuf, size_t nByte){
+ if( pBuf->n+nByte>pBuf->nAlloc ){
+ u8 *aNew;
+ size_t nNew = pBuf->n ? pBuf->n*2 : 512;
+ size_t nReq = pBuf->n + nByte;
+
+ while( nNew<nReq ) nNew = nNew*2;
+ aNew = sqlite3_realloc(pBuf->a, nNew);
+ if( aNew==0 ) return SQLITE_NOMEM;
+ pBuf->a = aNew;
+ pBuf->nAlloc = (int)nNew;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** xStep() callback for the zipfile() aggregate. This can be called in
+** any of the following ways:
+**
+** SELECT zipfile(name,data) ...
+** SELECT zipfile(name,mode,mtime,data) ...
+** SELECT zipfile(name,mode,mtime,data,method) ...
+*/
+void zipfileStep(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal){
+ ZipfileCtx *p; /* Aggregate function context */
+ ZipfileEntry e; /* New entry to add to zip archive */
+
+ sqlite3_value *pName = 0;
+ sqlite3_value *pMode = 0;
+ sqlite3_value *pMtime = 0;
+ sqlite3_value *pData = 0;
+ sqlite3_value *pMethod = 0;
+
+ int bIsDir = 0;
+ u32 mode;
+ int rc = SQLITE_OK;
+ char *zErr = 0;
+
+ int iMethod = -1; /* Compression method to use (0 or 8) */
+
+ const u8 *aData = 0; /* Possibly compressed data for new entry */
+ size_t nData = 0; /* Size of aData[] in bytes */
+ int szUncompressed = 0; /* Size of data before compression */
+ u8 *aFree = 0; /* Free this before returning */
+ u32 iCrc32 = 0; /* crc32 of uncompressed data */
+
+ char *zName = 0; /* Path (name) of new entry */
+ int nName = 0; /* Size of zName in bytes */
+ char *zFree = 0; /* Free this before returning */
+ size_t nByte;
+
+ memset(&e, 0, sizeof(e));
+ p = (ZipfileCtx*)sqlite3_aggregate_context(pCtx, sizeof(ZipfileCtx));
+ if( p==0 ) return;
+
+ /* Martial the arguments into stack variables */
+ if( nVal!=2 && nVal!=4 && nVal!=5 ){
+ zErr = sqlite3_mprintf("wrong number of arguments to function zipfile()");
+ rc = SQLITE_ERROR;
+ goto zipfile_step_out;
+ }
+ pName = apVal[0];
+ if( nVal==2 ){
+ pData = apVal[1];
+ }else{
+ pMode = apVal[1];
+ pMtime = apVal[2];
+ pData = apVal[3];
+ if( nVal==5 ){
+ pMethod = apVal[4];
+ }
+ }
+
+ /* Check that the 'name' parameter looks ok. */
+ zName = (char*)sqlite3_value_text(pName);
+ nName = sqlite3_value_bytes(pName);
+ if( zName==0 ){
+ zErr = sqlite3_mprintf("first argument to zipfile() must be non-NULL");
+ rc = SQLITE_ERROR;
+ goto zipfile_step_out;
+ }
+
+ /* Inspect the 'method' parameter. This must be either 0 (store), 8 (use
+ ** deflate compression) or NULL (choose automatically). */
+ if( pMethod && SQLITE_NULL!=sqlite3_value_type(pMethod) ){
+ iMethod = (int)sqlite3_value_int64(pMethod);
+ if( iMethod!=0 && iMethod!=8 ){
+ zErr = sqlite3_mprintf("illegal method value: %d", iMethod);
+ rc = SQLITE_ERROR;
+ goto zipfile_step_out;
+ }
+ }
+
+ /* Now inspect the data. If this is NULL, then the new entry must be a
+ ** directory. Otherwise, figure out whether or not the data should
+ ** be deflated or simply stored in the zip archive. */
+ if( sqlite3_value_type(pData)==SQLITE_NULL ){
+ bIsDir = 1;
+ iMethod = 0;
+ }else{
+ aData = sqlite3_value_blob(pData);
+ szUncompressed = nData = sqlite3_value_bytes(pData);
+ iCrc32 = crc32(0, aData, nData);
+ if( iMethod<0 || iMethod==8 ){
+ size_t nOut = 0;
+ rc = zipfileDeflate(aData, nData, &aFree, &nOut, &zErr);
+ if( rc!=SQLITE_OK ){
+ goto zipfile_step_out;
+ }
+ if( iMethod==8 || nOut<nData ){
+ aData = aFree;
+ nData = nOut;
+ iMethod = 8;
+ }else{
+ iMethod = 0;
+ }
+ }
+ }
+
+ /* Decode the "mode" argument. */
+ rc = zipfileGetMode(pMode, bIsDir, &mode, &zErr);
+ if( rc ) goto zipfile_step_out;
+
+ /* Decode the "mtime" argument. */
+ e.mUnixTime = zipfileGetTime(pMtime);
+
+ /* If this is a directory entry, ensure that there is exactly one '/'
+ ** at the end of the path. Or, if this is not a directory and the path
+ ** ends in '/' it is an error. */
+ if( bIsDir==0 ){
+ if( zName[nName-1]=='/' ){
+ zErr = sqlite3_mprintf("non-directory name must not end with /");
+ rc = SQLITE_ERROR;
+ goto zipfile_step_out;
+ }
+ }else{
+ if( zName[nName-1]!='/' ){
+ zName = zFree = sqlite3_mprintf("%s/", zName);
+ nName++;
+ if( zName==0 ){
+ rc = SQLITE_NOMEM;
+ goto zipfile_step_out;
+ }
+ }else{
+ while( nName>1 && zName[nName-2]=='/' ) nName--;
+ }
+ }
+
+ /* Assemble the ZipfileEntry object for the new zip archive entry */
+ e.cds.iVersionMadeBy = ZIPFILE_NEWENTRY_MADEBY;
+ e.cds.iVersionExtract = ZIPFILE_NEWENTRY_REQUIRED;
+ e.cds.flags = ZIPFILE_NEWENTRY_FLAGS;
+ e.cds.iCompression = (u16)iMethod;
+ zipfileMtimeToDos(&e.cds, (u32)e.mUnixTime);
+ e.cds.crc32 = iCrc32;
+ e.cds.szCompressed = nData;
+ e.cds.szUncompressed = szUncompressed;
+ e.cds.iExternalAttr = (mode<<16);
+ e.cds.iOffset = p->body.n;
+ e.cds.nFile = (u16)nName;
+ e.cds.zFile = zName;
+
+ /* Append the LFH to the body of the new archive */
+ nByte = ZIPFILE_LFH_FIXED_SZ + e.cds.nFile + 9;
+ if( (rc = zipfileBufferGrow(&p->body, nByte)) ) goto zipfile_step_out;
+ p->body.n += zipfileSerializeLFH(&e, &p->body.a[p->body.n]);
+
+ /* Append the data to the body of the new archive */
+ if( nData>0 ){
+ if( (rc = zipfileBufferGrow(&p->body, nData)) ) goto zipfile_step_out;
+ memcpy(&p->body.a[p->body.n], aData, nData);
+ p->body.n += nData;
+ }
+
+ /* Append the CDS record to the directory of the new archive */
+ nByte = ZIPFILE_CDS_FIXED_SZ + e.cds.nFile + 9;
+ if( (rc = zipfileBufferGrow(&p->cds, nByte)) ) goto zipfile_step_out;
+ p->cds.n += zipfileSerializeCDS(&e, &p->cds.a[p->cds.n]);
+
+ /* Increment the count of entries in the archive */
+ p->nEntry++;
+
+ zipfile_step_out:
+ sqlite3_free(aFree);
+ sqlite3_free(zFree);
+ if( rc ){
+ if( zErr ){
+ sqlite3_result_error(pCtx, zErr, -1);
+ }else{
+ sqlite3_result_error_code(pCtx, rc);
+ }
+ }
+ sqlite3_free(zErr);
+}
+
+/*
+** xFinalize() callback for zipfile aggregate function.
+*/
+void zipfileFinal(sqlite3_context *pCtx){
+ ZipfileCtx *p;
+ ZipfileEOCD eocd;
+ size_t nZip;
+ u8 *aZip;
+
+ p = (ZipfileCtx*)sqlite3_aggregate_context(pCtx, sizeof(ZipfileCtx));
+ if( p==0 ) return;
+ if( p->nEntry>0 ){
+ memset(&eocd, 0, sizeof(eocd));
+ eocd.nEntry = (u16)p->nEntry;
+ eocd.nEntryTotal = (u16)p->nEntry;
+ eocd.nSize = p->cds.n;
+ eocd.iOffset = p->body.n;
+
+ nZip = p->body.n + p->cds.n + ZIPFILE_EOCD_FIXED_SZ;
+ aZip = (u8*)sqlite3_malloc(nZip);
+ if( aZip==0 ){
+ sqlite3_result_error_nomem(pCtx);
+ }else{
+ memcpy(aZip, p->body.a, p->body.n);
+ memcpy(&aZip[p->body.n], p->cds.a, p->cds.n);
+ zipfileSerializeEOCD(&eocd, &aZip[p->body.n + p->cds.n]);
+ sqlite3_result_blob(pCtx, aZip, nZip, zipfileFree);
+ }
+ }
+
+ sqlite3_free(p->body.a);
+ sqlite3_free(p->cds.a);
+}
+
+
+/*
+** Register the "zipfile" virtual table.
+*/
+static int zipfileRegister(sqlite3 *db){
+ static const sqlite3_module zipfileModule = {
+ 1, /* iVersion */
+ zipfileConnect, /* xCreate */
+ zipfileConnect, /* xConnect */
+ zipfileBestIndex, /* xBestIndex */
+ zipfileDisconnect, /* xDisconnect */
+ zipfileDisconnect, /* xDestroy */
+ zipfileOpen, /* xOpen - open a cursor */
+ zipfileClose, /* xClose - close a cursor */
+ zipfileFilter, /* xFilter - configure scan constraints */
+ zipfileNext, /* xNext - advance a cursor */
+ zipfileEof, /* xEof - check for end of scan */
+ zipfileColumn, /* xColumn - read data */
+ 0, /* xRowid - read data */
+ zipfileUpdate, /* xUpdate */
+ zipfileBegin, /* xBegin */
+ 0, /* xSync */
+ zipfileCommit, /* xCommit */
+ zipfileRollback, /* xRollback */
+ zipfileFindFunction, /* xFindMethod */
+ 0, /* xRename */
+ };
+
+ int rc = sqlite3_create_module(db, "zipfile" , &zipfileModule, 0);
+ if( rc==SQLITE_OK ) rc = sqlite3_overload_function(db, "zipfile_cds", -1);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "zipfile", -1, SQLITE_UTF8, 0, 0,
+ zipfileStep, zipfileFinal
+ );
+ }
+ return rc;
+}
+#else /* SQLITE_OMIT_VIRTUALTABLE */
+# define zipfileRegister(x) SQLITE_OK
+#endif
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_zipfile_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ return zipfileRegister(db);
+}
--- origsrc/sqlite-autoconf-3300000/zorder.c 1970-01-01 01:00:00.000000000 +0100
+++ src/sqlite-autoconf-3300000/zorder.c 2019-10-08 13:42:19.270650500 +0200
@@ -0,0 +1,111 @@
+/*
+** 2018-02-09
+**
+** 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.
+**
+******************************************************************************
+**
+** SQL functions for z-order (Morton code) transformations.
+**
+** zorder(X0,X0,..,xN) Generate an N+1 dimension Morton code
+**
+** unzorder(Z,N,I) Extract the I-th dimension from N-dimensional
+** Morton code Z.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+
+/*
+** Functions: zorder(X0,X1,....)
+**
+** Convert integers X0, X1, ... into morton code.
+**
+** The output is a signed 64-bit integer. If any argument is too large,
+** an error is thrown.
+*/
+static void zorderFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3_int64 z, x[63];
+ int i, j;
+ z = 0;
+ for(i=0; i<argc; i++){
+ x[i] = sqlite3_value_int64(argv[i]);
+ }
+ if( argc>0 ){
+ for(i=0; i<63; i++){
+ j = i%argc;
+ z |= (x[j]&1)<<i;
+ x[j] >>= 1;
+ }
+ }
+ sqlite3_result_int64(context, z);
+ for(i=0; i<argc; i++){
+ if( x[i] ){
+ sqlite3_result_error(context, "parameter too large", -1);
+ }
+ }
+}
+
+
+/*
+** Functions: unzorder(Z,N,I)
+**
+** Assuming that Z is an N-dimensional Morton code, extract the I-th
+** dimension.
+*/
+static void unzorderFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3_int64 z, n, i, x;
+ int j, k;
+ z = sqlite3_value_int64(argv[0]);
+ n = sqlite3_value_int64(argv[1]);
+ i = sqlite3_value_int64(argv[2]);
+ x = 0;
+ for(k=0, j=i; j<63; j+=n, k++){
+ x |= ((z>>j)&1)<<k;
+ }
+ sqlite3_result_int64(context, x);
+}
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_zorder_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "zorder", -1, SQLITE_UTF8, 0,
+ zorderFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "unzorder", 3, SQLITE_UTF8, 0,
+ unzorderFunc, 0, 0);
+ }
+ return rc;
+}
+#if !defined(_WIN32) && !defined(SQLITE_TEST)
+int sqlite3_extension_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ return sqlite3_zorder_init(db, pzErrMsg, pApi);
+}
+#endif