From ce1f319698b28355b8f3b7410cd2addedd2ff38e Mon Sep 17 00:00:00 2001 From: Alexey Pavlov Date: Mon, 20 Jul 2020 12:42:41 +0300 Subject: [PATCH] sqlite : Update to 3.32.3 --- sqlite/PKGBUILD | 20 +- sqlite/sqlite3-3.30.0-1.src.patch | 56410 -------------- sqlite/sqlite3-3.32.3-1.src.patch | 108903 +++++++++++++++++++++++++++ 3 files changed, 108914 insertions(+), 56419 deletions(-) delete mode 100644 sqlite/sqlite3-3.30.0-1.src.patch create mode 100644 sqlite/sqlite3-3.32.3-1.src.patch diff --git a/sqlite/PKGBUILD b/sqlite/PKGBUILD index 6cb13b59..2b9210e1 100644 --- a/sqlite/PKGBUILD +++ b/sqlite/PKGBUILD @@ -5,9 +5,9 @@ pkgbase="sqlite" pkgname=('sqlite' 'libsqlite' 'libsqlite-devel' 'sqlite-doc' 'tcl-sqlite' 'sqlite-compress' 'sqlite-vfslog' 'sqlite-rbu' 'sqlite-icu' 'sqlite-extensions') -_amalgamationver=3300000 +_amalgamationver=3320300 _docver=${_amalgamationver} -pkgver=3.30.0 +pkgver=3.32.3 pkgrel=1 pkgdesc="A C library that implements an SQL database engine" arch=('i686' 'x86_64') @@ -15,16 +15,16 @@ license=(PublicDomain) url="https://www.sqlite.org/" makedepends=('libreadline-devel' 'icu-devel' 'zlib-devel' 'tcl') source=( # tarball containing the amalgamation for SQLite >= 3.7.5 together with a configure script and makefile for building it; includes now also the Tcl Extension Architecture (TEA) - https://www.sqlite.org/2019/sqlite-autoconf-${_amalgamationver}.tar.gz - https://www.sqlite.org/2019/sqlite-doc-${_docver}.zip + https://www.sqlite.org/2020/sqlite-autoconf-${_amalgamationver}.tar.gz + https://www.sqlite.org/2020/sqlite-doc-${_docver}.zip LICENSE - 'sqlite3-3.30.0-1.src.patch' + 'sqlite3-3.32.3-1.src.patch' 'sqlite-3.28.0-msys2.patch') options=('!libtool' '!emptydirs' '!debug' 'strip') -sha256sums=('e0a8cf4c7a87455e55e10413d16f358ca121ccec687fe1301eac95e2d340fc58' - 'cb4deed80e94c7c0d7ee4a5c76d9d91e4deec48e8b158b473b27253fbfc891d6' +sha256sums=('a31507123c1c2e3a210afec19525fd7b5bb1e19a6a34ae5b998fbd7302568b66' + '36920536daf7f8b19c2e646dc79db62e13cc1a992f562ba9a11fa7c191f24a4e' '0b76663a90e034f3d7f2af5bfada4cedec5ebc275361899eccc5c18e6f01ff1f' - '95179493fda34cf56d60adbee51f97dfd30f50cadb038e537adbfc30b11a91cf' + '3cccdd11f96e1e8cc3c5439dc007840e894cd4428df5f503d93d91e40bad9d65' 'fd301fe04600d5a91045dfc4dd7d3e95f0c18b6df82239fcd3bac1a176141b2a') # Helper macros to help make tasks easier # @@ -109,7 +109,7 @@ prepare() { vfslog.c vfsstat.c vtshim.c vtablog.c wholenumber.c \ zipfile.c zorder.c - apply_patch_with_msg_p2 sqlite3-3.30.0-1.src.patch + apply_patch_with_msg_p2 sqlite3-3.32.3-1.src.patch apply_patch_with_msg sqlite-3.28.0-msys2.patch autoreconf -fi @@ -120,7 +120,9 @@ build() { -DHAVE_MALLOC_H \ -DHAVE_MALLOC_USABLE_SIZE \ -DSQLITE_ENABLE_DBSTAT_VTAB=1 \ + -DSQLITE_ENABLE_DBPAGE_VTAB=1 \ -DSQLITE_ENABLE_STAT4=1 \ + -DSQLITE_ENABLE_FTS5=1 \ -DSQLITE_ENABLE_UNLOCK_NOTIFY=1 \ -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 \ -DSQLITE_OMIT_LOOKASIDE \ diff --git a/sqlite/sqlite3-3.30.0-1.src.patch b/sqlite/sqlite3-3.30.0-1.src.patch deleted file mode 100644 index 4eeada42..00000000 --- a/sqlite/sqlite3-3.30.0-1.src.patch +++ /dev/null @@ -1,56410 +0,0 @@ ---- 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 ( - ) -+# 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=, -- V -+** vocabulary_word=, -- W -+** vocabulary_language=, -- L -+** edit_distances= -+** ); -+** -+** 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 " 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 -+#include -+#include -+#include -+#include -+ -+#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; ipNext; -+ pX->pNext = 0; -+ for(i=0; a[i] && ipRule = 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; iInpVCheck ){ -+ 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 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; izVocabTab); -+ 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; inConstraint; 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 -+ -+static int anyCollFunc( -+ void *NotUsed, -+ int nKey1, const void *pKey1, -+ int nKey2, const void *pKey2 -+){ -+ int rc, n; -+ n = nKey1 -+#include -+ -+/* 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 -+#include -+ -+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 -+#include -+ -+/* 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; inConstraint; 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 -+#include -+ -+#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]) ){ -+ 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; inConstraint; 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=, -- T -+** idcolumn=, -- X -+** parentcolumn= -- 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 -+#include -+#include -+#include -+#include -+ -+#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 = (idid) ? 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->idid ){ -+ 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; iInzDb); -+ 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 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; izTableName); -+ 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; inConstraint; 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; inConstraint; 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 -+#include -+#include -+ -+#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; inConstraint; 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 -+ -+/* -+** 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 -+SQLITE_EXTENSION_INIT1 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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; izErr. 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=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; iCol0 && iColnCol = 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; ibase); -+ for(i=0; ibase.pVtab; -+ int i; -+ for(i=0; inCol; 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( inCol ){ -+ 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 && inCol) ){ -+ pCur->iRowid = -1; -+ }else{ -+ pCur->iRowid++; -+ while( inCol ){ -+ 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 && inCol && 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; inConstraint; 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 -+#include -+ -+#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; inConstraint; 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 && iOffnPage ){ -+ 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 -+#include -+#include -+ -+/* -+** 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; in+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; in = (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; ixCallback(",", 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>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; ixCallback(",", 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 -+ -+/* -+** 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 -+ -+/* -+** 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; inUsed+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 -+#include -+ -+#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; inConstraint; 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 -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#if !defined(_WIN32) && !defined(WIN32) -+# include -+# include -+# include -+#else -+# include "windows.h" -+# include -+# include -+# 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 -+#include -+ -+ -+/* -+** 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=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(¤tTime); -+ SystemTimeToFileTime(¤tTime, &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( nzPath); -+ } -+ } -+ 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; inConstraint; 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 -+#include -+#include -+#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; iz, 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; i0; 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=4003000 -+ while( z=1300 -+ while( z= 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=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=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( base0 ){ -+ 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; inConstraint; 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(); -+** -+** 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 " 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 -+#include -+#include -+#include -+ -+#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; ipNext; -+ pX->pNext = 0; -+ for(i=0; a[i] && ipRule = 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; iInnCursor==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; iaQueue[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; -+ 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( imxQueue = 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)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; inConstraint; 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 -+#include -+#include -+#include -+ -+#include -+ -+#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(, ); -+** -+** Where is a string containing an ICU locale identifier (i.e. -+** "en_AU", "tr_TR" etc.) and 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 -+#include -+ -+/* -+** 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 -+#include -+#include -+#include -+ -+/* 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 /* 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 = NnAlloc ? 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; inUsed+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->nUsednAlloc ); -+} -+ -+/* -+** 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>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->nNodenAlloc ); -+ 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; iKeynJson==nJson -+ && memcmp(p->zJson,zJson,nJson)==0 -+ ){ -+ p->nErr = 0; -+ pMatch = p; -+ }else if( p->iHoldiHold; -+ 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; inNode ); -+ 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; inErr ) 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 && iTargetnNode ); -+ pTarget = &pParse->aNode[iTarget]; -+ assert( (pPatch->jnFlags & JNODE_APPEND)==0 ); -+ if( pTarget->eType!=JSON_OBJECT ){ -+ jsonRemoveAllNulls(pPatch); -+ return pPatch; -+ } -+ iRoot = iTarget; -+ for(i=1; in; 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; jn; 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; ijnFlags |= 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->iiEnd ){ -+ 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; inConstraint; 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 -+#include -+ -+#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; inDb; 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<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 -+#include -+#include -+ -+/* 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 -+SQLITE_EXTENSION_INIT1 -+#include -+#include -+ -+ -+/* -+** 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->szMaxsz ) 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 -+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( szMaxzName,"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 -+ -+/* -+** 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; inUsed; 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 -+#include -+ -+/* -+** 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; k0 && 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; i5 ){ -+ 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 -+#include -+ -+/* -+** 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 -+#include -+#include -+ -+/* 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( aa==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 -+#include -+ -+/* 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; inConstraint; 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 -+#include -+#include -+ -+/* -+** 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; i1 && nArg<=8 && 0==memcmp(zArg, "-vacuum", nArg) ){ -+ bVacuum = 1; -+ }else if( nArg>1 && nArg<=7 -+ && 0==memcmp(zArg, "-presql", nArg) && i1 && nArg<=5 && 0==memcmp(zArg, "-step", nArg) && i1 && nArg<=9 -+ && 0==memcmp(zArg, "-statstep", nArg) && i0 && (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 -+#include -+#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; inState; 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->imx && (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+1mx && (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+3mx && (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; inState; 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 && jaOp[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; inState; 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+4sIn.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+2sIn.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.isIn.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 && nsIn.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; j0 ){ -+ 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; jzInit)-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 -+#include -+ -+/* -+** 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 -+#include -+ -+/* -+** 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 -+#include -+#include -+#include -+#include -+ -+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( nszPage); -+ } -+ 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( y0 && 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( x0 ){ 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 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