diff --git a/deps/extract.js b/deps/extract.js new file mode 100644 index 00000000..40528a66 --- /dev/null +++ b/deps/extract.js @@ -0,0 +1,130 @@ +#!/usr/bin/env node +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const zlib = require('zlib'); + +const LOCAL_FILE_HEADER_SIG = 0x04034b50; +const COMPRESSION_STORE = 0; +const COMPRESSION_DEFLATE = 8; + +function extractZip(zipPath, destDir) { + const data = fs.readFileSync(zipPath); + let offset = 0; + let entries = 0; + + // Detect top-level directory prefix to strip (e.g., "sqlite-amalgamation-3530100/") + let prefixToStrip = ''; + let firstEntry = true; + + while (offset < data.length) { + const sig = data.readUInt32LE(offset); + if (sig !== LOCAL_FILE_HEADER_SIG) { + break; + } + + const compressionMethod = data.readUInt16LE(offset + 8); + const compressedSize = data.readUInt32LE(offset + 18); + const fileNameLength = data.readUInt16LE(offset + 26); + const extraFieldLength = data.readUInt16LE(offset + 28); + + const fileName = data.toString('utf8', offset + 30, offset + 30 + fileNameLength); + const dataOffset = offset + 30 + fileNameLength + extraFieldLength; + const compressedData = data.subarray(dataOffset, dataOffset + compressedSize); + + // Detect top-level directory prefix from first entry + if (firstEntry && fileName.includes('/')) { + prefixToStrip = fileName.substring(0, fileName.indexOf('/') + 1); + firstEntry = false; + } + + // Strip prefix from filename + let outFileName = fileName; + if (prefixToStrip && outFileName.startsWith(prefixToStrip)) { + outFileName = outFileName.substring(prefixToStrip.length); + } + + let fileData; + if (compressionMethod === COMPRESSION_STORE) { + fileData = compressedData; + } else if (compressionMethod === COMPRESSION_DEFLATE) { + fileData = zlib.inflateRawSync(compressedData); + } else { + throw new Error(`Unsupported compression method ${compressionMethod} for file ${fileName}`); + } + + if (outFileName && !outFileName.endsWith('/')) { + const outPath = path.join(destDir, outFileName); + const resolvedDest = path.resolve(destDir); + const resolvedOut = path.resolve(outPath); + if (!resolvedOut.startsWith(resolvedDest + path.sep)) { + throw new Error(`Zip Slip detected: ${outFileName} resolves outside destination directory`); + } + const dir = path.dirname(outPath); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + fs.writeFileSync(outPath, fileData); + entries++; + } + + offset = dataOffset + compressedSize; + } + + if (entries === 0) { + throw new Error('No files extracted — zip may be corrupted or empty'); + } + + return entries; +} + +function main() { + const archivePath = path.resolve(process.argv[2]); + const destDir = path.resolve(process.argv[3]); + + if (!archivePath || !destDir) { + console.error('Usage: extract.js '); + process.exit(1); + } + + // Resolve archive path relative to script directory if not absolute + const zipFile = path.isAbsolute(archivePath) + ? archivePath + : path.join(__dirname, archivePath); + + // Compute extraction directory: destDir + archive basename without .zip + const archiveName = path.basename(archivePath, '.zip'); + const extractDir = path.join(destDir, archiveName); + const stampFile = path.join(extractDir, '.extract-stamp'); + + if (fs.existsSync(stampFile)) { + console.log(`[extract] Already extracted: ${extractDir}`); + process.exit(0); + } + + if (!fs.existsSync(zipFile)) { + console.error(`[extract] ERROR: Zip file not found: ${zipFile}`); + process.exit(1); + } + + if (fs.existsSync(extractDir)) { + console.log(`[extract] Removing stale extraction directory: ${extractDir}`); + fs.rmSync(extractDir, { recursive: true, force: true }); + } + + console.log(`[extract] Extracting ${path.basename(zipFile)}...`); + fs.mkdirSync(extractDir, { recursive: true }); + + try { + const entries = extractZip(zipFile, extractDir); + fs.writeFileSync(stampFile, `Extracted from ${path.basename(zipFile)}\n`); + console.log(`[extract] Extraction complete: ${entries} file(s) extracted to ${extractDir}`); + } catch (err) { + console.error(`[extract] ERROR: ${err.message}`); + fs.rmSync(extractDir, { recursive: true, force: true }); + process.exit(1); + } +} + +main(); diff --git a/deps/sqlite-amalgamation-3530100.zip b/deps/sqlite-amalgamation-3530100.zip new file mode 100644 index 00000000..1da68a20 Binary files /dev/null and b/deps/sqlite-amalgamation-3530100.zip differ diff --git a/deps/sqlite-amalgamation-3530100/shell.c b/deps/sqlite-amalgamation-3530100/shell.c deleted file mode 100644 index 57faceb4..00000000 --- a/deps/sqlite-amalgamation-3530100/shell.c +++ /dev/null @@ -1,37308 +0,0 @@ -/* -** This is the amalgamated source code to the "sqlite3" or "sqlite3.exe" -** command-line shell (CLI) for SQLite. This file is automatically -** generated by the tool/mkshellc.tcl script from the following sources: -** -** ext/expert/sqlite3expert.c -** ext/expert/sqlite3expert.h -** ext/intck/sqlite3intck.c -** ext/intck/sqlite3intck.h -** ext/misc/appendvfs.c -** ext/misc/base64.c -** ext/misc/base85.c -** ext/misc/completion.c -** ext/misc/decimal.c -** ext/misc/fileio.c -** ext/misc/ieee754.c -** ext/misc/memtrace.c -** ext/misc/pcachetrace.c -** ext/misc/regexp.c -** ext/misc/series.c -** ext/misc/sha1.c -** ext/misc/shathree.c -** ext/misc/sqlar.c -** ext/misc/sqlite3_stdio.c -** ext/misc/sqlite3_stdio.h -** ext/misc/stmtrand.c -** ext/misc/uint.c -** ext/misc/vfstrace.c -** ext/misc/windirent.h -** ext/misc/zipfile.c -** ext/qrf/qrf.c -** ext/qrf/qrf.h -** ext/recover/dbdata.c -** ext/recover/sqlite3recover.c -** ext/recover/sqlite3recover.h -** src/shell.c.in -** -** To modify this program, get a copy of the canonical SQLite source tree, -** edit the src/shell.c.in file and/or some of the other files that are -** listed above, then rerun the command "make shell.c". -*/ -/************************* Begin src/shell.c.in ******************/ -/* -** 2001 September 15 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** This file contains code to implement the "sqlite3" command line -** utility for accessing SQLite databases. -*/ -#if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS) -/* This needs to come before any includes for MSVC compiler */ -#define _CRT_SECURE_NO_WARNINGS -#endif -typedef unsigned int u32; -typedef unsigned short int u16; - -/* -** Limit input nesting via .read or any other input redirect. -** It's not too expensive, so a generous allowance can be made. -*/ -#define MAX_INPUT_NESTING 25 - -/* -** Used to prevent warnings about unused parameters -*/ -#define UNUSED_PARAMETER(x) (void)(x) - -/* -** Number of elements in an array -*/ -#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0])) - -/* -** Optionally #include a user-defined header, whereby compilation options -** may be set prior to where they take effect, but after platform setup. -** If SQLITE_CUSTOM_INCLUDE=? is defined, its value names the #include -** file. Note that this macro has a like effect on sqlite3.c compilation. -*/ -# define SHELL_STRINGIFY_(f) #f -# define SHELL_STRINGIFY(f) SHELL_STRINGIFY_(f) -#ifdef SQLITE_CUSTOM_INCLUDE -# include SHELL_STRINGIFY(SQLITE_CUSTOM_INCLUDE) -#endif - -/* -** If SQLITE_SHELL_FIDDLE is defined then the shell is modified -** somewhat for use as a WASM module in a web browser. This flag -** should only be used when building the "fiddle" web application, as -** the browser-mode build has much different user input requirements -** and this build mode rewires the user input subsystem to account for -** that. -*/ -#if defined(SQLITE_SHELL_FIDDLE) -# undef SQLITE_OMIT_LOAD_EXTENSION -# define SQLITE_OMIT_LOAD_EXTENSION 1 -#endif - -/* -** Warning pragmas copied from msvc.h in the core. -*/ -#if defined(_MSC_VER) -#pragma warning(disable : 4054) -#pragma warning(disable : 4055) -#pragma warning(disable : 4100) -#pragma warning(disable : 4127) -#pragma warning(disable : 4130) -#pragma warning(disable : 4152) -#pragma warning(disable : 4189) -#pragma warning(disable : 4206) -#pragma warning(disable : 4210) -#pragma warning(disable : 4232) -#pragma warning(disable : 4244) -#pragma warning(disable : 4305) -#pragma warning(disable : 4306) -#pragma warning(disable : 4702) -#pragma warning(disable : 4706) -#endif /* defined(_MSC_VER) */ - -/* -** No support for loadable extensions in VxWorks. -*/ -#if (defined(__RTP__) || defined(_WRS_KERNEL)) && !SQLITE_OMIT_LOAD_EXTENSION -# define SQLITE_OMIT_LOAD_EXTENSION 1 -#endif - -/* -** Enable large-file support for fopen() and friends on unix. -*/ -#ifndef SQLITE_DISABLE_LFS -# define _LARGE_FILE 1 -# ifndef _FILE_OFFSET_BITS -# define _FILE_OFFSET_BITS 64 -# endif -# define _LARGEFILE_SOURCE 1 -#endif - -#if defined(SQLITE_SHELL_FIDDLE) && !defined(_POSIX_SOURCE) -/* -** emcc requires _POSIX_SOURCE (or one of several similar defines) -** to expose strdup(). -*/ -# define _POSIX_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include "sqlite3.h" -typedef sqlite3_int64 i64; -typedef sqlite3_uint64 u64; -typedef unsigned char u8; -#include -#include -#ifndef _WIN32 -# include -# include -#endif - -#if !defined(_WIN32) && !defined(WIN32) -# include -# if !defined(__RTP__) && !defined(_WRS_KERNEL) && !defined(SQLITE_WASI) -# include -# endif -#endif -#if (!defined(_WIN32) && !defined(WIN32)) || defined(__MINGW32__) -# include -# include -# define GETPID getpid -# if defined(__MINGW32__) -# define DIRENT dirent -# ifndef S_ISLNK -# define S_ISLNK(mode) (0) -# endif -# endif -#else -# define GETPID (int)GetCurrentProcessId -#endif -#include -#include - -#if HAVE_READLINE -# include -# include -#endif - -#if HAVE_EDITLINE -# include -#endif - -#if HAVE_EDITLINE || HAVE_READLINE - -# define shell_add_history(X) add_history(X) -# define shell_read_history(X) read_history(X) -# define shell_write_history(X) write_history(X) -# define shell_stifle_history(X) stifle_history(X) -# define shell_readline(X) readline(X) - -#elif HAVE_LINENOISE - -# include "linenoise.h" -# define shell_add_history(X) linenoiseHistoryAdd(X) -# define shell_read_history(X) linenoiseHistoryLoad(X) -# define shell_write_history(X) linenoiseHistorySave(X) -# define shell_stifle_history(X) linenoiseHistorySetMaxLen(X) -# define shell_readline(X) linenoise(X) - -#else - -# define shell_read_history(X) -# define shell_write_history(X) -# define shell_stifle_history(X) - -# define SHELL_USE_LOCAL_GETLINE 1 -#endif - -#ifndef deliberate_fall_through -/* Quiet some compilers about some of our intentional code. */ -# if defined(GCC_VERSION) && GCC_VERSION>=7000000 -# define deliberate_fall_through __attribute__((fallthrough)); -# else -# define deliberate_fall_through -# endif -#endif - -#if defined(_WIN32) || defined(WIN32) -# include -# include -# define isatty(h) _isatty(h) -# ifndef access -# define access(f,m) _access((f),(m)) -# endif -# ifndef unlink -# define unlink _unlink -# endif -# ifndef strdup -# define strdup _strdup -# endif -# undef pclose -# define pclose _pclose -#else - /* Make sure isatty() has a prototype. */ - extern int isatty(int); - -# if !defined(__RTP__) && !defined(_WRS_KERNEL) && !defined(SQLITE_WASI) - /* popen and pclose are not C89 functions and so are - ** sometimes omitted from the header */ - extern FILE *popen(const char*,const char*); - extern int pclose(FILE*); -# else -# define SQLITE_OMIT_POPEN 1 -# endif -#endif - -#if defined(_WIN32_WCE) -/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty() - * thus we always assume that we have a console. That can be - * overridden with the -batch command line option. - */ -#define isatty(x) 1 -#endif - -/* ctype macros that work with signed characters */ -#define IsSpace(X) isspace((unsigned char)X) -#define IsDigit(X) isdigit((unsigned char)X) -#define ToLower(X) (char)tolower((unsigned char)X) -#define IsAlnum(X) isalnum((unsigned char)X) -#define IsAlpha(X) isalpha((unsigned char)X) - -#if defined(_WIN32) || defined(WIN32) -#undef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#include - -/* string conversion routines only needed on Win32 */ -extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR); -extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText); -#endif - -/************************* Begin ext/misc/sqlite3_stdio.h ******************/ -/* -** 2024-09-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 header file contains definitions of interfaces that provide -** cross-platform I/O for UTF-8 content. -** -** On most platforms, the interfaces definitions in this file are -** just #defines. For example sqlite3_fopen() is a macro that resolves -** to the standard fopen() in the C-library. -** -** But Windows does not have a standard C-library, at least not one that -** can handle UTF-8. So for windows build, the interfaces resolve to new -** C-language routines contained in the separate sqlite3_stdio.c source file. -** -** So on all non-Windows platforms, simply #include this header file and -** use the interfaces defined herein. Then to run your application on Windows, -** also link in the accompanying sqlite3_stdio.c source file when compiling -** to get compatible interfaces. -*/ -#ifndef _SQLITE3_STDIO_H_ -#define _SQLITE3_STDIO_H_ 1 -#ifdef _WIN32 -/**** Definitions For Windows ****/ -#include -#include -#include - -FILE *sqlite3_fopen(const char *zFilename, const char *zMode); -FILE *sqlite3_popen(const char *zCommand, const char *type); -char *sqlite3_fgets(char *s, int size, FILE *stream); -int sqlite3_fputs(const char *s, FILE *stream); -int sqlite3_fprintf(FILE *stream, const char *format, ...); -int sqlite3_vfprintf(FILE *stream, const char *format, va_list); -void sqlite3_fsetmode(FILE *stream, int mode); - - -#else -/**** Definitions For All Other Platforms ****/ -#include -#define sqlite3_fopen fopen -#define sqlite3_popen popen -#define sqlite3_fgets fgets -#define sqlite3_fputs fputs -#define sqlite3_fprintf fprintf -#define sqlite3_vfprintf vfprintf -#define sqlite3_fsetmode(F,X) /*no-op*/ - -#endif -#endif /* _SQLITE3_STDIO_H_ */ - -/************************* End ext/misc/sqlite3_stdio.h ********************/ -/************************* Begin ext/misc/sqlite3_stdio.c ******************/ -/* -** 2024-09-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. -** -************************************************************************* -** -** Implementation of standard I/O interfaces for UTF-8 that are missing -** on Windows. -*/ -#ifdef _WIN32 /* This file is a no-op on all platforms except Windows */ -#ifndef _SQLITE3_STDIO_H_ -/* #include "sqlite3_stdio.h" */ -#endif -#undef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -/* #include "sqlite3.h" */ -#include -#include -#include -#include - -/* -** If the SQLITE_U8TEXT_ONLY option is defined, then use O_U8TEXT -** when appropriate on all output. (Sometimes use O_BINARY when -** rendering ASCII text in cases where NL-to-CRLF expansion would -** not be correct.) -** -** If the SQLITE_U8TEXT_STDIO option is defined, then use O_U8TEXT -** when appropriate when writing to stdout or stderr. Use O_BINARY -** or O_TEXT (depending on things like the .mode and the .crlf setting -** in the CLI, or other context clues in other applications) for all -** other output channels. -** -** The default behavior, if neither of the above is defined is to -** use O_U8TEXT when writing to the Windows console (or anything -** else for which _isatty() returns true) and to use O_BINARY or O_TEXT -** for all other output channels. -** -** The SQLITE_USE_W32_FOR_CONSOLE_IO macro is also available. If -** defined, it forces the use of Win32 APIs for all console I/O, both -** input and output. This is necessary for some non-Microsoft run-times -** that implement stdio differently from Microsoft/Visual-Studio. -*/ -#if defined(SQLITE_U8TEXT_ONLY) -# define UseWtextForOutput(fd) 1 -# define UseWtextForInput(fd) 1 -# define IsConsole(fd) _isatty(_fileno(fd)) -#elif defined(SQLITE_U8TEXT_STDIO) -# define UseWtextForOutput(fd) ((fd)==stdout || (fd)==stderr) -# define UseWtextForInput(fd) ((fd)==stdin) -# define IsConsole(fd) _isatty(_fileno(fd)) -#else -# define UseWtextForOutput(fd) _isatty(_fileno(fd)) -# define UseWtextForInput(fd) _isatty(_fileno(fd)) -# define IsConsole(fd) 1 -#endif - -/* -** Global variables determine if simulated O_BINARY mode is to be -** used for stdout or other, respectively. Simulated O_BINARY mode -** means the mode is usually O_BINARY, but switches to O_U8TEXT for -** unicode characters U+0080 or greater (any character that has a -** multi-byte representation in UTF-8). This is the only way we -** have found to render Unicode characters on a Windows console while -** at the same time avoiding undesirable \n to \r\n translation. -*/ -static int simBinaryStdout = 0; -static int simBinaryOther = 0; - - -/* -** Determine if simulated binary mode should be used for output to fd -*/ -static int UseBinaryWText(FILE *fd){ - if( fd==stdout || fd==stderr ){ - return simBinaryStdout; - }else{ - return simBinaryOther; - } -} - - -/* -** Work-alike for the fopen() routine from the standard C library. -*/ -FILE *sqlite3_fopen(const char *zFilename, const char *zMode){ - FILE *fp = 0; - wchar_t *b1, *b2; - int sz1, sz2; - - sz1 = (int)strlen(zFilename); - sz2 = (int)strlen(zMode); - b1 = sqlite3_malloc64( (sz1+1)*sizeof(b1[0]) ); - b2 = sqlite3_malloc64( (sz2+1)*sizeof(b1[0]) ); - if( b1 && b2 ){ - sz1 = MultiByteToWideChar(CP_UTF8, 0, zFilename, sz1, b1, sz1); - b1[sz1] = 0; - sz2 = MultiByteToWideChar(CP_UTF8, 0, zMode, sz2, b2, sz2); - b2[sz2] = 0; - fp = _wfopen(b1, b2); - } - sqlite3_free(b1); - sqlite3_free(b2); - simBinaryOther = 0; - return fp; -} - - -/* -** Work-alike for the popen() routine from the standard C library. -*/ -FILE *sqlite3_popen(const char *zCommand, const char *zMode){ - FILE *fp = 0; - wchar_t *b1, *b2; - int sz1, sz2; - - sz1 = (int)strlen(zCommand); - sz2 = (int)strlen(zMode); - b1 = sqlite3_malloc64( (sz1+1)*sizeof(b1[0]) ); - b2 = sqlite3_malloc64( (sz2+1)*sizeof(b1[0]) ); - if( b1 && b2 ){ - sz1 = MultiByteToWideChar(CP_UTF8, 0, zCommand, sz1, b1, sz1); - b1[sz1] = 0; - sz2 = MultiByteToWideChar(CP_UTF8, 0, zMode, sz2, b2, sz2); - b2[sz2] = 0; - fp = _wpopen(b1, b2); - } - sqlite3_free(b1); - sqlite3_free(b2); - return fp; -} - -/* -** Work-alike for fgets() from the standard C library. -*/ -char *sqlite3_fgets(char *buf, int sz, FILE *in){ - if( UseWtextForInput(in) ){ - /* When reading from the command-prompt in Windows, it is necessary - ** to use _O_WTEXT input mode to read UTF-16 characters, then translate - ** that into UTF-8. Otherwise, non-ASCII characters all get translated - ** into '?'. - */ - wchar_t *b1 = sqlite3_malloc64( sz*sizeof(wchar_t) ); - if( b1==0 ) return 0; -#ifdef SQLITE_USE_W32_FOR_CONSOLE_IO - DWORD nRead = 0; - if( IsConsole(in) - && ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), b1, sz-1, &nRead, 0) - ){ - b1[nRead] = 0; - }else -#endif - { - _setmode(_fileno(in), IsConsole(in) ? _O_WTEXT : _O_U8TEXT); - if( fgetws(b1, sz/4, in)==0 ){ - sqlite3_free(b1); - return 0; - } - } - WideCharToMultiByte(CP_UTF8, 0, b1, -1, buf, sz, 0, 0); - sqlite3_free(b1); - return buf; - }else{ - /* Reading from a file or other input source, just read bytes without - ** any translation. */ - return fgets(buf, sz, in); - } -} - -/* -** Send ASCII text as O_BINARY. But for Unicode characters U+0080 and -** greater, switch to O_U8TEXT. -*/ -static void piecemealOutput(wchar_t *b1, int sz, FILE *out){ - int i; - wchar_t c; - while( sz>0 ){ - for(i=0; i=0x80; i++){} - if( i>0 ){ - c = b1[i]; - b1[i] = 0; - fflush(out); - _setmode(_fileno(out), _O_U8TEXT); - fputws(b1, out); - fflush(out); - b1 += i; - b1[0] = c; - sz -= i; - }else{ - fflush(out); - _setmode(_fileno(out), _O_TEXT); - _setmode(_fileno(out), _O_BINARY); - fwrite(&b1[0], 1, 1, out); - for(i=1; i -/* #include "sqlite3.h" */ - -/* -** Specification used by clients to define the output format they want -*/ -typedef struct sqlite3_qrf_spec sqlite3_qrf_spec; -struct sqlite3_qrf_spec { - unsigned char iVersion; /* Version number of this structure */ - unsigned char eStyle; /* Formatting style. "box", "csv", etc... */ - unsigned char eEsc; /* How to escape control characters in text */ - unsigned char eText; /* Quoting style for text */ - unsigned char eTitle; /* Quating style for the text of column names */ - unsigned char eBlob; /* Quoting style for BLOBs */ - unsigned char bTitles; /* True to show column names */ - unsigned char bWordWrap; /* Try to wrap on word boundaries */ - unsigned char bTextJsonb; /* Render JSONB blobs as JSON text */ - unsigned char eDfltAlign; /* Default alignment, no covered by aAlignment */ - unsigned char eTitleAlign; /* Alignment for column headers */ - unsigned char bSplitColumn; /* Wrap single-column output into many columns */ - unsigned char bBorder; /* Show outer border in Box and Table styles */ - short int nWrap; /* Wrap columns wider than this */ - short int nScreenWidth; /* Maximum overall table width */ - short int nLineLimit; /* Maximum number of lines for any row */ - short int nTitleLimit; /* Maximum number of characters in a title */ - unsigned int nMultiInsert; /* Add rows to one INSERT until size exceeds */ - int nCharLimit; /* Maximum number of characters in a cell */ - int nWidth; /* Number of entries in aWidth[] */ - int nAlign; /* Number of entries in aAlignment[] */ - short int *aWidth; /* Column widths */ - unsigned char *aAlign; /* Column alignments */ - char *zColumnSep; /* Alternative column separator */ - char *zRowSep; /* Alternative row separator */ - char *zTableName; /* Output table name */ - char *zNull; /* Rendering of NULL */ - char *(*xRender)(void*,sqlite3_value*); /* Render a value */ - int (*xWrite)(void*,const char*,sqlite3_int64); /* Write output */ - void *pRenderArg; /* First argument to the xRender callback */ - void *pWriteArg; /* First argument to the xWrite callback */ - char **pzOutput; /* Storage location for output string */ - /* Additional fields may be added in the future */ -}; - -/* -** Interfaces -*/ -int sqlite3_format_query_result( - sqlite3_stmt *pStmt, /* SQL statement to run */ - const sqlite3_qrf_spec *pSpec, /* Result format specification */ - char **pzErr /* OUT: Write error message here */ -); - -/* -** Range of values for sqlite3_qrf_spec.aWidth[] entries and for -** sqlite3_qrf_spec.mxColWidth and .nScreenWidth -*/ -#define QRF_MAX_WIDTH 10000 -#define QRF_MIN_WIDTH 0 - -/* -** Output styles: -*/ -#define QRF_STYLE_Auto 0 /* Choose a style automatically */ -#define QRF_STYLE_Box 1 /* Unicode box-drawing characters */ -#define QRF_STYLE_Column 2 /* One record per line in neat columns */ -#define QRF_STYLE_Count 3 /* Output only a count of the rows of output */ -#define QRF_STYLE_Csv 4 /* Comma-separated-value */ -#define QRF_STYLE_Eqp 5 /* Format EXPLAIN QUERY PLAN output */ -#define QRF_STYLE_Explain 6 /* EXPLAIN output */ -#define QRF_STYLE_Html 7 /* Generate an XHTML table */ -#define QRF_STYLE_Insert 8 /* Generate SQL "insert" statements */ -#define QRF_STYLE_Json 9 /* Output is a list of JSON objects */ -#define QRF_STYLE_JObject 10 /* Independent JSON objects for each row */ -#define QRF_STYLE_Line 11 /* One column per line. */ -#define QRF_STYLE_List 12 /* One record per line with a separator */ -#define QRF_STYLE_Markdown 13 /* Markdown formatting */ -#define QRF_STYLE_Off 14 /* No query output shown */ -#define QRF_STYLE_Quote 15 /* SQL-quoted, comma-separated */ -#define QRF_STYLE_Stats 16 /* EQP-like output but with performance stats */ -#define QRF_STYLE_StatsEst 17 /* EQP-like output with planner estimates */ -#define QRF_STYLE_StatsVm 18 /* EXPLAIN-like output with performance stats */ -#define QRF_STYLE_Table 19 /* MySQL-style table formatting */ - -/* -** Quoting styles for text. -** Allowed values for sqlite3_qrf_spec.eText -*/ -#define QRF_TEXT_Auto 0 /* Choose text encoding automatically */ -#define QRF_TEXT_Plain 1 /* Literal text */ -#define QRF_TEXT_Sql 2 /* Quote as an SQL literal */ -#define QRF_TEXT_Csv 3 /* CSV-style quoting */ -#define QRF_TEXT_Html 4 /* HTML-style quoting */ -#define QRF_TEXT_Tcl 5 /* C/Tcl quoting */ -#define QRF_TEXT_Json 6 /* JSON quoting */ -#define QRF_TEXT_Relaxed 7 /* Relaxed SQL quoting */ - -/* -** Quoting styles for BLOBs -** Allowed values for sqlite3_qrf_spec.eBlob -*/ -#define QRF_BLOB_Auto 0 /* Determine BLOB quoting using eText */ -#define QRF_BLOB_Text 1 /* Display content exactly as it is */ -#define QRF_BLOB_Sql 2 /* Quote as an SQL literal */ -#define QRF_BLOB_Hex 3 /* Hexadecimal representation */ -#define QRF_BLOB_Tcl 4 /* "\000" notation */ -#define QRF_BLOB_Json 5 /* A JSON string */ -#define QRF_BLOB_Size 6 /* Display the blob size only */ - -/* -** Control-character escape modes. -** Allowed values for sqlite3_qrf_spec.eEsc -*/ -#define QRF_ESC_Auto 0 /* Choose the ctrl-char escape automatically */ -#define QRF_ESC_Off 1 /* Do not escape control characters */ -#define QRF_ESC_Ascii 2 /* Unix-style escapes. Ex: U+0007 shows ^G */ -#define QRF_ESC_Symbol 3 /* Unicode escapes. Ex: U+0007 shows U+2407 */ - -/* -** Allowed values for "boolean" fields, such as "bColumnNames", "bWordWrap", -** and "bTextJsonb". There is an extra "auto" variants so these are actually -** tri-state settings, not booleans. -*/ -#define QRF_SW_Auto 0 /* Let QRF choose the best value */ -#define QRF_SW_Off 1 /* This setting is forced off */ -#define QRF_SW_On 2 /* This setting is forced on */ -#define QRF_Auto 0 /* Alternate spelling for QRF_*_Auto */ -#define QRF_No 1 /* Alternate spelling for QRF_SW_Off */ -#define QRF_Yes 2 /* Alternate spelling for QRF_SW_On */ - -/* -** Possible alignment values alignment settings -** -** Horizontal Vertial -** ---------- -------- */ -#define QRF_ALIGN_Auto 0 /* auto auto */ -#define QRF_ALIGN_Left 1 /* left auto */ -#define QRF_ALIGN_Center 2 /* center auto */ -#define QRF_ALIGN_Right 3 /* right auto */ -#define QRF_ALIGN_Top 4 /* auto top */ -#define QRF_ALIGN_NW 5 /* left top */ -#define QRF_ALIGN_N 6 /* center top */ -#define QRF_ALIGN_NE 7 /* right top */ -#define QRF_ALIGN_Middle 8 /* auto middle */ -#define QRF_ALIGN_W 9 /* left middle */ -#define QRF_ALIGN_C 10 /* center middle */ -#define QRF_ALIGN_E 11 /* right middle */ -#define QRF_ALIGN_Bottom 12 /* auto bottom */ -#define QRF_ALIGN_SW 13 /* left bottom */ -#define QRF_ALIGN_S 14 /* center bottom */ -#define QRF_ALIGN_SE 15 /* right bottom */ -#define QRF_ALIGN_HMASK 3 /* Horizontal alignment mask */ -#define QRF_ALIGN_VMASK 12 /* Vertical alignment mask */ - -/* -** Auxiliary routines contined within this module that might be useful -** in other contexts, and which are therefore exported. -*/ -/* -** Return an estimate of the width, in columns, for the single Unicode -** character c. For normal characters, the answer is always 1. But the -** estimate might be 0 or 2 for zero-width and double-width characters. -** -** Different devices display unicode using different widths. So -** it is impossible to know that true display width with 100% accuracy. -** Inaccuracies in the width estimates might cause columns to be misaligned. -** Unfortunately, there is nothing we can do about that. -*/ -int sqlite3_qrf_wcwidth(int c); - -/* -** Return an estimate of the number of display columns used by the -** string in the argument. The width of individual characters is -** determined as for sqlite3_qrf_wcwidth(). VT100 escape code sequences -** are assigned a width of zero. -*/ -size_t sqlite3_qrf_wcswidth(const char*); - - -#ifdef __cplusplus -} -#endif -#endif /* !defined(SQLITE_QRF_H) */ - -/************************* End ext/qrf/qrf.h ********************/ -/************************* Begin ext/qrf/qrf.c ******************/ -/* -** 2025-10-20 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** Implementation of the Query Result-Format or "qrf" utility library for -** SQLite. See the README.md documentation for additional information. -*/ -#ifndef SQLITE_QRF_H -#include "qrf.h" -#endif -#include -#include -#include - -#ifndef SQLITE_AMALGAMATION -/* typedef sqlite3_int64 i64; */ -#endif - -/* A single line in the EQP output */ -typedef struct qrfEQPGraphRow qrfEQPGraphRow; -struct qrfEQPGraphRow { - int iEqpId; /* ID for this row */ - int iParentId; /* ID of the parent row */ - qrfEQPGraphRow *pNext; /* Next row in sequence */ - char zText[1]; /* Text to display for this row */ -}; - -/* All EQP output is collected into an instance of the following */ -typedef struct qrfEQPGraph qrfEQPGraph; -struct qrfEQPGraph { - qrfEQPGraphRow *pRow; /* Linked list of all rows of the EQP output */ - qrfEQPGraphRow *pLast; /* Last element of the pRow list */ - int nWidth; /* Width of the graph */ - char zPrefix[400]; /* Graph prefix */ -}; - -/* -** Private state information. Subject to change from one release to the -** next. -*/ -typedef struct Qrf Qrf; -struct Qrf { - sqlite3_stmt *pStmt; /* The statement whose output is to be rendered */ - sqlite3 *db; /* The corresponding database connection */ - sqlite3_stmt *pJTrans; /* JSONB to JSON translator statement */ - char **pzErr; /* Write error message here, if not NULL */ - sqlite3_str *pOut; /* Accumulated output */ - int iErr; /* Error code */ - int nCol; /* Number of output columns */ - int expMode; /* Original sqlite3_stmt_isexplain() plus 1 */ - int mxWidth; /* Screen width */ - int mxHeight; /* nLineLimit */ - union { - struct { /* Content for QRF_STYLE_Line */ - int mxColWth; /* Maximum display width of any column */ - char **azCol; /* Names of output columns (MODE_Line) */ - } sLine; - qrfEQPGraph *pGraph; /* EQP graph (Eqp, Stats, and StatsEst) */ - struct { /* Content for QRF_STYLE_Explain */ - int nIndent; /* Slots allocated for aiIndent */ - int iIndent; /* Current slot */ - int *aiIndent; /* Indentation for each opcode */ - } sExpln; - unsigned int nIns; /* Bytes used for current INSERT stmt */ - } u; - sqlite3_int64 nRow; /* Number of rows handled so far */ - int *actualWidth; /* Actual width of each column */ - sqlite3_qrf_spec spec; /* Copy of the original spec */ -}; - -/* -** Data for substitute ctype.h functions. Used for x-platform -** consistency and so that '_' is counted as an alphabetic -** character. -** -** 0x01 - space -** 0x02 - digit -** 0x04 - alphabetic, including '_' -*/ -static const char qrfCType[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 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, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, - 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, - 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 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 qrfSpace(x) ((qrfCType[(unsigned char)x]&1)!=0) -#define qrfDigit(x) ((qrfCType[(unsigned char)x]&2)!=0) -#define qrfAlpha(x) ((qrfCType[(unsigned char)x]&4)!=0) -#define qrfAlnum(x) ((qrfCType[(unsigned char)x]&6)!=0) - -#ifndef deliberate_fall_through -/* Quiet some compilers about some of our intentional code. */ -# if defined(GCC_VERSION) && GCC_VERSION>=7000000 -# define deliberate_fall_through __attribute__((fallthrough)); -# else -# define deliberate_fall_through -# endif -#endif - -/* -** Set an error code and error message. -*/ -static void qrfError( - Qrf *p, /* Query result state */ - int iCode, /* Error code */ - const char *zFormat, /* Message format (or NULL) */ - ... -){ - p->iErr = iCode; - if( p->pzErr!=0 ){ - sqlite3_free(*p->pzErr); - *p->pzErr = 0; - if( zFormat ){ - va_list ap; - va_start(ap, zFormat); - *p->pzErr = sqlite3_vmprintf(zFormat, ap); - va_end(ap); - } - } -} - -/* -** Out-of-memory error. -*/ -static void qrfOom(Qrf *p){ - qrfError(p, SQLITE_NOMEM, "out of memory"); -} - -/* -** Transfer any error in pStr over into p. -*/ -static void qrfStrErr(Qrf *p, sqlite3_str *pStr){ - int rc = pStr ? sqlite3_str_errcode(pStr) : 0; - if( rc ){ - qrfError(p, rc, sqlite3_errstr(rc)); - } -} - - -/* -** Add a new entry to the EXPLAIN QUERY PLAN data -*/ -static void qrfEqpAppend(Qrf *p, int iEqpId, int p2, const char *zText){ - qrfEQPGraphRow *pNew; - sqlite3_int64 nText; - if( zText==0 ) return; - if( p->u.pGraph==0 ){ - p->u.pGraph = sqlite3_malloc64( sizeof(qrfEQPGraph) ); - if( p->u.pGraph==0 ){ - qrfOom(p); - return; - } - memset(p->u.pGraph, 0, sizeof(qrfEQPGraph) ); - } - nText = strlen(zText); - pNew = sqlite3_malloc64( sizeof(*pNew) + nText ); - if( pNew==0 ){ - qrfOom(p); - return; - } - pNew->iEqpId = iEqpId; - pNew->iParentId = p2; - memcpy(pNew->zText, zText, nText+1); - pNew->pNext = 0; - if( p->u.pGraph->pLast ){ - p->u.pGraph->pLast->pNext = pNew; - }else{ - p->u.pGraph->pRow = pNew; - } - p->u.pGraph->pLast = pNew; -} - -/* -** Free and reset the EXPLAIN QUERY PLAN data that has been collected -** in p->u.pGraph. -*/ -static void qrfEqpReset(Qrf *p){ - qrfEQPGraphRow *pRow, *pNext; - if( p->u.pGraph ){ - for(pRow = p->u.pGraph->pRow; pRow; pRow = pNext){ - pNext = pRow->pNext; - sqlite3_free(pRow); - } - sqlite3_free(p->u.pGraph); - p->u.pGraph = 0; - } -} - -/* Return the next EXPLAIN QUERY PLAN line with iEqpId that occurs after -** pOld, or return the first such line if pOld is NULL -*/ -static qrfEQPGraphRow *qrfEqpNextRow(Qrf *p, int iEqpId, qrfEQPGraphRow *pOld){ - qrfEQPGraphRow *pRow = pOld ? pOld->pNext : p->u.pGraph->pRow; - while( pRow && pRow->iParentId!=iEqpId ) pRow = pRow->pNext; - return pRow; -} - -/* Render a single level of the graph that has iEqpId as its parent. Called -** recursively to render sublevels. -*/ -static void qrfEqpRenderLevel(Qrf *p, int iEqpId){ - qrfEQPGraphRow *pRow, *pNext; - i64 n = strlen(p->u.pGraph->zPrefix); - char *z; - for(pRow = qrfEqpNextRow(p, iEqpId, 0); pRow; pRow = pNext){ - pNext = qrfEqpNextRow(p, iEqpId, pRow); - z = pRow->zText; - sqlite3_str_appendf(p->pOut, "%s%s%s\n", p->u.pGraph->zPrefix, - pNext ? "|--" : "`--", z); - if( n<(i64)sizeof(p->u.pGraph->zPrefix)-7 ){ - memcpy(&p->u.pGraph->zPrefix[n], pNext ? "| " : " ", 4); - qrfEqpRenderLevel(p, pRow->iEqpId); - p->u.pGraph->zPrefix[n] = 0; - } - } -} - -/* -** Render the 64-bit value N in a more human-readable format into -** pOut. -** -** + Only show the first three significant digits. -** + Append suffixes K, M, G, T, P, and E for 1e3, 1e6, ... 1e18 -*/ -static void qrfApproxInt64(sqlite3_str *pOut, i64 N){ - static const char aSuffix[] = { 'K', 'M', 'G', 'T', 'P', 'E' }; - int i; - if( N<0 ){ - N = N==INT64_MIN ? INT64_MAX : -N; - sqlite3_str_append(pOut, "-", 1); - } - if( N<10000 ){ - sqlite3_str_appendf(pOut, "%4lld ", N); - return; - } - for(i=1; i<=18; i++){ - N = (N+5)/10; - if( N<10000 ){ - int n = (int)N; - switch( i%3 ){ - case 0: - sqlite3_str_appendf(pOut, "%d.%02d", n/1000, (n%1000)/10); - break; - case 1: - sqlite3_str_appendf(pOut, "%2d.%d", n/100, (n%100)/10); - break; - case 2: - sqlite3_str_appendf(pOut, "%4d", n/10); - break; - } - sqlite3_str_append(pOut, &aSuffix[i/3], 1); - break; - } - } -} - -/* -** Display and reset the EXPLAIN QUERY PLAN data -*/ -static void qrfEqpRender(Qrf *p, i64 nCycle){ - qrfEQPGraphRow *pRow; - if( p->u.pGraph!=0 && (pRow = p->u.pGraph->pRow)!=0 ){ - if( pRow->zText[0]=='-' ){ - if( pRow->pNext==0 ){ - qrfEqpReset(p); - return; - } - sqlite3_str_appendf(p->pOut, "%s\n", pRow->zText+3); - p->u.pGraph->pRow = pRow->pNext; - sqlite3_free(pRow); - }else if( nCycle>0 ){ - int nSp = p->u.pGraph->nWidth - 2; - if( p->spec.eStyle==QRF_STYLE_StatsEst ){ - sqlite3_str_appendchar(p->pOut, nSp, ' '); - sqlite3_str_appendall(p->pOut, - "Cycles Loops (est) Rows (est)\n"); - sqlite3_str_appendchar(p->pOut, nSp, ' '); - sqlite3_str_appendall(p->pOut, - "---------- ------------ ------------\n"); - }else{ - sqlite3_str_appendchar(p->pOut, nSp, ' '); - sqlite3_str_appendall(p->pOut, - "Cycles Loops Rows \n"); - sqlite3_str_appendchar(p->pOut, nSp, ' '); - sqlite3_str_appendall(p->pOut, - "---------- ----- -----\n"); - } - sqlite3_str_appendall(p->pOut, "QUERY PLAN"); - sqlite3_str_appendchar(p->pOut, nSp - 10, ' '); - qrfApproxInt64(p->pOut, nCycle); - sqlite3_str_appendall(p->pOut, " 100%\n"); - }else{ - sqlite3_str_appendall(p->pOut, "QUERY PLAN\n"); - } - p->u.pGraph->zPrefix[0] = 0; - qrfEqpRenderLevel(p, 0); - qrfEqpReset(p); - } -} - -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS -/* -** Helper function for qrfExpStats(). -** -*/ -static int qrfStatsHeight(sqlite3_stmt *p, int iEntry){ - int iPid = 0; - int ret = 1; - sqlite3_stmt_scanstatus_v2(p, iEntry, - SQLITE_SCANSTAT_SELECTID, SQLITE_SCANSTAT_COMPLEX, (void*)&iPid - ); - while( iPid!=0 ){ - int ii; - for(ii=0; 1; ii++){ - int iId; - int res; - res = sqlite3_stmt_scanstatus_v2(p, ii, - SQLITE_SCANSTAT_SELECTID, SQLITE_SCANSTAT_COMPLEX, (void*)&iId - ); - if( res ) break; - if( iId==iPid ){ - sqlite3_stmt_scanstatus_v2(p, ii, - SQLITE_SCANSTAT_PARENTID, SQLITE_SCANSTAT_COMPLEX, (void*)&iPid - ); - } - } - ret++; - } - return ret; -} -#endif /* SQLITE_ENABLE_STMT_SCANSTATUS */ - - -/* -** Generate ".scanstatus est" style of EQP output. -*/ -static void qrfEqpStats(Qrf *p){ -#ifndef SQLITE_ENABLE_STMT_SCANSTATUS - qrfError(p, SQLITE_ERROR, "not available in this build"); -#else - static const int f = SQLITE_SCANSTAT_COMPLEX; - sqlite3_stmt *pS = p->pStmt; - int i = 0; - i64 nTotal = 0; - int nWidth = 0; - int prevPid = -1; /* Previous iPid */ - double rEstCum = 1.0; /* Cumulative row estimate */ - sqlite3_str *pLine = sqlite3_str_new(p->db); - sqlite3_str *pStats = sqlite3_str_new(p->db); - qrfEqpReset(p); - - for(i=0; 1; i++){ - const char *z = 0; - int n = 0; - if( sqlite3_stmt_scanstatus_v2(pS,i,SQLITE_SCANSTAT_EXPLAIN,f,(void*)&z) ){ - break; - } - n = (int)strlen(z) + qrfStatsHeight(pS,i)*3; - if( n>nWidth ) nWidth = n; - } - nWidth += 2; - - sqlite3_stmt_scanstatus_v2(pS,-1, SQLITE_SCANSTAT_NCYCLE, f, (void*)&nTotal); - for(i=0; 1; i++){ - i64 nLoop = 0; - i64 nRow = 0; - i64 nCycle = 0; - int iId = 0; - int iPid = 0; - const char *zo = 0; - const char *zName = 0; - double rEst = 0.0; - - if( sqlite3_stmt_scanstatus_v2(pS,i,SQLITE_SCANSTAT_EXPLAIN,f,(void*)&zo) ){ - break; - } - sqlite3_stmt_scanstatus_v2(pS,i, SQLITE_SCANSTAT_PARENTID,f,(void*)&iPid); - if( iPid!=prevPid ){ - prevPid = iPid; - rEstCum = 1.0; - } - sqlite3_stmt_scanstatus_v2(pS,i, SQLITE_SCANSTAT_EST,f,(void*)&rEst); - rEstCum *= rEst; - sqlite3_stmt_scanstatus_v2(pS,i, SQLITE_SCANSTAT_NLOOP,f,(void*)&nLoop); - sqlite3_stmt_scanstatus_v2(pS,i, SQLITE_SCANSTAT_NVISIT,f,(void*)&nRow); - sqlite3_stmt_scanstatus_v2(pS,i, SQLITE_SCANSTAT_NCYCLE,f,(void*)&nCycle); - sqlite3_stmt_scanstatus_v2(pS,i, SQLITE_SCANSTAT_SELECTID,f,(void*)&iId); - sqlite3_stmt_scanstatus_v2(pS,i, SQLITE_SCANSTAT_NAME,f,(void*)&zName); - - if( nCycle>=0 || nLoop>=0 || nRow>=0 ){ - int nSp = 0; - sqlite3_str_reset(pStats); - if( nCycle>=0 && nTotal>0 ){ - qrfApproxInt64(pStats, nCycle); - sqlite3_str_appendf(pStats, " %3d%%", - ((nCycle*100)+nTotal/2) / nTotal - ); - nSp = 2; - } - if( nLoop>=0 ){ - if( nSp ) sqlite3_str_appendchar(pStats, nSp, ' '); - qrfApproxInt64(pStats, nLoop); - nSp = 2; - if( p->spec.eStyle==QRF_STYLE_StatsEst ){ - sqlite3_str_appendf(pStats, " "); - qrfApproxInt64(pStats, (i64)(rEstCum/rEst)); - } - } - if( nRow>=0 ){ - if( nSp ) sqlite3_str_appendchar(pStats, nSp, ' '); - qrfApproxInt64(pStats, nRow); - nSp = 2; - if( p->spec.eStyle==QRF_STYLE_StatsEst ){ - sqlite3_str_appendf(pStats, " "); - qrfApproxInt64(pStats, (i64)rEstCum); - } - } - sqlite3_str_appendf(pLine, - "% *s %s", -1*(nWidth-qrfStatsHeight(pS,i)*3), zo, - sqlite3_str_value(pStats) - ); - sqlite3_str_reset(pStats); - qrfEqpAppend(p, iId, iPid, sqlite3_str_value(pLine)); - sqlite3_str_reset(pLine); - }else{ - qrfEqpAppend(p, iId, iPid, zo); - } - } - if( p->u.pGraph ) p->u.pGraph->nWidth = nWidth; - qrfStrErr(p, pLine); - sqlite3_free(sqlite3_str_finish(pLine)); - qrfStrErr(p, pStats); - sqlite3_free(sqlite3_str_finish(pStats)); -#endif -} - - -/* -** Reset the prepared statement. -*/ -static void qrfResetStmt(Qrf *p){ - int rc = sqlite3_reset(p->pStmt); - if( rc!=SQLITE_OK && p->iErr==SQLITE_OK ){ - qrfError(p, rc, "%s", sqlite3_errmsg(p->db)); - } -} - -/* -** If xWrite is defined, send all content of pOut to xWrite and -** reset pOut. -*/ -static void qrfWrite(Qrf *p){ - int n; - if( p->spec.xWrite && (n = sqlite3_str_length(p->pOut))>0 ){ - int rc = p->spec.xWrite(p->spec.pWriteArg, - sqlite3_str_value(p->pOut), - (sqlite3_int64)n); - sqlite3_str_reset(p->pOut); - if( rc ){ - qrfError(p, rc, "Failed to write %d bytes of output", n); - } - } -} - -/* Lookup table to estimate the number of columns consumed by a Unicode -** character. -*/ -static const struct { - unsigned char w; /* Width of the character in columns */ - int iFirst; /* First character in a span having this width */ -} aQrfUWidth[] = { - /* {1, 0x00000}, */ - {0, 0x00300}, {1, 0x00370}, {0, 0x00483}, {1, 0x00487}, {0, 0x00488}, - {1, 0x0048a}, {0, 0x00591}, {1, 0x005be}, {0, 0x005bf}, {1, 0x005c0}, - {0, 0x005c1}, {1, 0x005c3}, {0, 0x005c4}, {1, 0x005c6}, {0, 0x005c7}, - {1, 0x005c8}, {0, 0x00600}, {1, 0x00604}, {0, 0x00610}, {1, 0x00616}, - {0, 0x0064b}, {1, 0x0065f}, {0, 0x00670}, {1, 0x00671}, {0, 0x006d6}, - {1, 0x006e5}, {0, 0x006e7}, {1, 0x006e9}, {0, 0x006ea}, {1, 0x006ee}, - {0, 0x0070f}, {1, 0x00710}, {0, 0x00711}, {1, 0x00712}, {0, 0x00730}, - {1, 0x0074b}, {0, 0x007a6}, {1, 0x007b1}, {0, 0x007eb}, {1, 0x007f4}, - {0, 0x00901}, {1, 0x00903}, {0, 0x0093c}, {1, 0x0093d}, {0, 0x00941}, - {1, 0x00949}, {0, 0x0094d}, {1, 0x0094e}, {0, 0x00951}, {1, 0x00955}, - {0, 0x00962}, {1, 0x00964}, {0, 0x00981}, {1, 0x00982}, {0, 0x009bc}, - {1, 0x009bd}, {0, 0x009c1}, {1, 0x009c5}, {0, 0x009cd}, {1, 0x009ce}, - {0, 0x009e2}, {1, 0x009e4}, {0, 0x00a01}, {1, 0x00a03}, {0, 0x00a3c}, - {1, 0x00a3d}, {0, 0x00a41}, {1, 0x00a43}, {0, 0x00a47}, {1, 0x00a49}, - {0, 0x00a4b}, {1, 0x00a4e}, {0, 0x00a70}, {1, 0x00a72}, {0, 0x00a81}, - {1, 0x00a83}, {0, 0x00abc}, {1, 0x00abd}, {0, 0x00ac1}, {1, 0x00ac6}, - {0, 0x00ac7}, {1, 0x00ac9}, {0, 0x00acd}, {1, 0x00ace}, {0, 0x00ae2}, - {1, 0x00ae4}, {0, 0x00b01}, {1, 0x00b02}, {0, 0x00b3c}, {1, 0x00b3d}, - {0, 0x00b3f}, {1, 0x00b40}, {0, 0x00b41}, {1, 0x00b44}, {0, 0x00b4d}, - {1, 0x00b4e}, {0, 0x00b56}, {1, 0x00b57}, {0, 0x00b82}, {1, 0x00b83}, - {0, 0x00bc0}, {1, 0x00bc1}, {0, 0x00bcd}, {1, 0x00bce}, {0, 0x00c3e}, - {1, 0x00c41}, {0, 0x00c46}, {1, 0x00c49}, {0, 0x00c4a}, {1, 0x00c4e}, - {0, 0x00c55}, {1, 0x00c57}, {0, 0x00cbc}, {1, 0x00cbd}, {0, 0x00cbf}, - {1, 0x00cc0}, {0, 0x00cc6}, {1, 0x00cc7}, {0, 0x00ccc}, {1, 0x00cce}, - {0, 0x00ce2}, {1, 0x00ce4}, {0, 0x00d41}, {1, 0x00d44}, {0, 0x00d4d}, - {1, 0x00d4e}, {0, 0x00dca}, {1, 0x00dcb}, {0, 0x00dd2}, {1, 0x00dd5}, - {0, 0x00dd6}, {1, 0x00dd7}, {0, 0x00e31}, {1, 0x00e32}, {0, 0x00e34}, - {1, 0x00e3b}, {0, 0x00e47}, {1, 0x00e4f}, {0, 0x00eb1}, {1, 0x00eb2}, - {0, 0x00eb4}, {1, 0x00eba}, {0, 0x00ebb}, {1, 0x00ebd}, {0, 0x00ec8}, - {1, 0x00ece}, {0, 0x00f18}, {1, 0x00f1a}, {0, 0x00f35}, {1, 0x00f36}, - {0, 0x00f37}, {1, 0x00f38}, {0, 0x00f39}, {1, 0x00f3a}, {0, 0x00f71}, - {1, 0x00f7f}, {0, 0x00f80}, {1, 0x00f85}, {0, 0x00f86}, {1, 0x00f88}, - {0, 0x00f90}, {1, 0x00f98}, {0, 0x00f99}, {1, 0x00fbd}, {0, 0x00fc6}, - {1, 0x00fc7}, {0, 0x0102d}, {1, 0x01031}, {0, 0x01032}, {1, 0x01033}, - {0, 0x01036}, {1, 0x0103b}, {0, 0x01058}, - {1, 0x0105a}, {2, 0x01100}, {0, 0x01160}, {1, 0x01200}, {0, 0x0135f}, - {1, 0x01360}, {0, 0x01712}, {1, 0x01715}, {0, 0x01732}, {1, 0x01735}, - {0, 0x01752}, {1, 0x01754}, {0, 0x01772}, {1, 0x01774}, {0, 0x017b4}, - {1, 0x017b6}, {0, 0x017b7}, {1, 0x017be}, {0, 0x017c6}, {1, 0x017c7}, - {0, 0x017c9}, {1, 0x017d4}, {0, 0x017dd}, {1, 0x017de}, {0, 0x0180b}, - {1, 0x0180e}, {0, 0x018a9}, {1, 0x018aa}, {0, 0x01920}, {1, 0x01923}, - {0, 0x01927}, {1, 0x01929}, {0, 0x01932}, {1, 0x01933}, {0, 0x01939}, - {1, 0x0193c}, {0, 0x01a17}, {1, 0x01a19}, {0, 0x01b00}, {1, 0x01b04}, - {0, 0x01b34}, {1, 0x01b35}, {0, 0x01b36}, {1, 0x01b3b}, {0, 0x01b3c}, - {1, 0x01b3d}, {0, 0x01b42}, {1, 0x01b43}, {0, 0x01b6b}, {1, 0x01b74}, - {0, 0x01dc0}, {1, 0x01dcb}, {0, 0x01dfe}, {1, 0x01e00}, {0, 0x0200b}, - {1, 0x02010}, {0, 0x0202a}, {1, 0x0202f}, {0, 0x02060}, {1, 0x02064}, - {0, 0x0206a}, {1, 0x02070}, {0, 0x020d0}, {1, 0x020f0}, {2, 0x02329}, - {1, 0x0232b}, {2, 0x02e80}, {0, 0x0302a}, {2, 0x03030}, {1, 0x0303f}, - {2, 0x03040}, {0, 0x03099}, {2, 0x0309b}, {1, 0x0a4d0}, {0, 0x0a806}, - {1, 0x0a807}, {0, 0x0a80b}, {1, 0x0a80c}, {0, 0x0a825}, {1, 0x0a827}, - {2, 0x0ac00}, {1, 0x0d7a4}, {2, 0x0f900}, {1, 0x0fb00}, {0, 0x0fb1e}, - {1, 0x0fb1f}, {0, 0x0fe00}, {2, 0x0fe10}, {1, 0x0fe1a}, {0, 0x0fe20}, - {1, 0x0fe24}, {2, 0x0fe30}, {1, 0x0fe70}, {0, 0x0feff}, {2, 0x0ff00}, - {1, 0x0ff61}, {2, 0x0ffe0}, {1, 0x0ffe7}, {0, 0x0fff9}, {1, 0x0fffc}, - {0, 0x10a01}, {1, 0x10a04}, {0, 0x10a05}, {1, 0x10a07}, {0, 0x10a0c}, - {1, 0x10a10}, {0, 0x10a38}, {1, 0x10a3b}, {0, 0x10a3f}, {1, 0x10a40}, - {0, 0x1d167}, {1, 0x1d16a}, {0, 0x1d173}, {1, 0x1d183}, {0, 0x1d185}, - {1, 0x1d18c}, {0, 0x1d1aa}, {1, 0x1d1ae}, {0, 0x1d242}, {1, 0x1d245}, - {2, 0x20000}, {1, 0x2fffe}, {2, 0x30000}, {1, 0x3fffe}, {0, 0xe0001}, - {1, 0xe0002}, {0, 0xe0020}, {1, 0xe0080}, {0, 0xe0100}, {1, 0xe01f0} -}; - -/* -** Return an estimate of the width, in columns, for the single Unicode -** character c. For normal characters, the answer is always 1. But the -** estimate might be 0 or 2 for zero-width and double-width characters. -** -** Different display devices display unicode using different widths. So -** it is impossible to know that true display width with 100% accuracy. -** Inaccuracies in the width estimates might cause columns to be misaligned. -** Unfortunately, there is nothing we can do about that. -*/ -int sqlite3_qrf_wcwidth(int c){ - int iFirst, iLast; - - /* Fast path for common characters */ - if( c<0x300 ) return 1; - - /* The general case */ - iFirst = 0; - iLast = sizeof(aQrfUWidth)/sizeof(aQrfUWidth[0]) - 1; - while( iFirst c ){ - iLast = iMid - 1; - }else{ - return aQrfUWidth[iMid].w; - } - } - if( aQrfUWidth[iLast].iFirst > c ) return aQrfUWidth[iFirst].w; - return aQrfUWidth[iLast].w; -} - -/* -** Compute the value and length of a multi-byte UTF-8 character that -** begins at z[0]. Return the length. Write the Unicode value into *pU. -** -** This routine only works for *multi-byte* UTF-8 characters. It does -** not attempt to detect illegal characters. -*/ -int sqlite3_qrf_decode_utf8(const unsigned char *z, int *pU){ - if( (z[0] & 0xe0)==0xc0 && (z[1] & 0xc0)==0x80 ){ - *pU = ((z[0] & 0x1f)<<6) | (z[1] & 0x3f); - return 2; - } - if( (z[0] & 0xf0)==0xe0 && (z[1] & 0xc0)==0x80 && (z[2] & 0xc0)==0x80 ){ - *pU = ((z[0] & 0x0f)<<12) | ((z[1] & 0x3f)<<6) | (z[2] & 0x3f); - return 3; - } - if( (z[0] & 0xf8)==0xf0 && (z[1] & 0xc0)==0x80 && (z[2] & 0xc0)==0x80 - && (z[3] & 0xc0)==0x80 - ){ - *pU = ((z[0] & 0x0f)<<18) | ((z[1] & 0x3f)<<12) | ((z[2] & 0x3f))<<6 - | (z[3] & 0x3f); - return 4; - } - *pU = 0; - return 1; -} - -/* -** Check to see if z[] is a valid VT100 escape. If it is, then -** return the number of bytes in the escape sequence. Return 0 if -** z[] is not a VT100 escape. -** -** This routine assumes that z[0] is \033 (ESC). -*/ -static int qrfIsVt100(const unsigned char *z){ - int i; - if( z[1]!='[' ) return 0; - i = 2; - while( z[i]>=0x30 && z[i]<=0x3f ){ i++; } - while( z[i]>=0x20 && z[i]<=0x2f ){ i++; } - if( z[i]<0x40 || z[i]>0x7e ) return 0; - return i+1; -} - -/* -** Return the length of a string in display characters. -** -** Most characters of the input string count as 1, including -** multi-byte UTF8 characters. However, zero-width unicode -** characters and VT100 escape sequences count as zero, and -** double-width characters count as two. -** -** The definition of "zero-width" and "double-width" characters -** is not precise. It depends on the output device, to some extent, -** and it varies according to the Unicode version. This routine -** makes the best guess that it can. -*/ -size_t sqlite3_qrf_wcswidth(const char *zIn){ - const unsigned char *z = (const unsigned char*)zIn; - size_t n = 0; - while( *z ){ - if( z[0]<' ' ){ - int k; - if( z[0]=='\033' && (k = qrfIsVt100(z))>0 ){ - z += k; - }else{ - z++; - } - }else if( (0x80&z[0])==0 ){ - n++; - z++; - }else{ - int u = 0; - int len = sqlite3_qrf_decode_utf8(z, &u); - z += len; - n += sqlite3_qrf_wcwidth(u); - } - } - return n; -} - -/* -** Return the display width of the longest line of text -** in the (possibly) multi-line input string zIn[0..nByte]. -** zIn[] is not necessarily zero-terminated. Take -** into account tab characters, zero- and double-width -** characters, CR and NL, and VT100 escape codes. -** -** Write the number of newlines into *pnNL. So, *pnNL will -** return 0 if everything fits on one line, or positive it -** it will need to be split. -*/ -static int qrfDisplayWidth(const char *zIn, sqlite3_int64 nByte, int *pnNL){ - const unsigned char *z; - const unsigned char *zEnd; - int mx = 0; - int n = 0; - int nNL = 0; - if( zIn==0 ) zIn = ""; - z = (const unsigned char*)zIn; - zEnd = &z[nByte]; - while( z0 ){ - z += k; - }else{ - if( z[0]=='\t' ){ - n = (n+8)&~7; - }else if( z[0]=='\n' || z[0]=='\r' ){ - nNL++; - if( n>mx ) mx = n; - n = 0; - } - z++; - } - }else if( (0x80&z[0])==0 ){ - n++; - z++; - }else{ - int u = 0; - int len = sqlite3_qrf_decode_utf8(z, &u); - z += len; - n += sqlite3_qrf_wcwidth(u); - } - } - if( mx>n ) n = mx; - if( pnNL ) *pnNL = nNL; - return n; -} - -/* -** Escape the input string if it is needed and in accordance with -** eEsc, which is either QRF_ESC_Ascii or QRF_ESC_Symbol. -** -** Escaping is needed if the string contains any control characters -** other than \t, \n, and \r\n -** -** If no escaping is needed (the common case) then set *ppOut to NULL -** and return 0. If escaping is needed, write the escaped string into -** memory obtained from sqlite3_malloc64() and make *ppOut point to that -** memory and return 0. If an error occurs, return non-zero. -** -** The caller is responsible for freeing *ppFree if it is non-NULL in order -** to reclaim memory. -*/ -static void qrfEscape( - int eEsc, /* QRF_ESC_Ascii or QRF_ESC_Symbol */ - sqlite3_str *pStr, /* String to be escaped */ - int iStart /* Begin escapding on this byte of pStr */ -){ - sqlite3_int64 i, j; /* Loop counters */ - sqlite3_int64 sz; /* Size of the string prior to escaping */ - sqlite3_int64 nCtrl = 0;/* Number of control characters to escape */ - unsigned char *zIn; /* Text to be escaped */ - unsigned char c; /* A single character of the text */ - unsigned char *zOut; /* Where to write the results */ - - /* Find the text to be escaped */ - zIn = (unsigned char*)sqlite3_str_value(pStr); - if( zIn==0 ) return; - zIn += iStart; - - /* Count the control characters */ - for(i=0; (c = zIn[i])!=0; i++){ - if( c<=0x1f - && c!='\t' - && c!='\n' - && (c!='\r' || zIn[i+1]!='\n') - ){ - nCtrl++; - } - } - if( nCtrl==0 ) return; /* Early out if no control characters */ - - /* Make space to hold the escapes. Copy the original text to the end - ** of the available space. */ - sz = sqlite3_str_length(pStr) - iStart; - if( eEsc==QRF_ESC_Symbol ) nCtrl *= 2; - sqlite3_str_appendchar(pStr, nCtrl, ' '); - zOut = (unsigned char*)sqlite3_str_value(pStr); - if( zOut==0 ) return; - zOut += iStart; - zIn = zOut + nCtrl; - memmove(zIn,zOut,sz); - - /* Convert the control characters */ - for(i=j=0; (c = zIn[i])!=0; i++){ - if( c>0x1f - || c=='\t' - || c=='\n' - || (c=='\r' && zIn[i+1]=='\n') - ){ - continue; - } - if( i>0 ){ - memmove(&zOut[j], zIn, i); - j += i; - } - zIn += i+1; - i = -1; - if( eEsc==QRF_ESC_Symbol ){ - zOut[j++] = 0xe2; - zOut[j++] = 0x90; - zOut[j++] = 0x80+c; - }else{ - zOut[j++] = '^'; - zOut[j++] = 0x40+c; - } - } -} - -/* -** Determine if the string z[] can be shown as plain text. Return true -** if z[] is unambiguously text. Return false if z[] needs to be -** quoted. -** -** All of the following must be true in order for z[] to be relaxable: -** -** (1) z[] does not begin or end with ' or whitespace -** (2) z[] is not the same as the NULL rendering -** (3) z[] does not looks like a numeric literal -*/ -static int qrfRelaxable(Qrf *p, const char *z){ - size_t i, n; - if( z[0]=='\'' || qrfSpace(z[0]) ) return 0; - if( z[0]==0 ){ - return (p->spec.zNull!=0 && p->spec.zNull[0]!=0); - } - n = strlen(z); - if( n==0 || z[n-1]=='\'' || qrfSpace(z[n-1]) ) return 0; - if( p->spec.zNull && strcmp(p->spec.zNull,z)==0 ) return 0; - i = (z[0]=='-' || z[0]=='+'); - if( strcmp(z+i,"Inf")==0 ) return 0; - if( !qrfDigit(z[i]) ) return 1; - i++; - while( qrfDigit(z[i]) ){ i++; } - if( z[i]==0 ) return 0; - if( z[i]=='.' ){ - i++; - while( qrfDigit(z[i]) ){ i++; } - if( z[i]==0 ) return 0; - } - if( z[i]=='e' || z[i]=='E' ){ - i++; - if( z[i]=='+' || z[i]=='-' ){ i++; } - if( !qrfDigit(z[i]) ) return 1; - i++; - while( qrfDigit(z[i]) ){ i++; } - } - return z[i]!=0; -} - -/* -** If a field contains any character identified by a 1 in the following -** array, then the string must be quoted for CSV. -*/ -static const char qrfCsvQuote[] = { - 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, 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, 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, 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, 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, -}; - -/* -** Encode text appropriately and append it to pOut. -*/ -static void qrfEncodeText(Qrf *p, sqlite3_str *pOut, const char *zTxt){ - int iStart = sqlite3_str_length(pOut); - switch( p->spec.eText ){ - case QRF_TEXT_Relaxed: - if( qrfRelaxable(p, zTxt) ){ - sqlite3_str_appendall(pOut, zTxt); - break; - } - deliberate_fall_through; /* FALLTHRU */ - case QRF_TEXT_Sql: { - if( p->spec.eEsc==QRF_ESC_Off ){ - sqlite3_str_appendf(pOut, "%Q", zTxt); - }else{ - sqlite3_str_appendf(pOut, "%#Q", zTxt); - } - break; - } - case QRF_TEXT_Csv: { - unsigned int i; - for(i=0; zTxt[i]; i++){ - if( qrfCsvQuote[((const unsigned char*)zTxt)[i]] ){ - i = 0; - break; - } - } - if( i==0 || strstr(zTxt, p->spec.zColumnSep)!=0 ){ - sqlite3_str_appendf(pOut, "\"%w\"", zTxt); - }else{ - sqlite3_str_appendall(pOut, zTxt); - } - break; - } - case QRF_TEXT_Html: { - const unsigned char *z = (const unsigned char*)zTxt; - while( *z ){ - unsigned int i = 0; - unsigned char c; - while( (c=z[i])>'>' - || (c && c!='<' && c!='>' && c!='&' && c!='\"' && c!='\'') - ){ - i++; - } - if( i>0 ){ - sqlite3_str_append(pOut, (const char*)z, i); - } - switch( z[i] ){ - case '>': sqlite3_str_append(pOut, "<", 4); break; - case '&': sqlite3_str_append(pOut, "&", 5); break; - case '<': sqlite3_str_append(pOut, "<", 4); break; - case '"': sqlite3_str_append(pOut, """, 6); break; - case '\'': sqlite3_str_append(pOut, "'", 5); break; - default: i--; - } - z += i + 1; - } - break; - } - case QRF_TEXT_Tcl: - case QRF_TEXT_Json: { - const unsigned char *z = (const unsigned char*)zTxt; - sqlite3_str_append(pOut, "\"", 1); - while( *z ){ - unsigned int i; - for(i=0; z[i]>=0x20 && z[i]!='\\' && z[i]!='"'; i++){} - if( i>0 ){ - sqlite3_str_append(pOut, (const char*)z, i); - } - if( z[i]==0 ) break; - switch( z[i] ){ - case '"': sqlite3_str_append(pOut, "\\\"", 2); break; - case '\\': sqlite3_str_append(pOut, "\\\\", 2); break; - case '\b': sqlite3_str_append(pOut, "\\b", 2); break; - case '\f': sqlite3_str_append(pOut, "\\f", 2); break; - case '\n': sqlite3_str_append(pOut, "\\n", 2); break; - case '\r': sqlite3_str_append(pOut, "\\r", 2); break; - case '\t': sqlite3_str_append(pOut, "\\t", 2); break; - default: { - if( p->spec.eText==QRF_TEXT_Json ){ - sqlite3_str_appendf(pOut, "\\u%04x", z[i]); - }else{ - sqlite3_str_appendf(pOut, "\\%03o", z[i]); - } - break; - } - } - z += i + 1; - } - sqlite3_str_append(pOut, "\"", 1); - break; - } - default: { - sqlite3_str_appendall(pOut, zTxt); - break; - } - } - if( p->spec.eEsc!=QRF_ESC_Off ){ - qrfEscape(p->spec.eEsc, pOut, iStart); - } -} - -/* -** Do a quick sanity check to see aBlob[0..nBlob-1] is valid JSONB -** return true if it is and false if it is not. -** -** False positives are possible, but not false negatives. -*/ -static int qrfJsonbQuickCheck(unsigned char *aBlob, int nBlob){ - unsigned char x; /* Payload size half-byte */ - int i; /* Loop counter */ - int n; /* Bytes in the payload size integer */ - sqlite3_uint64 sz; /* value of the payload size integer */ - - if( nBlob==0 ) return 0; - x = aBlob[0]>>4; - if( x<=11 ) return nBlob==(1+x); - n = x<14 ? x-11 : 4*(x-13); - if( nBlob<1+n ) return 0; - sz = aBlob[1]; - for(i=1; ipStmt is known to be a BLOB. Check -** to see if that BLOB is really a JSONB blob. If it is, then translate -** it into a text JSON representation and return a pointer to that text JSON. -** If the BLOB is not JSONB, then return a NULL pointer. -** -** The memory used to hold the JSON text is managed internally by the -** "p" object and is overwritten and/or deallocated upon the next call -** to this routine (with the same p argument) or when the p object is -** finailized. -*/ -static const char *qrfJsonbToJson(Qrf *p, int iCol){ - int nByte; - const void *pBlob; - int rc; - nByte = sqlite3_column_bytes(p->pStmt, iCol); - pBlob = sqlite3_column_blob(p->pStmt, iCol); - if( qrfJsonbQuickCheck((unsigned char*)pBlob, nByte)==0 ){ - return 0; - } - if( p->pJTrans==0 ){ - sqlite3 *db; - rc = sqlite3_open(":memory:",&db); - if( rc ){ - sqlite3_close(db); - return 0; - } - rc = sqlite3_prepare_v2(db, "SELECT json(?1)", -1, &p->pJTrans, 0); - if( rc ){ - sqlite3_finalize(p->pJTrans); - p->pJTrans = 0; - sqlite3_close(db); - return 0; - } - }else{ - sqlite3_reset(p->pJTrans); - } - sqlite3_bind_blob(p->pJTrans, 1, (void*)pBlob, nByte, SQLITE_STATIC); - rc = sqlite3_step(p->pJTrans); - if( rc==SQLITE_ROW ){ - return (const char*)sqlite3_column_text(p->pJTrans, 0); - }else{ - return 0; - } -} - -/* -** Adjust the input string zIn[] such that it is no more than N display -** characters wide. If it is wider than that, then truncate and add -** ellipsis. Or if zIn[] contains a \r or \n, truncate at that point, -** adding ellipsis. Embedded tabs in zIn[] are converted into ordinary -** spaces. -** -** Return this display width of the modified title string. -*/ -static int qrfTitleLimit(char *zIn, int N){ - unsigned char *z = (unsigned char*)zIn; - int n = 0; - unsigned char *zEllipsis = 0; - while( 1 /*exit-by-break*/ ){ - if( z[0]<' ' ){ - int k; - if( z[0]==0 ){ - zEllipsis = 0; - break; - }else if( z[0]=='\033' && (k = qrfIsVt100(z))>0 ){ - z += k; - }else if( z[0]=='\t' ){ - z[0] = ' '; - }else if( z[0]=='\n' || z[0]=='\r' ){ - z[0] = ' '; - }else{ - z++; - } - }else if( (0x80&z[0])==0 ){ - if( n>=(N-3) && zEllipsis==0 ) zEllipsis = z; - if( n==N ){ z[0] = 0; break; } - n++; - z++; - }else{ - int u = 0; - int len = sqlite3_qrf_decode_utf8(z, &u); - if( n+len>(N-3) && zEllipsis==0 ) zEllipsis = z; - if( n+len>N ){ z[0] = 0; break; } - z += len; - n += sqlite3_qrf_wcwidth(u); - } - } - if( zEllipsis && N>=3 ) memcpy(zEllipsis,"...",4); - return n; -} - - -/* -** Render value pVal into pOut -*/ -static void qrfRenderValue(Qrf *p, sqlite3_str *pOut, int iCol){ -#if SQLITE_VERSION_NUMBER>=3052000 - int iStartLen = sqlite3_str_length(pOut); -#endif - if( p->spec.xRender ){ - sqlite3_value *pVal; - char *z; - pVal = sqlite3_value_dup(sqlite3_column_value(p->pStmt,iCol)); - z = p->spec.xRender(p->spec.pRenderArg, pVal); - sqlite3_value_free(pVal); - if( z ){ - sqlite3_str_appendall(pOut, z); - sqlite3_free(z); - return; - } - } - switch( sqlite3_column_type(p->pStmt,iCol) ){ - case SQLITE_INTEGER: { - sqlite3_str_appendf(pOut, "%lld", sqlite3_column_int64(p->pStmt,iCol)); - break; - } - case SQLITE_FLOAT: { - const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol); - sqlite3_str_appendall(pOut, zTxt); - break; - } - case SQLITE_BLOB: { - if( p->spec.bTextJsonb==QRF_Yes ){ - const char *zJson = qrfJsonbToJson(p, iCol); - if( zJson ){ - if( p->spec.eText==QRF_TEXT_Sql ){ - sqlite3_str_append(pOut,"jsonb(",6); - qrfEncodeText(p, pOut, zJson); - sqlite3_str_append(pOut,")",1); - }else{ - qrfEncodeText(p, pOut, zJson); - } - break; - } - } - switch( p->spec.eBlob ){ - case QRF_BLOB_Hex: - case QRF_BLOB_Sql: { - int iStart; - int nBlob = sqlite3_column_bytes(p->pStmt,iCol); - int i, j; - char *zVal; - const unsigned char *a = sqlite3_column_blob(p->pStmt,iCol); - if( p->spec.eBlob==QRF_BLOB_Sql ){ - sqlite3_str_append(pOut, "x'", 2); - } - iStart = sqlite3_str_length(pOut); - sqlite3_str_appendchar(pOut, nBlob, ' '); - sqlite3_str_appendchar(pOut, nBlob, ' '); - if( p->spec.eBlob==QRF_BLOB_Sql ){ - sqlite3_str_appendchar(pOut, 1, '\''); - } - if( sqlite3_str_errcode(pOut) ) return; - zVal = sqlite3_str_value(pOut); - for(i=0, j=iStart; i>4)&0xf]; - zVal[j+1] = "0123456789abcdef"[(c)&0xf]; - } - break; - } - case QRF_BLOB_Tcl: - case QRF_BLOB_Json: { - int iStart; - int nBlob = sqlite3_column_bytes(p->pStmt,iCol); - int i, j; - char *zVal; - const unsigned char *a = sqlite3_column_blob(p->pStmt,iCol); - int szC = p->spec.eBlob==QRF_BLOB_Json ? 6 : 4; - sqlite3_str_append(pOut, "\"", 1); - iStart = sqlite3_str_length(pOut); - for(i=szC; i>0; i--){ - sqlite3_str_appendchar(pOut, nBlob, ' '); - } - sqlite3_str_appendchar(pOut, 1, '"'); - if( sqlite3_str_errcode(pOut) ) return; - zVal = sqlite3_str_value(pOut); - for(i=0, j=iStart; i>6)&3); - zVal[j+2] = '0' + ((c>>3)&7); - zVal[j+3] = '0' + (c&7); - }else{ - zVal[j+1] = 'u'; - zVal[j+2] = '0'; - zVal[j+3] = '0'; - zVal[j+4] = "0123456789abcdef"[(c>>4)&0xf]; - zVal[j+5] = "0123456789abcdef"[(c)&0xf]; - } - } - break; - } - case QRF_BLOB_Size: { - int nBlob = sqlite3_column_bytes(p->pStmt,iCol); - sqlite3_str_appendf(pOut, "(%d-byte blob)", nBlob); - break; - } - default: { - const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol); - qrfEncodeText(p, pOut, zTxt); - } - } - break; - } - case SQLITE_NULL: { - sqlite3_str_appendall(pOut, p->spec.zNull); - break; - } - case SQLITE_TEXT: { - const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol); - qrfEncodeText(p, pOut, zTxt); - break; - } - } -#if SQLITE_VERSION_NUMBER>=3052000 - if( p->spec.nCharLimit>0 - && (sqlite3_str_length(pOut) - iStartLen) > p->spec.nCharLimit - ){ - const unsigned char *z; - int ii = 0, w = 0, limit = p->spec.nCharLimit; - z = (const unsigned char*)sqlite3_str_value(pOut) + iStartLen; - if( limit<4 ) limit = 4; - while( 1 ){ - if( z[ii]<' ' ){ - int k; - if( z[ii]=='\033' && (k = qrfIsVt100(z+ii))>0 ){ - ii += k; - }else if( z[ii]==0 ){ - break; - }else{ - ii++; - } - }else if( (0x80&z[ii])==0 ){ - w++; - if( w>limit ) break; - ii++; - }else{ - int u = 0; - int len = sqlite3_qrf_decode_utf8(&z[ii], &u); - w += sqlite3_qrf_wcwidth(u); - if( w>limit ) break; - ii += len; - } - } - if( w>limit ){ - sqlite3_str_truncate(pOut, iStartLen+ii); - sqlite3_str_append(pOut, "...", 3); - } - } -#endif -} - -/* Trim spaces of the end if pOut -*/ -static void qrfRTrim(sqlite3_str *pOut){ -#if SQLITE_VERSION_NUMBER>=3052000 - int nByte = sqlite3_str_length(pOut); - const char *zOut = sqlite3_str_value(pOut); - while( nByte>0 && zOut[nByte-1]==' ' ){ nByte--; } - sqlite3_str_truncate(pOut, nByte); -#endif -} - -/* -** Store string zUtf to pOut as w characters. If w is negative, -** then right-justify the text. W is the width in display characters, not -** in bytes. Double-width unicode characters count as two characters. -** VT100 escape sequences count as zero. And so forth. -*/ -static void qrfWidthPrint(Qrf *p, sqlite3_str *pOut, int w, const char *zUtf){ - const unsigned char *a = (const unsigned char*)zUtf; - static const int mxW = 10000000; - unsigned char c; - int i = 0; - int n = 0; - int k; - int aw; - (void)p; - if( w<-mxW ){ - w = -mxW; - }else if( w>mxW ){ - w= mxW; - } - aw = w<0 ? -w : w; - if( a==0 ) a = (const unsigned char*)""; - while( (c = a[i])!=0 ){ - if( (c&0xc0)==0xc0 ){ - int u; - int len = sqlite3_qrf_decode_utf8(a+i, &u); - int x = sqlite3_qrf_wcwidth(u); - if( x+n>aw ){ - break; - } - i += len; - n += x; - }else if( c==0x1b && (k = qrfIsVt100(&a[i]))>0 ){ - i += k; - }else if( n>=aw ){ - break; - }else{ - n++; - i++; - } - } - if( n>=aw ){ - sqlite3_str_append(pOut, zUtf, i); - }else if( w<0 ){ - if( aw>n ) sqlite3_str_appendchar(pOut, aw-n, ' '); - sqlite3_str_append(pOut, zUtf, i); - }else{ - sqlite3_str_append(pOut, zUtf, i); - if( aw>n ) sqlite3_str_appendchar(pOut, aw-n, ' '); - } -} - -/* -** (*pz)[] is a line of text that is to be displayed the box or table or -** similar tabular formats. z[] contain newlines or might be too wide -** to fit in the columns so will need to be split into multiple line. -** -** This routine determines: -** -** * How many bytes of z[] should be shown on the current line. -** * How many character positions those bytes will cover. -** * The byte offset to the start of the next line. -*/ -static void qrfWrapLine( - const char *zIn, /* Input text to be displayed */ - int w, /* Column width in characters (not bytes) */ - int bWrap, /* True if we should do word-wrapping */ - int *pnThis, /* OUT: How many bytes of z[] for the current line */ - int *pnWide, /* OUT: How wide is the text of this line */ - int *piNext /* OUT: Offset into z[] to start of the next line */ -){ - int i; /* Input bytes consumed */ - int k; /* Bytes in a VT100 code */ - int n; /* Output column number */ - const unsigned char *z = (const unsigned char*)zIn; - unsigned char c = 0; - - if( z[0]==0 ){ - *pnThis = 0; - *pnWide = 0; - *piNext = 0; - return; - } - n = 0; - for(i=0; n<=w; i++){ - c = z[i]; - if( c>=0xc0 ){ - int u; - int len = sqlite3_qrf_decode_utf8(&z[i], &u); - int wcw = sqlite3_qrf_wcwidth(u); - if( wcw+n>w ) break; - i += len-1; - n += wcw; - continue; - } - if( c>=' ' ){ - if( n==w ) break; - n++; - continue; - } - if( c==0 || c=='\n' ) break; - if( c=='\r' && z[i+1]=='\n' ){ c = z[++i]; break; } - if( c=='\t' ){ - int wcw = 8 - (n&7); - if( n+wcw>w ) break; - n += wcw; - continue; - } - if( c==0x1b && (k = qrfIsVt100(&z[i]))>0 ){ - i += k-1; - }else if( n==w ){ - break; - }else{ - n++; - } - } - if( c==0 ){ - *pnThis = i; - *pnWide = n; - *piNext = i; - return; - } - if( c=='\n' ){ - *pnThis = i; - *pnWide = n; - *piNext = i+1; - return; - } - - /* If we get this far, that means the current line will end at some - ** point that is neither a "\n" or a 0x00. Figure out where that - ** split should occur - */ - if( bWrap && z[i]!=0 && !qrfSpace(z[i]) && qrfAlnum(c)==qrfAlnum(z[i]) ){ - /* Perhaps try to back up to a better place to break the line */ - for(k=i-1; k>=i/2; k--){ - if( qrfSpace(z[k]) ) break; - } - if( k=i/2; k--){ - if( qrfAlnum(z[k-1])!=qrfAlnum(z[k]) && (z[k]&0xc0)!=0x80 ) break; - } - } - if( k>=i/2 ){ - i = k; - n = qrfDisplayWidth((const char*)z, k, 0); - } - } - *pnThis = i; - *pnWide = n; - while( zIn[i]==' ' || zIn[i]=='\t' || zIn[i]=='\r' ){ i++; } - *piNext = i; -} - -/* -** Append nVal bytes of text from zVal onto the end of pOut. -** Convert tab characters in zVal to the appropriate number of -** spaces. -*/ -static void qrfAppendWithTabs( - sqlite3_str *pOut, /* Append text here */ - const char *zVal, /* Text to append */ - int nVal /* Use only the first nVal bytes of zVal[] */ -){ - int i = 0; - unsigned int col = 0; - unsigned char *z = (unsigned char *)zVal; - while( i0 ){ - sqlite3_str_append(pOut, (const char*)z, k); - z += k; - nVal -= k; - }else if( c=='\t' ){ - k = 8 - (col&7); - sqlite3_str_appendchar(pOut, k, ' '); - col += k; - z++; - nVal--; - }else if( c=='\r' && nVal==1 ){ - z++; - nVal--; - }else{ - char zCtrlPik[4]; - col++; - zCtrlPik[0] = 0xe2; - zCtrlPik[1] = 0x90; - zCtrlPik[2] = 0x80+c; - sqlite3_str_append(pOut, zCtrlPik, 3); - z++; - nVal--; - } - }else if( (0x80&c)==0 ){ - i++; - col++; - }else{ - int u = 0; - int len = sqlite3_qrf_decode_utf8(&z[i], &u); - i += len; - col += sqlite3_qrf_wcwidth(u); - } - } - sqlite3_str_append(pOut, (const char*)z, i); -} - -/* -** GCC does not define the offsetof() macro so we'll have to do it -** ourselves. -*/ -#ifndef offsetof -# define offsetof(ST,M) ((size_t)((char*)&((ST*)0)->M - (char*)0)) -#endif - -/* -** Data for columnar layout, collected into a single object so -** that it can be more easily passed into subroutines. -*/ -typedef struct qrfColData qrfColData; -struct qrfColData { - Qrf *p; /* The QRF instance */ - int nCol; /* Number of columns in the table */ - unsigned char bMultiRow; /* One or more cells will span multiple lines */ - unsigned char nMargin; /* Width of column margins */ - sqlite3_int64 nRow; /* Number of rows */ - sqlite3_int64 nAlloc; /* Number of cells allocated */ - sqlite3_int64 n; /* Number of cells. nCol*nRow */ - char **az; /* Content of all cells */ - int *aiWth; /* Width of each cell */ - unsigned char *abNum; /* True for each numeric cell */ - struct qrfPerCol { /* Per-column data */ - char *z; /* Cache of text for current row */ - int w; /* Computed width of this column */ - int mxW; /* Maximum natural (unwrapped) width */ - unsigned char e; /* Alignment */ - unsigned char fx; /* Width is fixed */ - unsigned char bNum; /* True if is numeric */ - } *a; /* One per column */ -}; - -/* -** Output horizontally justified text into pOut. The text is the -** first nVal bytes of zVal. Include nWS bytes of whitespace, either -** split between both sides, or on the left, or on the right, depending -** on eAlign. -*/ -static void qrfPrintAligned( - sqlite3_str *pOut, /* Append text here */ - struct qrfPerCol *pCol, /* Information about the text to print */ - int nVal, /* Use only the first nVal bytes of zVal[] */ - int nWS /* Whitespace for horizonal alignment */ -){ - unsigned char eAlign = pCol->e & QRF_ALIGN_HMASK; - if( eAlign==QRF_Auto && pCol->bNum ) eAlign = QRF_ALIGN_Right; - if( eAlign==QRF_ALIGN_Center ){ - /* Center the text */ - sqlite3_str_appendchar(pOut, nWS/2, ' '); - qrfAppendWithTabs(pOut, pCol->z, nVal); - sqlite3_str_appendchar(pOut, nWS - nWS/2, ' '); - }else if( eAlign==QRF_ALIGN_Right ){ - /* Right justify the text */ - sqlite3_str_appendchar(pOut, nWS, ' '); - qrfAppendWithTabs(pOut, pCol->z, nVal); - }else{ - /* Left justify the text */ - qrfAppendWithTabs(pOut, pCol->z, nVal); - sqlite3_str_appendchar(pOut, nWS, ' '); - } -} - -/* -** Free all the memory allocates in the qrfColData object -*/ -static void qrfColDataFree(qrfColData *p){ - sqlite3_int64 i; - for(i=0; in; i++) sqlite3_free(p->az[i]); - sqlite3_free(p->az); - sqlite3_free(p->aiWth); - sqlite3_free(p->abNum); - sqlite3_free(p->a); - memset(p, 0, sizeof(*p)); -} - -/* -** Allocate space for more cells in the qrfColData object. -** Return non-zero if a memory allocation fails. -*/ -static int qrfColDataEnlarge(qrfColData *p){ - char **azData; - int *aiWth; - unsigned char *abNum; - p->nAlloc = 2*p->nAlloc + 10*p->nCol; - azData = sqlite3_realloc64(p->az, p->nAlloc*sizeof(char*)); - if( azData==0 ){ - qrfOom(p->p); - qrfColDataFree(p); - return 1; - } - p->az = azData; - aiWth = sqlite3_realloc64(p->aiWth, p->nAlloc*sizeof(int)); - if( aiWth==0 ){ - qrfOom(p->p); - qrfColDataFree(p); - return 1; - } - p->aiWth = aiWth; - abNum = sqlite3_realloc64(p->abNum, p->nAlloc); - if( abNum==0 ){ - qrfOom(p->p); - qrfColDataFree(p); - return 1; - } - p->abNum = abNum; - return 0; -} - -/* -** Print a markdown or table-style row separator using ascii-art -*/ -static void qrfRowSeparator(sqlite3_str *pOut, qrfColData *p, char cSep){ - int i; - if( p->nCol>0 ){ - int useBorder = p->p->spec.bBorder!=QRF_No; - if( useBorder ){ - sqlite3_str_append(pOut, &cSep, 1); - } - sqlite3_str_appendchar(pOut, p->a[0].w+p->nMargin, '-'); - for(i=1; inCol; i++){ - sqlite3_str_append(pOut, &cSep, 1); - sqlite3_str_appendchar(pOut, p->a[i].w+p->nMargin, '-'); - } - if( useBorder ){ - sqlite3_str_append(pOut, &cSep, 1); - } - } - sqlite3_str_append(pOut, "\n", 1); -} - -/* -** UTF8 box-drawing characters. Imagine box lines like this: -** -** 1 -** | -** 4 --+-- 2 -** | -** 3 -** -** Each box characters has between 2 and 4 of the lines leading from -** the center. The characters are here identified by the numbers of -** their corresponding lines. -*/ -#define BOX_24 "\342\224\200" /* U+2500 --- */ -#define BOX_13 "\342\224\202" /* U+2502 | */ -#define BOX_23 "\342\224\214" /* U+250c ,- */ -#define BOX_34 "\342\224\220" /* U+2510 -, */ -#define BOX_12 "\342\224\224" /* U+2514 '- */ -#define BOX_14 "\342\224\230" /* U+2518 -' */ -#define BOX_123 "\342\224\234" /* U+251c |- */ -#define BOX_134 "\342\224\244" /* U+2524 -| */ -#define BOX_234 "\342\224\254" /* U+252c -,- */ -#define BOX_124 "\342\224\264" /* U+2534 -'- */ -#define BOX_1234 "\342\224\274" /* U+253c -|- */ - -/* Rounded corners: */ -#define BOX_R12 "\342\225\260" /* U+2570 '- */ -#define BOX_R23 "\342\225\255" /* U+256d ,- */ -#define BOX_R34 "\342\225\256" /* U+256e -, */ -#define BOX_R14 "\342\225\257" /* U+256f -' */ - -/* Doubled horizontal lines: */ -#define DBL_24 "\342\225\220" /* U+2550 === */ -#define DBL_123 "\342\225\236" /* U+255e |= */ -#define DBL_134 "\342\225\241" /* U+2561 =| */ -#define DBL_1234 "\342\225\252" /* U+256a =|= */ - -/* Draw horizontal line N characters long using unicode box -** characters -*/ -static void qrfBoxLine(sqlite3_str *pOut, int N, int bDbl){ - const char *azDash[2] = { - BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24, - DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 - };/* 0 1 2 3 4 5 6 7 8 9 */ - const int nDash = 30; - N *= 3; - while( N>nDash ){ - sqlite3_str_append(pOut, azDash[bDbl], nDash); - N -= nDash; - } - sqlite3_str_append(pOut, azDash[bDbl], N); -} - -/* -** Draw a horizontal separator for a QRF_STYLE_Box table. -*/ -static void qrfBoxSeparator( - sqlite3_str *pOut, - qrfColData *p, - const char *zSep1, - const char *zSep2, - const char *zSep3, - int bDbl -){ - int i; - if( p->nCol>0 ){ - int useBorder = p->p->spec.bBorder!=QRF_No; - if( useBorder ){ - sqlite3_str_appendall(pOut, zSep1); - } - qrfBoxLine(pOut, p->a[0].w+p->nMargin, bDbl); - for(i=1; inCol; i++){ - sqlite3_str_appendall(pOut, zSep2); - qrfBoxLine(pOut, p->a[i].w+p->nMargin, bDbl); - } - if( useBorder ){ - sqlite3_str_appendall(pOut, zSep3); - } - } - sqlite3_str_append(pOut, "\n", 1); -} - -/* -** Load into pData the default alignment for the body of a table. -*/ -static void qrfLoadAlignment(qrfColData *pData, Qrf *p){ - sqlite3_int64 i; - for(i=0; inCol; i++){ - pData->a[i].e = p->spec.eDfltAlign; - if( ispec.nAlign ){ - unsigned char ax = p->spec.aAlign[i]; - if( (ax & QRF_ALIGN_HMASK)!=0 ){ - pData->a[i].e = (ax & QRF_ALIGN_HMASK) | - (pData->a[i].e & QRF_ALIGN_VMASK); - } - }else if( ispec.nWidth ){ - if( p->spec.aWidth[i]<0 ){ - pData->a[i].e = QRF_ALIGN_Right | - (pData->a[i].e & QRF_ALIGN_VMASK); - } - } - } -} - -/* -** If the single column in pData->a[] with pData->n entries can be -** laid out as nCol columns with a 2-space gap between each such -** that all columns fit within nSW, then return a pointer to an array -** of integers which is the width of each column from left to right. -** -** If the layout is not possible, return a NULL pointer. -** -** Space to hold the returned array is from sqlite_malloc64(). -*/ -static int *qrfValidLayout( - qrfColData *pData, /* Collected query results */ - Qrf *p, /* On which to report an OOM */ - int nCol, /* Attempt this many columns */ - int nSW /* Screen width */ -){ - int i; /* Loop counter */ - int nr; /* Number of rows */ - int w = 0; /* Width of the current column */ - int t; /* Total width of all columns */ - int *aw; /* Array of individual column widths */ - - aw = sqlite3_malloc64( sizeof(int)*nCol ); - if( aw==0 ){ - qrfOom(p); - return 0; - } - nr = (pData->n + nCol - 1)/nCol; - for(i=0; in; i++){ - if( (i%nr)==0 ){ - if( i>0 ) aw[i/nr-1] = w; - w = pData->aiWth[i]; - }else if( pData->aiWth[i]>w ){ - w = pData->aiWth[i]; - } - } - aw[nCol-1] = w; - for(t=i=0; inSW ){ - sqlite3_free(aw); - return 0; - } - return aw; -} - -/* -** The output is single-column and the bSplitColumn flag is set. -** Check to see if the single-column output can be split into multiple -** columns that appear side-by-side. Adjust pData appropriately. -*/ -static void qrfSplitColumn(qrfColData *pData, Qrf *p){ - int nCol = 1; - int *aw = 0; - char **az = 0; - int *aiWth = 0; - unsigned char *abNum = 0; - int nColNext = 2; - int w; - struct qrfPerCol *a = 0; - sqlite3_int64 nRow = 1; - sqlite3_int64 i; - while( 1/*exit-by-break*/ ){ - int *awNew = qrfValidLayout(pData, p, nColNext, p->spec.nScreenWidth); - if( awNew==0 ) break; - sqlite3_free(aw); - aw = awNew; - nCol = nColNext; - nRow = (pData->n + nCol - 1)/nCol; - if( nRow==1 ) break; - nColNext++; - while( (pData->n + nColNext - 1)/nColNext == nRow ) nColNext++; - } - if( nCol==1 ){ - sqlite3_free(aw); - return; /* Cannot do better than 1 column */ - } - az = sqlite3_malloc64( nRow*nCol*sizeof(char*) ); - if( az==0 ){ - qrfOom(p); - return; - } - aiWth = sqlite3_malloc64( nRow*nCol*sizeof(int) ); - if( aiWth==0 ){ - sqlite3_free(az); - qrfOom(p); - return; - } - a = sqlite3_malloc64( nCol*sizeof(struct qrfPerCol) ); - if( a==0 ){ - sqlite3_free(az); - sqlite3_free(aiWth); - qrfOom(p); - return; - } - abNum = sqlite3_malloc64( nRow*nCol ); - if( abNum==0 ){ - sqlite3_free(az); - sqlite3_free(aiWth); - sqlite3_free(a); - qrfOom(p); - return; - } - for(i=0; in; i++){ - sqlite3_int64 j = (i%nRow)*nCol + (i/nRow); - az[j] = pData->az[i]; - abNum[j]= pData->abNum[i]; - pData->az[i] = 0; - aiWth[j] = pData->aiWth[i]; - } - while( ia[0].e; - } - sqlite3_free(pData->az); - sqlite3_free(pData->aiWth); - sqlite3_free(pData->a); - sqlite3_free(pData->abNum); - sqlite3_free(aw); - pData->az = az; - pData->aiWth = aiWth; - pData->a = a; - pData->abNum = abNum; - pData->nCol = nCol; - pData->n = pData->nAlloc = nRow*nCol; - for(i=w=0; inMargin = (p->spec.nScreenWidth - w)/(nCol - 1); - if( pData->nMargin>5 ) pData->nMargin = 5; -} - -/* -** Adjust the layout for the screen width restriction -*/ -static void qrfRestrictScreenWidth(qrfColData *pData, Qrf *p){ - int sepW; /* Width of all box separators and margins */ - int sumW; /* Total width of data area over all columns */ - int targetW; /* Desired total data area */ - int i; /* Loop counters */ - int nCol; /* Number of columns */ - - pData->nMargin = 2; /* Default to normal margins */ - if( p->spec.nScreenWidth==0 ) return; - if( p->spec.eStyle==QRF_STYLE_Column ){ - sepW = pData->nCol*2 - 2; - }else{ - sepW = pData->nCol*3 + 1; - if( p->spec.bBorder==QRF_No ) sepW -= 2; - } - nCol = pData->nCol; - for(i=sumW=0; ia[i].w; - if( p->spec.nScreenWidth >= sumW+sepW ) return; - - /* First thing to do is reduce the separation between columns */ - pData->nMargin = 0; - if( p->spec.eStyle==QRF_STYLE_Column ){ - sepW = pData->nCol - 1; - }else{ - sepW = pData->nCol + 1; - if( p->spec.bBorder==QRF_No ) sepW -= 2; - } - targetW = p->spec.nScreenWidth - sepW; - -#define MIN_SQUOZE 8 -#define MIN_EX_SQUOZE 16 - /* Reduce the width of the widest eligible column. A column is - ** eligible for narrowing if: - ** - ** * It is not a fixed-width column (a[0].fx is false) - ** * The current width is more than MIN_SQUOZE - ** * Either: - ** + The current width is more then MIN_EX_SQUOZE, or - ** + The current width is more than half the max width (a[].mxW) - ** - ** Keep making reductions until either no more reductions are - ** possible or until the size target is reached. - */ - while( sumW > targetW ){ - int gain, w; - int ix = -1; - int mx = 0; - for(i=0; ia[i].fx==0 - && (w = pData->a[i].w)>mx - && w>MIN_SQUOZE - && (w>MIN_EX_SQUOZE || w*2>pData->a[i].mxW) - ){ - ix = i; - mx = w; - } - } - if( ix<0 ) break; - if( mx>=MIN_SQUOZE*2 ){ - gain = mx/2; - }else{ - gain = mx - MIN_SQUOZE; - } - if( sumW - gain < targetW ){ - gain = sumW - targetW; - } - sumW -= gain; - pData->a[ix].w -= gain; - pData->bMultiRow = 1; - } -} - -/* -** Columnar modes require that the entire query be evaluated first, with -** results written into memory, so that we can compute appropriate column -** widths. -*/ -static void qrfColumnar(Qrf *p){ - sqlite3_int64 i, j; /* Loop counters */ - const char *colSep = 0; /* Column separator text */ - const char *rowSep = 0; /* Row terminator text */ - const char *rowStart = 0; /* Row start text */ - int szColSep, szRowSep, szRowStart; /* Size in bytes of previous 3 */ - int rc; /* Result code */ - int nColumn = p->nCol; /* Number of columns */ - int bWW; /* True to do word-wrap */ - sqlite3_str *pStr; /* Temporary rendering */ - qrfColData data; /* Columnar layout data */ - int bRTrim; /* Trim trailing space */ - - rc = sqlite3_step(p->pStmt); - if( rc!=SQLITE_ROW || nColumn==0 ){ - return; /* No output */ - } - - /* Initialize the data container */ - memset(&data, 0, sizeof(data)); - data.nCol = p->nCol; - data.p = p; - data.a = sqlite3_malloc64( nColumn*sizeof(struct qrfPerCol) ); - if( data.a==0 ){ - qrfOom(p); - return; - } - memset(data.a, 0, nColumn*sizeof(struct qrfPerCol) ); - if( qrfColDataEnlarge(&data) ) return; - assert( data.az!=0 ); - - /* Load the column header names and all cell content into data */ - if( p->spec.bTitles==QRF_Yes ){ - unsigned char saved_eText = p->spec.eText; - p->spec.eText = p->spec.eTitle; - memset(data.abNum, 0, nColumn); - for(i=0; ipStmt,i); - int nNL = 0; - int n, w; - pStr = sqlite3_str_new(p->db); - qrfEncodeText(p, pStr, z ? z : ""); - n = sqlite3_str_length(pStr); - qrfStrErr(p, pStr); - z = data.az[data.n] = sqlite3_str_finish(pStr); - if( p->spec.nTitleLimit ){ - nNL = 0; - data.aiWth[data.n] = w = qrfTitleLimit(data.az[data.n], - p->spec.nTitleLimit ); - }else{ - data.aiWth[data.n] = w = qrfDisplayWidth(z, n, &nNL); - } - data.n++; - if( w>data.a[i].mxW ) data.a[i].mxW = w; - if( nNL ) data.bMultiRow = 1; - } - p->spec.eText = saved_eText; - p->nRow++; - } - do{ - if( data.n+nColumn > data.nAlloc ){ - if( qrfColDataEnlarge(&data) ) return; - } - for(i=0; ipStmt,i); - pStr = sqlite3_str_new(p->db); - qrfRenderValue(p, pStr, i); - n = sqlite3_str_length(pStr); - qrfStrErr(p, pStr); - z = data.az[data.n] = sqlite3_str_finish(pStr); - data.abNum[data.n] = eType==SQLITE_INTEGER || eType==SQLITE_FLOAT; - data.aiWth[data.n] = w = qrfDisplayWidth(z, n, &nNL); - data.n++; - if( w>data.a[i].mxW ) data.a[i].mxW = w; - if( nNL ) data.bMultiRow = 1; - } - p->nRow++; - }while( sqlite3_step(p->pStmt)==SQLITE_ROW && p->iErr==SQLITE_OK ); - if( p->iErr ){ - qrfColDataFree(&data); - return; - } - - /* Compute the width and alignment of every column */ - if( p->spec.bTitles==QRF_No ){ - qrfLoadAlignment(&data, p); - }else{ - unsigned char e; - if( p->spec.eTitleAlign==QRF_Auto ){ - e = QRF_ALIGN_Center; - }else{ - e = p->spec.eTitleAlign; - } - for(i=0; ispec.nWidth ){ - w = p->spec.aWidth[i]; - if( w==(-32768) ){ - w = 0; - if( p->spec.nAlign>i && (p->spec.aAlign[i] & QRF_ALIGN_HMASK)==0 ){ - data.a[i].e |= QRF_ALIGN_Right; - } - }else if( w<0 ){ - w = -w; - if( p->spec.nAlign>i && (p->spec.aAlign[i] & QRF_ALIGN_HMASK)==0 ){ - data.a[i].e |= QRF_ALIGN_Right; - } - } - if( w ) data.a[i].fx = 1; - } - if( w==0 ){ - w = data.a[i].mxW; - if( p->spec.nWrap>0 && w>p->spec.nWrap ){ - w = p->spec.nWrap; - data.bMultiRow = 1; - } - }else if( (data.bMultiRow==0 || w==1) && data.a[i].mxW>w ){ - data.bMultiRow = 1; - if( w==1 ){ - /* If aiWth[j] is 2 or more, then there might be a double-wide - ** character somewhere. So make the column width at least 2. */ - w = 2; - } - } - data.a[i].w = w; - } - - if( nColumn==1 - && data.n>1 - && p->spec.bSplitColumn==QRF_Yes - && p->spec.eStyle==QRF_STYLE_Column - && p->spec.bTitles==QRF_No - && p->spec.nScreenWidth>data.a[0].w+3 - ){ - /* Attempt to convert single-column tables into multi-column by - ** verticle wrapping, if the screen is wide enough and if the - ** bSplitColumn flag is set. */ - qrfSplitColumn(&data, p); - nColumn = data.nCol; - }else{ - /* Adjust the column widths due to screen width restrictions */ - qrfRestrictScreenWidth(&data, p); - } - - /* Draw the line across the top of the table. Also initialize - ** the row boundary and column separator texts. */ - switch( p->spec.eStyle ){ - case QRF_STYLE_Box: - if( data.nMargin ){ - rowStart = BOX_13 " "; - colSep = " " BOX_13 " "; - rowSep = " " BOX_13 "\n"; - }else{ - rowStart = BOX_13; - colSep = BOX_13; - rowSep = BOX_13 "\n"; - } - if( p->spec.bBorder==QRF_No){ - rowStart += 3; - rowSep = "\n"; - }else{ - qrfBoxSeparator(p->pOut, &data, BOX_R23, BOX_234, BOX_R34, 0); - } - break; - case QRF_STYLE_Table: - if( data.nMargin ){ - rowStart = "| "; - colSep = " | "; - rowSep = " |\n"; - }else{ - rowStart = "|"; - colSep = "|"; - rowSep = "|\n"; - } - if( p->spec.bBorder==QRF_No ){ - rowStart += 1; - rowSep = "\n"; - }else{ - qrfRowSeparator(p->pOut, &data, '+'); - } - break; - case QRF_STYLE_Column: { - static const char zSpace[] = " "; - rowStart = ""; - if( data.nMargin<2 ){ - colSep = " "; - }else if( data.nMargin<=5 ){ - colSep = &zSpace[5-data.nMargin]; - }else{ - colSep = zSpace; - } - rowSep = "\n"; - break; - } - default: /*case QRF_STYLE_Markdown:*/ - if( data.nMargin ){ - rowStart = "| "; - colSep = " | "; - rowSep = " |\n"; - }else{ - rowStart = "|"; - colSep = "|"; - rowSep = "|\n"; - } - break; - } - szRowStart = (int)strlen(rowStart); - szRowSep = (int)strlen(rowSep); - szColSep = (int)strlen(colSep); - - bWW = (p->spec.bWordWrap==QRF_Yes && data.bMultiRow); - if( p->spec.eStyle==QRF_STYLE_Column - || (p->spec.bBorder==QRF_No - && (p->spec.eStyle==QRF_STYLE_Box || p->spec.eStyle==QRF_STYLE_Table) - ) - ){ - bRTrim = 1; - }else{ - bRTrim = 0; - } - for(i=0; ipOut)==SQLITE_OK; i+=nColumn){ - int bMore; - int nRow = 0; - - /* Draw a single row of the table. This might be the title line - ** (if there is a title line) or a row in the body of the table. - ** The column number will be j. The row number is i/nColumn. - */ - for(j=0; jpOut, rowStart, szRowStart); - bMore = 0; - for(j=0; jpOut, &data.a[j], nThis, nWS); - data.a[j].z += iNext; - if( data.a[j].z[0]!=0 ){ - bMore = 1; - } - if( jpOut, colSep, szColSep); - }else{ - if( bRTrim ) qrfRTrim(p->pOut); - sqlite3_str_append(p->pOut, rowSep, szRowSep); - } - } - }while( bMore && ++nRow < p->mxHeight ); - if( bMore ){ - /* This row was terminated by nLineLimit. Show ellipsis. */ - sqlite3_str_append(p->pOut, rowStart, szRowStart); - for(j=0; jpOut, data.a[j].w, ' '); - }else{ - int nE = 3; - if( nE>data.a[j].w ) nE = data.a[j].w; - data.a[j].z = "..."; - qrfPrintAligned(p->pOut, &data.a[j], nE, data.a[j].w-nE); - } - if( jpOut, colSep, szColSep); - }else{ - if( bRTrim ) qrfRTrim(p->pOut); - sqlite3_str_append(p->pOut, rowSep, szRowSep); - } - } - } - - /* Draw either (1) the separator between the title line and the body - ** of the table, or (2) separators between individual rows of the table - ** body. isTitleDataSeparator will be true if we are doing (1). - */ - if( (i==0 || data.bMultiRow) && i+nColumnspec.bTitles==QRF_Yes); - if( isTitleDataSeparator ){ - qrfLoadAlignment(&data, p); - } - switch( p->spec.eStyle ){ - case QRF_STYLE_Table: { - if( isTitleDataSeparator || data.bMultiRow ){ - qrfRowSeparator(p->pOut, &data, '+'); - } - break; - } - case QRF_STYLE_Box: { - if( isTitleDataSeparator ){ - qrfBoxSeparator(p->pOut, &data, DBL_123, DBL_1234, DBL_134, 1); - }else if( data.bMultiRow ){ - qrfBoxSeparator(p->pOut, &data, BOX_123, BOX_1234, BOX_134, 0); - } - break; - } - case QRF_STYLE_Markdown: { - if( isTitleDataSeparator ){ - qrfRowSeparator(p->pOut, &data, '|'); - } - break; - } - case QRF_STYLE_Column: { - if( isTitleDataSeparator ){ - for(j=0; jpOut, data.a[j].w, '-'); - if( jpOut, colSep, szColSep); - }else{ - qrfRTrim(p->pOut); - sqlite3_str_append(p->pOut, rowSep, szRowSep); - } - } - }else if( data.bMultiRow ){ - qrfRTrim(p->pOut); - sqlite3_str_append(p->pOut, "\n", 1); - } - break; - } - } - } - } - - /* Draw the line across the bottom of the table */ - if( p->spec.bBorder!=QRF_No ){ - switch( p->spec.eStyle ){ - case QRF_STYLE_Box: - qrfBoxSeparator(p->pOut, &data, BOX_R12, BOX_124, BOX_R14, 0); - break; - case QRF_STYLE_Table: - qrfRowSeparator(p->pOut, &data, '+'); - break; - } - } - qrfWrite(p); - - qrfColDataFree(&data); - return; -} - -/* -** Parameter azArray points to a zero-terminated array of strings. zStr -** points to a single nul-terminated string. Return non-zero if zStr -** is equal, according to strcmp(), to any of the strings in the array. -** Otherwise, return zero. -*/ -static int qrfStringInArray(const char *zStr, const char **azArray){ - int i; - if( zStr==0 ) return 0; - for(i=0; azArray[i]; i++){ - if( 0==strcmp(zStr, azArray[i]) ) return 1; - } - return 0; -} - -/* -** Print out an EXPLAIN with indentation. This is a two-pass algorithm. -** -** On the first pass, we compute aiIndent[iOp] which is the amount of -** indentation to apply to the iOp-th opcode. The output actually occurs -** on the second pass. -** -** The indenting rules are: -** -** * For each "Next", "Prev", "VNext" or "VPrev" instruction, indent -** all opcodes that occur between the p2 jump destination and the opcode -** itself by 2 spaces. -** -** * Do the previous for "Return" instructions for when P2 is positive. -** See tag-20220407a in wherecode.c and vdbe.c. -** -** * For each "Goto", if the jump destination is earlier in the program -** and ends on one of: -** Yield SeekGt SeekLt RowSetRead Rewind -** or if the P1 parameter is one instead of zero, -** then indent all opcodes between the earlier instruction -** and "Goto" by 2 spaces. -*/ -static void qrfExplain(Qrf *p){ - int *abYield = 0; /* abYield[iOp] is rue if opcode iOp is an OP_Yield */ - int *aiIndent = 0; /* Indent the iOp-th opcode by aiIndent[iOp] */ - i64 nAlloc = 0; /* Allocated size of aiIndent[], abYield */ - int nIndent = 0; /* Number of entries in aiIndent[] */ - int iOp; /* Opcode number */ - int i; /* Column loop counter */ - - const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", - "Return", 0 }; - const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead", - "Rewind", 0 }; - const char *azGoto[] = { "Goto", 0 }; - - /* The caller guarantees that the leftmost 4 columns of the statement - ** passed to this function are equivalent to the leftmost 4 columns - ** of EXPLAIN statement output. In practice the statement may be - ** an EXPLAIN, or it may be a query on the bytecode() virtual table. */ - assert( sqlite3_column_count(p->pStmt)>=4 ); - assert( 0==sqlite3_stricmp( sqlite3_column_name(p->pStmt, 0), "addr" ) ); - assert( 0==sqlite3_stricmp( sqlite3_column_name(p->pStmt, 1), "opcode" ) ); - assert( 0==sqlite3_stricmp( sqlite3_column_name(p->pStmt, 2), "p1" ) ); - assert( 0==sqlite3_stricmp( sqlite3_column_name(p->pStmt, 3), "p2" ) ); - - for(iOp=0; SQLITE_ROW==sqlite3_step(p->pStmt) && !p->iErr; iOp++){ - int iAddr = sqlite3_column_int(p->pStmt, 0); - const char *zOp = (const char*)sqlite3_column_text(p->pStmt, 1); - int p1 = sqlite3_column_int(p->pStmt, 2); - int p2 = sqlite3_column_int(p->pStmt, 3); - - /* Assuming that p2 is an instruction address, set variable p2op to the - ** index of that instruction in the aiIndent[] array. p2 and p2op may be - ** different if the current instruction is part of a sub-program generated - ** by an SQL trigger or foreign key. */ - int p2op = (p2 + (iOp-iAddr)); - - /* Grow the aiIndent array as required */ - if( iOp>=nAlloc ){ - nAlloc += 100; - aiIndent = (int*)sqlite3_realloc64(aiIndent, nAlloc*sizeof(int)); - abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int)); - if( aiIndent==0 || abYield==0 ){ - qrfOom(p); - sqlite3_free(aiIndent); - sqlite3_free(abYield); - return; - } - } - - abYield[iOp] = qrfStringInArray(zOp, azYield); - aiIndent[iOp] = 0; - nIndent = iOp+1; - if( qrfStringInArray(zOp, azNext) && p2op>0 ){ - for(i=p2op; ipStmt); - if( p->iErr==SQLITE_OK ){ - static const int aExplainWidth[] = {4, 13, 4, 4, 4, 13, 2, 13}; - static const int aExplainMap[] = {0, 1, 2, 3, 4, 5, 6, 7 }; - static const int aScanExpWidth[] = {4,15, 6, 13, 4, 4, 4, 13, 2, 13}; - static const int aScanExpMap[] = {0, 9, 8, 1, 2, 3, 4, 5, 6, 7 }; - const int *aWidth = aExplainWidth; - const int *aMap = aExplainMap; - int nWidth = sizeof(aExplainWidth)/sizeof(int); - int iIndent = 1; - int nArg = p->nCol; - if( p->spec.eStyle==QRF_STYLE_StatsVm ){ - aWidth = aScanExpWidth; - aMap = aScanExpMap; - nWidth = sizeof(aScanExpWidth)/sizeof(int); - iIndent = 3; - } - if( nArg>nWidth ) nArg = nWidth; - - for(iOp=0; sqlite3_step(p->pStmt)==SQLITE_ROW && !p->iErr; iOp++){ - /* If this is the first row seen, print out the headers */ - if( iOp==0 ){ - for(i=0; ipStmt, aMap[i]); - qrfWidthPrint(p,p->pOut, aWidth[i], zCol); - if( i==nArg-1 ){ - sqlite3_str_append(p->pOut, "\n", 1); - }else{ - sqlite3_str_append(p->pOut, " ", 2); - } - } - for(i=0; ipOut, "%.*c", aWidth[i], '-'); - if( i==nArg-1 ){ - sqlite3_str_append(p->pOut, "\n", 1); - }else{ - sqlite3_str_append(p->pOut, " ", 2); - } - } - } - - for(i=0; ipStmt, aMap[i]); - int len; - if( i==nArg-1 ) w = 0; - if( zVal==0 ) zVal = ""; - len = (int)sqlite3_qrf_wcswidth(zVal); - if( len>w ){ - w = len; - zSep = " "; - } - if( i==iIndent && aiIndent && iOppOut, aiIndent[iOp], ' '); - } - qrfWidthPrint(p, p->pOut, w, zVal); - if( i==nArg-1 ){ - sqlite3_str_append(p->pOut, "\n", 1); - }else{ - sqlite3_str_appendall(p->pOut, zSep); - } - } - p->nRow++; - } - qrfWrite(p); - } - sqlite3_free(aiIndent); -} - -/* -** Do a "scanstatus vm" style EXPLAIN listing on p->pStmt. -** -** p->pStmt is probably not an EXPLAIN query. Instead, construct a -** new query that is a bytecode() rendering of p->pStmt with extra -** columns for the "scanstatus vm" outputs, and run the results of -** that new query through the normal EXPLAIN formatting. -*/ -static void qrfScanStatusVm(Qrf *p){ - sqlite3_stmt *pOrigStmt = p->pStmt; - sqlite3_stmt *pExplain; - int rc; - static const char *zSql = - " SELECT addr, opcode, p1, p2, p3, p4, p5, comment, nexec," - " format('% 6s (%.2f%%)'," - " CASE WHEN ncycle<100_000 THEN ncycle || ' '" - " WHEN ncycle<100_000_000 THEN (ncycle/1_000) || 'K'" - " WHEN ncycle<100_000_000_000 THEN (ncycle/1_000_000) || 'M'" - " ELSE (ncycle/1000_000_000) || 'G' END," - " ncycle*100.0/(sum(ncycle) OVER ())" - " ) AS cycles" - " FROM bytecode(?1)"; - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pExplain, 0); - if( rc ){ - qrfError(p, rc, "%s", sqlite3_errmsg(p->db)); - sqlite3_finalize(pExplain); - return; - } - sqlite3_bind_pointer(pExplain, 1, pOrigStmt, "stmt-pointer", 0); - p->pStmt = pExplain; - p->nCol = 10; - qrfExplain(p); - sqlite3_finalize(pExplain); - p->pStmt = pOrigStmt; -} - -/* -** 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 1 if quoting is required. Return 0 if no quoting is required. -*/ - -static int qrf_need_quote(const char *zName){ - int i; - const unsigned char *z = (const unsigned char*)zName; - if( z==0 ) return 1; - if( !qrfAlpha(z[0]) ) return 1; - for(i=0; z[i]; i++){ - if( !qrfAlnum(z[i]) ) return 1; - } - return sqlite3_keyword_check(zName, i)!=0; -} - -/* -** Helper function for QRF_STYLE_Json and QRF_STYLE_JObject. -** The initial "{" for a JSON object that will contain row content -** has been output. Now output all the content. -*/ -static void qrfOneJsonRow(Qrf *p){ - int i, nItem; - for(nItem=i=0; inCol; i++){ - const char *zCName; - zCName = sqlite3_column_name(p->pStmt, i); - if( nItem>0 ) sqlite3_str_append(p->pOut, ",", 1); - nItem++; - qrfEncodeText(p, p->pOut, zCName); - sqlite3_str_append(p->pOut, ":", 1); - qrfRenderValue(p, p->pOut, i); - } - qrfWrite(p); -} - -/* -** Render a single row of output for non-columnar styles - any -** style that lets us render row by row as the content is received -** from the query. -*/ -static void qrfOneSimpleRow(Qrf *p){ - int i; - switch( p->spec.eStyle ){ - case QRF_STYLE_Off: - case QRF_STYLE_Count: { - /* No-op */ - break; - } - case QRF_STYLE_Json: { - if( p->nRow==0 ){ - sqlite3_str_append(p->pOut, "[{", 2); - }else{ - sqlite3_str_append(p->pOut, "},\n{", 4); - } - qrfOneJsonRow(p); - break; - } - case QRF_STYLE_JObject: { - if( p->nRow==0 ){ - sqlite3_str_append(p->pOut, "{", 1); - }else{ - sqlite3_str_append(p->pOut, "}\n{", 3); - } - qrfOneJsonRow(p); - break; - } - case QRF_STYLE_Html: { - if( p->nRow==0 && p->spec.bTitles==QRF_Yes ){ - sqlite3_str_append(p->pOut, "", 4); - for(i=0; inCol; i++){ - const char *zCName = sqlite3_column_name(p->pStmt, i); - sqlite3_str_append(p->pOut, "\n", 5); - qrfEncodeText(p, p->pOut, zCName); - } - sqlite3_str_append(p->pOut, "\n\n", 7); - } - sqlite3_str_append(p->pOut, "", 4); - for(i=0; inCol; i++){ - sqlite3_str_append(p->pOut, "\n", 5); - qrfRenderValue(p, p->pOut, i); - } - sqlite3_str_append(p->pOut, "\n\n", 7); - qrfWrite(p); - break; - } - case QRF_STYLE_Insert: { - unsigned int mxIns = p->spec.nMultiInsert; - int szStart = sqlite3_str_length(p->pOut); - if( p->u.nIns==0 || p->u.nIns>=mxIns ){ - if( p->u.nIns ){ - sqlite3_str_append(p->pOut, ";\n", 2); - p->u.nIns = 0; - } - if( qrf_need_quote(p->spec.zTableName) ){ - sqlite3_str_appendf(p->pOut,"INSERT INTO \"%w\"",p->spec.zTableName); - }else{ - sqlite3_str_appendf(p->pOut,"INSERT INTO %s",p->spec.zTableName); - } - if( p->spec.bTitles==QRF_Yes ){ - for(i=0; inCol; i++){ - const char *zCName = sqlite3_column_name(p->pStmt, i); - if( qrf_need_quote(zCName) ){ - sqlite3_str_appendf(p->pOut, "%c\"%w\"", - i==0 ? '(' : ',', zCName); - }else{ - sqlite3_str_appendf(p->pOut, "%c%s", - i==0 ? '(' : ',', zCName); - } - } - sqlite3_str_append(p->pOut, ")", 1); - } - sqlite3_str_append(p->pOut," VALUES(", 8); - }else{ - sqlite3_str_append(p->pOut,",\n (", 5); - } - for(i=0; inCol; i++){ - if( i>0 ) sqlite3_str_append(p->pOut, ",", 1); - qrfRenderValue(p, p->pOut, i); - } - p->u.nIns += sqlite3_str_length(p->pOut) + 2 - szStart; - if( p->u.nIns>=mxIns ){ - sqlite3_str_append(p->pOut, ");\n", 3); - p->u.nIns = 0; - }else{ - sqlite3_str_append(p->pOut, ")", 1); - } - qrfWrite(p); - break; - } - case QRF_STYLE_Line: { - sqlite3_str *pVal; - int mxW; - int bWW; - int nSep; - if( p->u.sLine.azCol==0 ){ - p->u.sLine.azCol = sqlite3_malloc64( p->nCol*sizeof(char*) ); - if( p->u.sLine.azCol==0 ){ - qrfOom(p); - break; - } - p->u.sLine.mxColWth = 0; - for(i=0; inCol; i++){ - int sz; - const char *zCName = sqlite3_column_name(p->pStmt, i); - if( zCName==0 ) zCName = "unknown"; - p->u.sLine.azCol[i] = sqlite3_mprintf("%s", zCName); - if( p->spec.nTitleLimit>0 ){ - (void)qrfTitleLimit(p->u.sLine.azCol[i], p->spec.nTitleLimit); - } - sz = (int)sqlite3_qrf_wcswidth(p->u.sLine.azCol[i]); - if( sz > p->u.sLine.mxColWth ) p->u.sLine.mxColWth = sz; - } - } - if( p->nRow ) sqlite3_str_append(p->pOut, "\n", 1); - pVal = sqlite3_str_new(p->db); - nSep = (int)strlen(p->spec.zColumnSep); - mxW = p->mxWidth - (nSep + p->u.sLine.mxColWth); - bWW = p->spec.bWordWrap==QRF_Yes; - for(i=0; inCol; i++){ - const char *zVal; - int cnt = 0; - qrfWidthPrint(p, p->pOut, -p->u.sLine.mxColWth, p->u.sLine.azCol[i]); - sqlite3_str_append(p->pOut, p->spec.zColumnSep, nSep); - qrfRenderValue(p, pVal, i); - zVal = sqlite3_str_value(pVal); - if( zVal==0 ) zVal = ""; - do{ - int nThis, nWide, iNext; - qrfWrapLine(zVal, mxW, bWW, &nThis, &nWide, &iNext); - if( cnt ){ - sqlite3_str_appendchar(p->pOut,p->u.sLine.mxColWth+nSep,' '); - } - cnt++; - if( cnt>p->mxHeight ){ - zVal = "..."; - nThis = iNext = 3; - } - sqlite3_str_append(p->pOut, zVal, nThis); - sqlite3_str_append(p->pOut, "\n", 1); - zVal += iNext; - }while( zVal[0] ); - sqlite3_str_reset(pVal); - } - qrfStrErr(p, pVal); - sqlite3_free(sqlite3_str_finish(pVal)); - qrfWrite(p); - break; - } - case QRF_STYLE_Eqp: { - const char *zEqpLine = (const char*)sqlite3_column_text(p->pStmt,3); - int iEqpId = sqlite3_column_int(p->pStmt, 0); - int iParentId = sqlite3_column_int(p->pStmt, 1); - if( zEqpLine==0 ) zEqpLine = ""; - if( zEqpLine[0]=='-' ) qrfEqpRender(p, 0); - qrfEqpAppend(p, iEqpId, iParentId, zEqpLine); - break; - } - default: { /* QRF_STYLE_List */ - if( p->nRow==0 && p->spec.bTitles==QRF_Yes ){ - int saved_eText = p->spec.eText; - p->spec.eText = p->spec.eTitle; - for(i=0; inCol; i++){ - const char *zCName = sqlite3_column_name(p->pStmt, i); - if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep); - qrfEncodeText(p, p->pOut, zCName); - } - sqlite3_str_appendall(p->pOut, p->spec.zRowSep); - qrfWrite(p); - p->spec.eText = saved_eText; - } - for(i=0; inCol; i++){ - if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep); - qrfRenderValue(p, p->pOut, i); - } - sqlite3_str_appendall(p->pOut, p->spec.zRowSep); - qrfWrite(p); - break; - } - } - p->nRow++; -} - -/* -** Initialize the internal Qrf object. -*/ -static void qrfInitialize( - Qrf *p, /* State object to be initialized */ - sqlite3_stmt *pStmt, /* Query whose output to be formatted */ - const sqlite3_qrf_spec *pSpec, /* Format specification */ - char **pzErr /* Write errors here */ -){ - size_t sz; /* Size of pSpec[], based on pSpec->iVersion */ - memset(p, 0, sizeof(*p)); - p->pzErr = pzErr; - if( pSpec->iVersion>1 ){ - qrfError(p, SQLITE_ERROR, - "unusable sqlite3_qrf_spec.iVersion (%d)", - pSpec->iVersion); - return; - } - p->pStmt = pStmt; - p->db = sqlite3_db_handle(pStmt); - p->pOut = sqlite3_str_new(p->db); - if( p->pOut==0 ){ - qrfOom(p); - return; - } - p->iErr = SQLITE_OK; - p->nCol = sqlite3_column_count(p->pStmt); - p->nRow = 0; - sz = sizeof(sqlite3_qrf_spec); - memcpy(&p->spec, pSpec, sz); - if( p->spec.zNull==0 ) p->spec.zNull = ""; - p->mxWidth = p->spec.nScreenWidth; - if( p->mxWidth<=0 ) p->mxWidth = QRF_MAX_WIDTH; - p->mxHeight = p->spec.nLineLimit; - if( p->mxHeight<=0 ) p->mxHeight = 2147483647; - if( p->spec.eStyle>QRF_STYLE_Table ) p->spec.eStyle = QRF_Auto; - if( p->spec.eEsc>QRF_ESC_Symbol ) p->spec.eEsc = QRF_Auto; - if( p->spec.eText>QRF_TEXT_Relaxed ) p->spec.eText = QRF_Auto; - if( p->spec.eTitle>QRF_TEXT_Relaxed ) p->spec.eTitle = QRF_Auto; - if( p->spec.eBlob>QRF_BLOB_Size ) p->spec.eBlob = QRF_Auto; -qrf_reinit: - switch( p->spec.eStyle ){ - case QRF_Auto: { - switch( sqlite3_stmt_isexplain(pStmt) ){ - case 0: p->spec.eStyle = QRF_STYLE_Box; break; - case 1: p->spec.eStyle = QRF_STYLE_Explain; break; - default: p->spec.eStyle = QRF_STYLE_Eqp; break; - } - goto qrf_reinit; - } - case QRF_STYLE_List: { - if( p->spec.zColumnSep==0 ) p->spec.zColumnSep = "|"; - if( p->spec.zRowSep==0 ) p->spec.zRowSep = "\n"; - break; - } - case QRF_STYLE_JObject: - case QRF_STYLE_Json: { - p->spec.eText = QRF_TEXT_Json; - p->spec.zNull = "null"; - break; - } - case QRF_STYLE_Html: { - p->spec.eText = QRF_TEXT_Html; - p->spec.zNull = "null"; - break; - } - case QRF_STYLE_Insert: { - p->spec.eText = QRF_TEXT_Sql; - p->spec.zNull = "NULL"; - if( p->spec.zTableName==0 || p->spec.zTableName[0]==0 ){ - p->spec.zTableName = "tab"; - } - p->u.nIns = 0; - break; - } - case QRF_STYLE_Line: { - if( p->spec.zColumnSep==0 ){ - p->spec.zColumnSep = ": "; - } - break; - } - case QRF_STYLE_Csv: { - p->spec.eStyle = QRF_STYLE_List; - p->spec.eText = QRF_TEXT_Csv; - p->spec.zColumnSep = ","; - p->spec.zRowSep = "\r\n"; - p->spec.zNull = ""; - break; - } - case QRF_STYLE_Quote: { - p->spec.eText = QRF_TEXT_Sql; - p->spec.zNull = "NULL"; - p->spec.zColumnSep = ","; - p->spec.zRowSep = "\n"; - break; - } - case QRF_STYLE_Eqp: { - int expMode = sqlite3_stmt_isexplain(p->pStmt); - if( expMode!=2 ){ - sqlite3_stmt_explain(p->pStmt, 2); - p->expMode = expMode+1; - } - break; - } - case QRF_STYLE_Explain: { - int expMode = sqlite3_stmt_isexplain(p->pStmt); - if( expMode!=1 ){ - sqlite3_stmt_explain(p->pStmt, 1); - p->expMode = expMode+1; - } - break; - } - } - if( p->spec.eEsc==QRF_Auto ){ - p->spec.eEsc = QRF_ESC_Ascii; - } - if( p->spec.eText==QRF_Auto ){ - p->spec.eText = QRF_TEXT_Plain; - } - if( p->spec.eTitle==QRF_Auto ){ - switch( p->spec.eStyle ){ - case QRF_STYLE_Box: - case QRF_STYLE_Column: - case QRF_STYLE_Table: - p->spec.eTitle = QRF_TEXT_Plain; - break; - default: - p->spec.eTitle = p->spec.eText; - break; - } - } - if( p->spec.eBlob==QRF_Auto ){ - switch( p->spec.eText ){ - case QRF_TEXT_Sql: p->spec.eBlob = QRF_BLOB_Sql; break; - case QRF_TEXT_Csv: p->spec.eBlob = QRF_BLOB_Tcl; break; - case QRF_TEXT_Tcl: p->spec.eBlob = QRF_BLOB_Tcl; break; - case QRF_TEXT_Json: p->spec.eBlob = QRF_BLOB_Json; break; - default: p->spec.eBlob = QRF_BLOB_Text; break; - } - } - if( p->spec.bTitles==QRF_Auto ){ - switch( p->spec.eStyle ){ - case QRF_STYLE_Box: - case QRF_STYLE_Csv: - case QRF_STYLE_Column: - case QRF_STYLE_Table: - case QRF_STYLE_Markdown: - p->spec.bTitles = QRF_Yes; - break; - default: - p->spec.bTitles = QRF_No; - break; - } - } - if( p->spec.bWordWrap==QRF_Auto ){ - p->spec.bWordWrap = QRF_Yes; - } - if( p->spec.bTextJsonb==QRF_Auto ){ - p->spec.bTextJsonb = QRF_No; - } - if( p->spec.zColumnSep==0 ) p->spec.zColumnSep = ","; - if( p->spec.zRowSep==0 ) p->spec.zRowSep = "\n"; -} - -/* -** Finish rendering the results -*/ -static void qrfFinalize(Qrf *p){ - switch( p->spec.eStyle ){ - case QRF_STYLE_Count: { - sqlite3_str_appendf(p->pOut, "%lld\n", p->nRow); - break; - } - case QRF_STYLE_Json: { - if( p->nRow>0 ){ - sqlite3_str_append(p->pOut, "}]\n", 3); - } - break; - } - case QRF_STYLE_JObject: { - if( p->nRow>0 ){ - sqlite3_str_append(p->pOut, "}\n", 2); - } - break; - } - case QRF_STYLE_Insert: { - if( p->u.nIns ){ - sqlite3_str_append(p->pOut, ";\n", 2); - } - break; - } - case QRF_STYLE_Line: { - if( p->u.sLine.azCol ){ - int i; - for(i=0; inCol; i++) sqlite3_free(p->u.sLine.azCol[i]); - sqlite3_free(p->u.sLine.azCol); - } - break; - } - case QRF_STYLE_Stats: - case QRF_STYLE_StatsEst: { - i64 nCycle = 0; -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS - sqlite3_stmt_scanstatus_v2(p->pStmt, -1, SQLITE_SCANSTAT_NCYCLE, - SQLITE_SCANSTAT_COMPLEX, (void*)&nCycle); -#endif - qrfEqpRender(p, nCycle); - break; - } - case QRF_STYLE_Eqp: { - qrfEqpRender(p, 0); - break; - } - } - qrfWrite(p); - qrfStrErr(p, p->pOut); - if( p->spec.pzOutput ){ - if( p->spec.pzOutput[0] ){ - sqlite3_int64 n, sz; - char *zCombined; - sz = strlen(p->spec.pzOutput[0]); - n = sqlite3_str_length(p->pOut); - zCombined = sqlite3_realloc64(p->spec.pzOutput[0], sz+n+1); - if( zCombined==0 ){ - sqlite3_free(p->spec.pzOutput[0]); - p->spec.pzOutput[0] = 0; - qrfOom(p); - }else{ - p->spec.pzOutput[0] = zCombined; - memcpy(zCombined+sz, sqlite3_str_value(p->pOut), n+1); - } - sqlite3_free(sqlite3_str_finish(p->pOut)); - }else{ - p->spec.pzOutput[0] = sqlite3_str_finish(p->pOut); - } - }else if( p->pOut ){ - sqlite3_free(sqlite3_str_finish(p->pOut)); - } - if( p->expMode>0 ){ - sqlite3_stmt_explain(p->pStmt, p->expMode-1); - } - if( p->actualWidth ){ - sqlite3_free(p->actualWidth); - } - if( p->pJTrans ){ - sqlite3 *db = sqlite3_db_handle(p->pJTrans); - sqlite3_finalize(p->pJTrans); - sqlite3_close(db); - } -} - -/* -** Run the prepared statement pStmt and format the results according -** to the specification provided in pSpec. Return an error code. -** If pzErr is not NULL and if an error occurs, write an error message -** into *pzErr. -*/ -int sqlite3_format_query_result( - sqlite3_stmt *pStmt, /* Statement to evaluate */ - const sqlite3_qrf_spec *pSpec, /* Format specification */ - char **pzErr /* Write error message here */ -){ - Qrf qrf; /* The new Qrf being created */ - - if( pStmt==0 ) return SQLITE_OK; /* No-op */ - if( pSpec==0 ) return SQLITE_MISUSE; - qrfInitialize(&qrf, pStmt, pSpec, pzErr); - switch( qrf.spec.eStyle ){ - case QRF_STYLE_Box: - case QRF_STYLE_Column: - case QRF_STYLE_Markdown: - case QRF_STYLE_Table: { - /* Columnar modes require that the entire query be evaluated and the - ** results stored in memory, so that we can compute column widths */ - qrfColumnar(&qrf); - break; - } - case QRF_STYLE_Explain: { - qrfExplain(&qrf); - break; - } - case QRF_STYLE_StatsVm: { - qrfScanStatusVm(&qrf); - break; - } - case QRF_STYLE_Stats: - case QRF_STYLE_StatsEst: { - qrfEqpStats(&qrf); - break; - } - default: { - /* Non-columnar modes where the output can occur after each row - ** of result is received */ - while( qrf.iErr==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ - qrfOneSimpleRow(&qrf); - } - break; - } - } - qrfResetStmt(&qrf); - qrfFinalize(&qrf); - return qrf.iErr; -} - -/************************* End ext/qrf/qrf.c ********************/ - -/* Use console I/O package as a direct INCLUDE. */ -#define SQLITE_INTERNAL_LINKAGE static - -#ifdef SQLITE_SHELL_FIDDLE -/* Deselect most features from the console I/O package for Fiddle. */ -# define SQLITE_CIO_NO_REDIRECT -# define SQLITE_CIO_NO_CLASSIFY -# define SQLITE_CIO_NO_TRANSLATE -# define SQLITE_CIO_NO_SETMODE -# define SQLITE_CIO_NO_FLUSH -#endif - -/* -** The source code for several run-time loadable extensions is inserted -** below by the ../tool/mkshellc.tcl script. Before processing that included -** code, we need to override some macros to make the included program code -** work here in the middle of this regular program. -*/ -#define SQLITE_EXTENSION_INIT1 -#define SQLITE_EXTENSION_INIT2(X) (void)(X) - -/************************* Begin ext/misc/windirent.h ******************/ -/* -** 2025-06-05 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -** An implementation of opendir(), readdir(), and closedir() for Windows, -** based on the FindFirstFile(), FindNextFile(), and FindClose() APIs -** of Win32. -** -** #include this file inside any C-code module that needs to use -** opendir()/readdir()/closedir(). This file is a no-op on non-Windows -** machines. On Windows, static functions are defined that implement -** those standard interfaces. -*/ -#if defined(_WIN32) && defined(_MSC_VER) && !defined(SQLITE_WINDIRENT_H) -#define SQLITE_WINDIRENT_H - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef FILENAME_MAX -# define FILENAME_MAX (260) -#endif -#ifndef S_ISREG -#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) -#endif -#ifndef S_ISDIR -#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#endif -#ifndef S_ISLNK -#define S_ISLNK(m) (0) -#endif -typedef unsigned short mode_t; - -/* The dirent object for Windows is abbreviated. The only field really -** usable by applications is d_name[]. -*/ -struct dirent { - int d_ino; /* Inode number (synthesized) */ - unsigned d_attributes; /* File attributes */ - char d_name[FILENAME_MAX]; /* Null-terminated filename */ -}; - -/* The internals of DIR are opaque according to standards. So it -** does not matter what we put here. */ -typedef struct DIR DIR; -struct DIR { - intptr_t d_handle; /* Handle for findfirst()/findnext() */ - struct dirent cur; /* Current entry */ -}; - -/* Ignore hidden and system files */ -#define WindowsFileToIgnore(a) \ - ((((a).attrib)&_A_HIDDEN) || (((a).attrib)&_A_SYSTEM)) - -/* -** Close a previously opened directory -*/ -static int closedir(DIR *pDir){ - int rc = 0; - if( pDir==0 ){ - return EINVAL; - } - if( pDir->d_handle!=0 && pDir->d_handle!=(-1) ){ - rc = _findclose(pDir->d_handle); - } - sqlite3_free(pDir); - return rc; -} - -/* -** Open a new directory. The directory name should be UTF-8 encoded. -** appropriate translations happen automatically. -*/ -static DIR *opendir(const char *zDirName){ - DIR *pDir; - wchar_t *b1; - sqlite3_int64 sz; - struct _wfinddata_t data; - - pDir = sqlite3_malloc64( sizeof(DIR) ); - if( pDir==0 ) return 0; - memset(pDir, 0, sizeof(DIR)); - memset(&data, 0, sizeof(data)); - sz = strlen(zDirName); - b1 = sqlite3_malloc64( (sz+3)*sizeof(b1[0]) ); - if( b1==0 ){ - closedir(pDir); - return NULL; - } - sz = MultiByteToWideChar(CP_UTF8, 0, zDirName, sz, b1, sz); - b1[sz++] = '\\'; - b1[sz++] = '*'; - b1[sz] = 0; - if( sz+1>sizeof(data.name)/sizeof(data.name[0]) ){ - closedir(pDir); - sqlite3_free(b1); - return NULL; - } - memcpy(data.name, b1, (sz+1)*sizeof(b1[0])); - sqlite3_free(b1); - pDir->d_handle = _wfindfirst(data.name, &data); - if( pDir->d_handle<0 ){ - closedir(pDir); - return NULL; - } - while( WindowsFileToIgnore(data) ){ - memset(&data, 0, sizeof(data)); - if( _wfindnext(pDir->d_handle, &data)==-1 ){ - closedir(pDir); - return NULL; - } - } - pDir->cur.d_ino = 0; - pDir->cur.d_attributes = data.attrib; - WideCharToMultiByte(CP_UTF8, 0, data.name, -1, - pDir->cur.d_name, FILENAME_MAX, 0, 0); - return pDir; -} - -/* -** Read the next entry from a directory. -** -** The returned struct-dirent object is managed by DIR. It is only -** valid until the next readdir() or closedir() call. Only the -** d_name[] field is meaningful. The d_name[] value has been -** translated into UTF8. -*/ -static struct dirent *readdir(DIR *pDir){ - struct _wfinddata_t data; - if( pDir==0 ) return 0; - if( (pDir->cur.d_ino++)==0 ){ - return &pDir->cur; - } - do{ - memset(&data, 0, sizeof(data)); - if( _wfindnext(pDir->d_handle, &data)==-1 ){ - return NULL; - } - }while( WindowsFileToIgnore(data) ); - pDir->cur.d_attributes = data.attrib; - WideCharToMultiByte(CP_UTF8, 0, data.name, -1, - pDir->cur.d_name, FILENAME_MAX, 0, 0); - return &pDir->cur; -} - -#endif /* defined(_WIN32) && defined(_MSC_VER) */ - -/************************* End ext/misc/windirent.h ********************/ -/************************* Begin ext/misc/memtrace.c ******************/ -/* -** 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; -} - -/************************* End ext/misc/memtrace.c ********************/ -/************************* Begin ext/misc/pcachetrace.c ******************/ -/* -** 2023-06-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_PCACHE2 -** mechanism to add a tracing layer on top of pluggable page cache of -** SQLite. If this extension is registered prior to sqlite3_initialize(), -** it will cause all page cache 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 --pcachetrace option of the -** command-line shell. -*/ -#include -#include -#include - -/* The original page cache routines */ -static sqlite3_pcache_methods2 pcacheBase; -static FILE *pcachetraceOut; - -/* Methods that trace pcache activity */ -static int pcachetraceInit(void *pArg){ - int nRes; - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xInit(%p)\n", pArg); - } - nRes = pcacheBase.xInit(pArg); - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xInit(%p) -> %d\n", pArg, nRes); - } - return nRes; -} -static void pcachetraceShutdown(void *pArg){ - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xShutdown(%p)\n", pArg); - } - pcacheBase.xShutdown(pArg); -} -static sqlite3_pcache *pcachetraceCreate(int szPage, int szExtra, int bPurge){ - sqlite3_pcache *pRes; - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xCreate(%d,%d,%d)\n", - szPage, szExtra, bPurge); - } - pRes = pcacheBase.xCreate(szPage, szExtra, bPurge); - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xCreate(%d,%d,%d) -> %p\n", - szPage, szExtra, bPurge, pRes); - } - return pRes; -} -static void pcachetraceCachesize(sqlite3_pcache *p, int nCachesize){ - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xCachesize(%p, %d)\n", p, nCachesize); - } - pcacheBase.xCachesize(p, nCachesize); -} -static int pcachetracePagecount(sqlite3_pcache *p){ - int nRes; - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xPagecount(%p)\n", p); - } - nRes = pcacheBase.xPagecount(p); - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xPagecount(%p) -> %d\n", p, nRes); - } - return nRes; -} -static sqlite3_pcache_page *pcachetraceFetch( - sqlite3_pcache *p, - unsigned key, - int crFg -){ - sqlite3_pcache_page *pRes; - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xFetch(%p,%u,%d)\n", p, key, crFg); - } - pRes = pcacheBase.xFetch(p, key, crFg); - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xFetch(%p,%u,%d) -> %p\n", - p, key, crFg, pRes); - } - return pRes; -} -static void pcachetraceUnpin( - sqlite3_pcache *p, - sqlite3_pcache_page *pPg, - int bDiscard -){ - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xUnpin(%p, %p, %d)\n", - p, pPg, bDiscard); - } - pcacheBase.xUnpin(p, pPg, bDiscard); -} -static void pcachetraceRekey( - sqlite3_pcache *p, - sqlite3_pcache_page *pPg, - unsigned oldKey, - unsigned newKey -){ - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xRekey(%p, %p, %u, %u)\n", - p, pPg, oldKey, newKey); - } - pcacheBase.xRekey(p, pPg, oldKey, newKey); -} -static void pcachetraceTruncate(sqlite3_pcache *p, unsigned n){ - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xTruncate(%p, %u)\n", p, n); - } - pcacheBase.xTruncate(p, n); -} -static void pcachetraceDestroy(sqlite3_pcache *p){ - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xDestroy(%p)\n", p); - } - pcacheBase.xDestroy(p); -} -static void pcachetraceShrink(sqlite3_pcache *p){ - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xShrink(%p)\n", p); - } - pcacheBase.xShrink(p); -} - -/* The substitute pcache methods */ -static sqlite3_pcache_methods2 ersaztPcacheMethods = { - 0, - 0, - pcachetraceInit, - pcachetraceShutdown, - pcachetraceCreate, - pcachetraceCachesize, - pcachetracePagecount, - pcachetraceFetch, - pcachetraceUnpin, - pcachetraceRekey, - pcachetraceTruncate, - pcachetraceDestroy, - pcachetraceShrink -}; - -/* Begin tracing memory allocations to out. */ -int sqlite3PcacheTraceActivate(FILE *out){ - int rc = SQLITE_OK; - if( pcacheBase.xFetch==0 ){ - rc = sqlite3_config(SQLITE_CONFIG_GETPCACHE2, &pcacheBase); - if( rc==SQLITE_OK ){ - rc = sqlite3_config(SQLITE_CONFIG_PCACHE2, &ersaztPcacheMethods); - } - } - pcachetraceOut = out; - return rc; -} - -/* Deactivate memory tracing */ -int sqlite3PcacheTraceDeactivate(void){ - int rc = SQLITE_OK; - if( pcacheBase.xFetch!=0 ){ - rc = sqlite3_config(SQLITE_CONFIG_PCACHE2, &pcacheBase); - if( rc==SQLITE_OK ){ - memset(&pcacheBase, 0, sizeof(pcacheBase)); - } - } - pcachetraceOut = 0; - return rc; -} - -/************************* End ext/misc/pcachetrace.c ********************/ -/************************* Begin ext/misc/shathree.c ******************/ -/* -** 2017-03-08 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This SQLite extension implements functions that compute SHA3 hashes -** in the way described by the (U.S.) NIST FIPS 202 SHA-3 Standard. -** Three SQL functions are implemented: -** -** sha3(X,SIZE) -** sha3_agg(Y,SIZE) -** sha3_query(Z,SIZE) -** -** The sha3(X) function computes the SHA3 hash of the input X, or NULL if -** X is NULL. If inputs X is text, the UTF-8 rendering of that text is -** used to compute the hash. If X is a BLOB, then the binary data of the -** blob is used to compute the hash. If X is an integer or real number, -** then that number if converted into UTF-8 text and the hash is computed -** over the text. -** -** The sha3_agg(Y) function computes the SHA3 hash of all Y inputs. Since -** order is important for the hash, it is recommended that the Y expression -** by followed by an ORDER BY clause to guarantee that the inputs occur -** in the desired order. -** -** The sha3_query(Y) function evaluates all queries in the SQL statements of Y -** and returns a hash of their results. -** -** The SIZE argument is optional. If omitted, the SHA3-256 hash algorithm -** is used. If SIZE is included it must be one of the integers 224, 256, -** 384, or 512, to determine SHA3 hash variant that is computed. -** -** Because the sha3_agg() and sha3_query() functions compute a hash over -** multiple values, the values are encode to use include type information. -** -** In sha3_agg(), the sequence of bytes that gets hashed for each input -** Y depends on the datatype of Y: -** -** typeof(Y)='null' A single "N" is hashed. (One byte) -** -** typeof(Y)='integer' The data hash is the character "I" followed -** by an 8-byte big-endian binary of the -** 64-bit signed integer. (Nine bytes total.) -** -** typeof(Y)='real' The character "F" followed by an 8-byte -** big-ending binary of the double. (Nine -** bytes total.) -** -** typeof(Y)='text' The hash is over prefix "Tnnn:" followed -** by the UTF8 encoding of the text. The "nnn" -** in the prefix is the minimum-length decimal -** representation of the octet_length of the text. -** Notice the ":" at the end of the prefix, which -** is needed to separate the prefix from the -** content in cases where the content starts -** with a digit. -** -** typeof(Y)='blob' The hash is taken over prefix "Bnnn:" followed -** by the binary content of the blob. The "nnn" -** in the prefix is the minimum-length decimal -** representation of the byte-length of the blob. -** -** According to the rules above, all of the following SELECT statements -** should return TRUE: -** -** SELECT sha3(1) = sha3('1'); -** -** SELECT sha3('hello') = sha3(x'68656c6c6f'); -** -** WITH a(x) AS (VALUES('xyzzy')) -** SELECT sha3_agg(x) = sha3('T5:xyzzy') FROM a; -** -** WITH a(x) AS (VALUES(x'010203')) -** SELECT sha3_agg(x) = sha3(x'42333a010203') FROM a; -** -** WITH a(x) AS (VALUES(0x123456)) -** SELECT sha3_agg(x) = sha3(x'490000000000123456') FROM a; -** -** WITH a(x) AS (VALUES(100.015625)) -** SELECT sha3_agg(x) = sha3(x'464059010000000000') FROM a; -** -** WITH a(x) AS (VALUES(NULL)) -** SELECT sha3_agg(x) = sha3('N') FROM a; -** -** -** In sha3_query(), individual column values are encoded as with -** sha3_agg(), but with the addition that a single "R" character is -** inserted at the start of each row. -** -** Note that sha3_agg() hashes rows for which Y is NULL. Add a FILTER -** clause if NULL rows should be excluded: -** -** SELECT sha3_agg(x ORDER BY rowid) FILTER(WHERE x NOT NULL) FROM t1; -*/ -/* #include "sqlite3ext.h" */ -SQLITE_EXTENSION_INIT1 -#include -#include -#include - -#ifndef SQLITE_AMALGAMATION -/* typedef sqlite3_uint64 u64; */ -#endif /* SQLITE_AMALGAMATION */ - -/****************************************************************************** -** The Hash Engine -*/ -/* -** Macros to determine whether the machine is big or little endian, -** and whether or not that determination is run-time or compile-time. -** -** For best performance, an attempt is made to guess at the byte-order -** using C-preprocessor macros. If that is unsuccessful, or if -** -DSHA3_BYTEORDER=0 is set, then byte-order is determined -** at run-time. -*/ -#ifndef SHA3_BYTEORDER -# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ - defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ - defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ - defined(__arm__) -# define SHA3_BYTEORDER 1234 -# elif defined(sparc) || defined(__ppc__) -# define SHA3_BYTEORDER 4321 -# else -# define SHA3_BYTEORDER 0 -# endif -#endif - - -/* -** State structure for a SHA3 hash in progress -*/ -typedef struct SHA3Context SHA3Context; -struct SHA3Context { - union { - u64 s[25]; /* Keccak state. 5x5 lines of 64 bits each */ - unsigned char x[1600]; /* ... or 1600 bytes */ - } u; - unsigned nRate; /* Bytes of input accepted per Keccak iteration */ - unsigned nLoaded; /* Input bytes loaded into u.x[] so far this cycle */ - unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */ - unsigned iSize; /* 224, 256, 358, or 512 */ -}; - -/* -** A single step of the Keccak mixing function for a 1600-bit state -*/ -static void KeccakF1600Step(SHA3Context *p){ - int i; - u64 b0, b1, b2, b3, b4; - u64 c0, c1, c2, c3, c4; - u64 d0, d1, d2, d3, d4; - static const u64 RC[] = { - 0x0000000000000001ULL, 0x0000000000008082ULL, - 0x800000000000808aULL, 0x8000000080008000ULL, - 0x000000000000808bULL, 0x0000000080000001ULL, - 0x8000000080008081ULL, 0x8000000000008009ULL, - 0x000000000000008aULL, 0x0000000000000088ULL, - 0x0000000080008009ULL, 0x000000008000000aULL, - 0x000000008000808bULL, 0x800000000000008bULL, - 0x8000000000008089ULL, 0x8000000000008003ULL, - 0x8000000000008002ULL, 0x8000000000000080ULL, - 0x000000000000800aULL, 0x800000008000000aULL, - 0x8000000080008081ULL, 0x8000000000008080ULL, - 0x0000000080000001ULL, 0x8000000080008008ULL - }; -# define a00 (p->u.s[0]) -# define a01 (p->u.s[1]) -# define a02 (p->u.s[2]) -# define a03 (p->u.s[3]) -# define a04 (p->u.s[4]) -# define a10 (p->u.s[5]) -# define a11 (p->u.s[6]) -# define a12 (p->u.s[7]) -# define a13 (p->u.s[8]) -# define a14 (p->u.s[9]) -# define a20 (p->u.s[10]) -# define a21 (p->u.s[11]) -# define a22 (p->u.s[12]) -# define a23 (p->u.s[13]) -# define a24 (p->u.s[14]) -# define a30 (p->u.s[15]) -# define a31 (p->u.s[16]) -# define a32 (p->u.s[17]) -# define a33 (p->u.s[18]) -# define a34 (p->u.s[19]) -# define a40 (p->u.s[20]) -# define a41 (p->u.s[21]) -# define a42 (p->u.s[22]) -# define a43 (p->u.s[23]) -# define a44 (p->u.s[24]) -# define ROL64(a,x) ((a<>(64-x))) - - for(i=0; i<24; i+=4){ - c0 = a00^a10^a20^a30^a40; - c1 = a01^a11^a21^a31^a41; - c2 = a02^a12^a22^a32^a42; - c3 = a03^a13^a23^a33^a43; - c4 = a04^a14^a24^a34^a44; - d0 = c4^ROL64(c1, 1); - d1 = c0^ROL64(c2, 1); - d2 = c1^ROL64(c3, 1); - d3 = c2^ROL64(c4, 1); - d4 = c3^ROL64(c0, 1); - - b0 = (a00^d0); - b1 = ROL64((a11^d1), 44); - b2 = ROL64((a22^d2), 43); - b3 = ROL64((a33^d3), 21); - b4 = ROL64((a44^d4), 14); - a00 = b0 ^((~b1)& b2 ); - a00 ^= RC[i]; - a11 = b1 ^((~b2)& b3 ); - a22 = b2 ^((~b3)& b4 ); - a33 = b3 ^((~b4)& b0 ); - a44 = b4 ^((~b0)& b1 ); - - b2 = ROL64((a20^d0), 3); - b3 = ROL64((a31^d1), 45); - b4 = ROL64((a42^d2), 61); - b0 = ROL64((a03^d3), 28); - b1 = ROL64((a14^d4), 20); - a20 = b0 ^((~b1)& b2 ); - a31 = b1 ^((~b2)& b3 ); - a42 = b2 ^((~b3)& b4 ); - a03 = b3 ^((~b4)& b0 ); - a14 = b4 ^((~b0)& b1 ); - - b4 = ROL64((a40^d0), 18); - b0 = ROL64((a01^d1), 1); - b1 = ROL64((a12^d2), 6); - b2 = ROL64((a23^d3), 25); - b3 = ROL64((a34^d4), 8); - a40 = b0 ^((~b1)& b2 ); - a01 = b1 ^((~b2)& b3 ); - a12 = b2 ^((~b3)& b4 ); - a23 = b3 ^((~b4)& b0 ); - a34 = b4 ^((~b0)& b1 ); - - b1 = ROL64((a10^d0), 36); - b2 = ROL64((a21^d1), 10); - b3 = ROL64((a32^d2), 15); - b4 = ROL64((a43^d3), 56); - b0 = ROL64((a04^d4), 27); - a10 = b0 ^((~b1)& b2 ); - a21 = b1 ^((~b2)& b3 ); - a32 = b2 ^((~b3)& b4 ); - a43 = b3 ^((~b4)& b0 ); - a04 = b4 ^((~b0)& b1 ); - - b3 = ROL64((a30^d0), 41); - b4 = ROL64((a41^d1), 2); - b0 = ROL64((a02^d2), 62); - b1 = ROL64((a13^d3), 55); - b2 = ROL64((a24^d4), 39); - a30 = b0 ^((~b1)& b2 ); - a41 = b1 ^((~b2)& b3 ); - a02 = b2 ^((~b3)& b4 ); - a13 = b3 ^((~b4)& b0 ); - a24 = b4 ^((~b0)& b1 ); - - c0 = a00^a20^a40^a10^a30; - c1 = a11^a31^a01^a21^a41; - c2 = a22^a42^a12^a32^a02; - c3 = a33^a03^a23^a43^a13; - c4 = a44^a14^a34^a04^a24; - d0 = c4^ROL64(c1, 1); - d1 = c0^ROL64(c2, 1); - d2 = c1^ROL64(c3, 1); - d3 = c2^ROL64(c4, 1); - d4 = c3^ROL64(c0, 1); - - b0 = (a00^d0); - b1 = ROL64((a31^d1), 44); - b2 = ROL64((a12^d2), 43); - b3 = ROL64((a43^d3), 21); - b4 = ROL64((a24^d4), 14); - a00 = b0 ^((~b1)& b2 ); - a00 ^= RC[i+1]; - a31 = b1 ^((~b2)& b3 ); - a12 = b2 ^((~b3)& b4 ); - a43 = b3 ^((~b4)& b0 ); - a24 = b4 ^((~b0)& b1 ); - - b2 = ROL64((a40^d0), 3); - b3 = ROL64((a21^d1), 45); - b4 = ROL64((a02^d2), 61); - b0 = ROL64((a33^d3), 28); - b1 = ROL64((a14^d4), 20); - a40 = b0 ^((~b1)& b2 ); - a21 = b1 ^((~b2)& b3 ); - a02 = b2 ^((~b3)& b4 ); - a33 = b3 ^((~b4)& b0 ); - a14 = b4 ^((~b0)& b1 ); - - b4 = ROL64((a30^d0), 18); - b0 = ROL64((a11^d1), 1); - b1 = ROL64((a42^d2), 6); - b2 = ROL64((a23^d3), 25); - b3 = ROL64((a04^d4), 8); - a30 = b0 ^((~b1)& b2 ); - a11 = b1 ^((~b2)& b3 ); - a42 = b2 ^((~b3)& b4 ); - a23 = b3 ^((~b4)& b0 ); - a04 = b4 ^((~b0)& b1 ); - - b1 = ROL64((a20^d0), 36); - b2 = ROL64((a01^d1), 10); - b3 = ROL64((a32^d2), 15); - b4 = ROL64((a13^d3), 56); - b0 = ROL64((a44^d4), 27); - a20 = b0 ^((~b1)& b2 ); - a01 = b1 ^((~b2)& b3 ); - a32 = b2 ^((~b3)& b4 ); - a13 = b3 ^((~b4)& b0 ); - a44 = b4 ^((~b0)& b1 ); - - b3 = ROL64((a10^d0), 41); - b4 = ROL64((a41^d1), 2); - b0 = ROL64((a22^d2), 62); - b1 = ROL64((a03^d3), 55); - b2 = ROL64((a34^d4), 39); - a10 = b0 ^((~b1)& b2 ); - a41 = b1 ^((~b2)& b3 ); - a22 = b2 ^((~b3)& b4 ); - a03 = b3 ^((~b4)& b0 ); - a34 = b4 ^((~b0)& b1 ); - - c0 = a00^a40^a30^a20^a10; - c1 = a31^a21^a11^a01^a41; - c2 = a12^a02^a42^a32^a22; - c3 = a43^a33^a23^a13^a03; - c4 = a24^a14^a04^a44^a34; - d0 = c4^ROL64(c1, 1); - d1 = c0^ROL64(c2, 1); - d2 = c1^ROL64(c3, 1); - d3 = c2^ROL64(c4, 1); - d4 = c3^ROL64(c0, 1); - - b0 = (a00^d0); - b1 = ROL64((a21^d1), 44); - b2 = ROL64((a42^d2), 43); - b3 = ROL64((a13^d3), 21); - b4 = ROL64((a34^d4), 14); - a00 = b0 ^((~b1)& b2 ); - a00 ^= RC[i+2]; - a21 = b1 ^((~b2)& b3 ); - a42 = b2 ^((~b3)& b4 ); - a13 = b3 ^((~b4)& b0 ); - a34 = b4 ^((~b0)& b1 ); - - b2 = ROL64((a30^d0), 3); - b3 = ROL64((a01^d1), 45); - b4 = ROL64((a22^d2), 61); - b0 = ROL64((a43^d3), 28); - b1 = ROL64((a14^d4), 20); - a30 = b0 ^((~b1)& b2 ); - a01 = b1 ^((~b2)& b3 ); - a22 = b2 ^((~b3)& b4 ); - a43 = b3 ^((~b4)& b0 ); - a14 = b4 ^((~b0)& b1 ); - - b4 = ROL64((a10^d0), 18); - b0 = ROL64((a31^d1), 1); - b1 = ROL64((a02^d2), 6); - b2 = ROL64((a23^d3), 25); - b3 = ROL64((a44^d4), 8); - a10 = b0 ^((~b1)& b2 ); - a31 = b1 ^((~b2)& b3 ); - a02 = b2 ^((~b3)& b4 ); - a23 = b3 ^((~b4)& b0 ); - a44 = b4 ^((~b0)& b1 ); - - b1 = ROL64((a40^d0), 36); - b2 = ROL64((a11^d1), 10); - b3 = ROL64((a32^d2), 15); - b4 = ROL64((a03^d3), 56); - b0 = ROL64((a24^d4), 27); - a40 = b0 ^((~b1)& b2 ); - a11 = b1 ^((~b2)& b3 ); - a32 = b2 ^((~b3)& b4 ); - a03 = b3 ^((~b4)& b0 ); - a24 = b4 ^((~b0)& b1 ); - - b3 = ROL64((a20^d0), 41); - b4 = ROL64((a41^d1), 2); - b0 = ROL64((a12^d2), 62); - b1 = ROL64((a33^d3), 55); - b2 = ROL64((a04^d4), 39); - a20 = b0 ^((~b1)& b2 ); - a41 = b1 ^((~b2)& b3 ); - a12 = b2 ^((~b3)& b4 ); - a33 = b3 ^((~b4)& b0 ); - a04 = b4 ^((~b0)& b1 ); - - c0 = a00^a30^a10^a40^a20; - c1 = a21^a01^a31^a11^a41; - c2 = a42^a22^a02^a32^a12; - c3 = a13^a43^a23^a03^a33; - c4 = a34^a14^a44^a24^a04; - d0 = c4^ROL64(c1, 1); - d1 = c0^ROL64(c2, 1); - d2 = c1^ROL64(c3, 1); - d3 = c2^ROL64(c4, 1); - d4 = c3^ROL64(c0, 1); - - b0 = (a00^d0); - b1 = ROL64((a01^d1), 44); - b2 = ROL64((a02^d2), 43); - b3 = ROL64((a03^d3), 21); - b4 = ROL64((a04^d4), 14); - a00 = b0 ^((~b1)& b2 ); - a00 ^= RC[i+3]; - a01 = b1 ^((~b2)& b3 ); - a02 = b2 ^((~b3)& b4 ); - a03 = b3 ^((~b4)& b0 ); - a04 = b4 ^((~b0)& b1 ); - - b2 = ROL64((a10^d0), 3); - b3 = ROL64((a11^d1), 45); - b4 = ROL64((a12^d2), 61); - b0 = ROL64((a13^d3), 28); - b1 = ROL64((a14^d4), 20); - a10 = b0 ^((~b1)& b2 ); - a11 = b1 ^((~b2)& b3 ); - a12 = b2 ^((~b3)& b4 ); - a13 = b3 ^((~b4)& b0 ); - a14 = b4 ^((~b0)& b1 ); - - b4 = ROL64((a20^d0), 18); - b0 = ROL64((a21^d1), 1); - b1 = ROL64((a22^d2), 6); - b2 = ROL64((a23^d3), 25); - b3 = ROL64((a24^d4), 8); - a20 = b0 ^((~b1)& b2 ); - a21 = b1 ^((~b2)& b3 ); - a22 = b2 ^((~b3)& b4 ); - a23 = b3 ^((~b4)& b0 ); - a24 = b4 ^((~b0)& b1 ); - - b1 = ROL64((a30^d0), 36); - b2 = ROL64((a31^d1), 10); - b3 = ROL64((a32^d2), 15); - b4 = ROL64((a33^d3), 56); - b0 = ROL64((a34^d4), 27); - a30 = b0 ^((~b1)& b2 ); - a31 = b1 ^((~b2)& b3 ); - a32 = b2 ^((~b3)& b4 ); - a33 = b3 ^((~b4)& b0 ); - a34 = b4 ^((~b0)& b1 ); - - b3 = ROL64((a40^d0), 41); - b4 = ROL64((a41^d1), 2); - b0 = ROL64((a42^d2), 62); - b1 = ROL64((a43^d3), 55); - b2 = ROL64((a44^d4), 39); - a40 = b0 ^((~b1)& b2 ); - a41 = b1 ^((~b2)& b3 ); - a42 = b2 ^((~b3)& b4 ); - a43 = b3 ^((~b4)& b0 ); - a44 = b4 ^((~b0)& b1 ); - } -} - -/* -** Initialize a new hash. iSize determines the size of the hash -** in bits and should be one of 224, 256, 384, or 512. Or iSize -** can be zero to use the default hash size of 256 bits. -*/ -static void SHA3Init(SHA3Context *p, int iSize){ - memset(p, 0, sizeof(*p)); - p->iSize = iSize; - if( iSize>=128 && iSize<=512 ){ - p->nRate = (1600 - ((iSize + 31)&~31)*2)/8; - }else{ - p->nRate = (1600 - 2*256)/8; - } -#if SHA3_BYTEORDER==1234 - /* Known to be little-endian at compile-time. No-op */ -#elif SHA3_BYTEORDER==4321 - p->ixMask = 7; /* Big-endian */ -#else - { - static unsigned int one = 1; - if( 1==*(unsigned char*)&one ){ - /* Little endian. No byte swapping. */ - p->ixMask = 0; - }else{ - /* Big endian. Byte swap. */ - p->ixMask = 7; - } - } -#endif -} - -/* -** Make consecutive calls to the SHA3Update function to add new content -** to the hash -*/ -static void SHA3Update( - SHA3Context *p, - const unsigned char *aData, - unsigned int nData -){ - unsigned int i = 0; - if( aData==0 ) return; -#if SHA3_BYTEORDER==1234 - if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){ - for(; i+7u.s[p->nLoaded/8] ^= *(u64*)&aData[i]; - p->nLoaded += 8; - if( p->nLoaded>=p->nRate ){ - KeccakF1600Step(p); - p->nLoaded = 0; - } - } - } -#endif - for(; iu.x[p->nLoaded] ^= aData[i]; -#elif SHA3_BYTEORDER==4321 - p->u.x[p->nLoaded^0x07] ^= aData[i]; -#else - p->u.x[p->nLoaded^p->ixMask] ^= aData[i]; -#endif - p->nLoaded++; - if( p->nLoaded==p->nRate ){ - KeccakF1600Step(p); - p->nLoaded = 0; - } - } -} - -/* -** After all content has been added, invoke SHA3Final() to compute -** the final hash. The function returns a pointer to the binary -** hash value. -*/ -static unsigned char *SHA3Final(SHA3Context *p){ - unsigned int i; - if( p->nLoaded==p->nRate-1 ){ - const unsigned char c1 = 0x86; - SHA3Update(p, &c1, 1); - }else{ - const unsigned char c2 = 0x06; - const unsigned char c3 = 0x80; - SHA3Update(p, &c2, 1); - p->nLoaded = p->nRate - 1; - SHA3Update(p, &c3, 1); - } - for(i=0; inRate; i++){ - p->u.x[i+p->nRate] = p->u.x[i^p->ixMask]; - } - return &p->u.x[p->nRate]; -} -/* End of the hashing logic -*****************************************************************************/ - -/* -** Implementation of the sha3(X,SIZE) function. -** -** Return a BLOB which is the SIZE-bit SHA3 hash of X. The default -** size is 256. If X is a BLOB, it is hashed as is. -** For all other non-NULL types of input, X is converted into a UTF-8 string -** and the string is hashed without the trailing 0x00 terminator. The hash -** of a NULL value is NULL. -*/ -static void sha3Func( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - SHA3Context cx; - int eType = sqlite3_value_type(argv[0]); - int nByte = sqlite3_value_bytes(argv[0]); - int iSize; - if( argc==1 ){ - iSize = 256; - }else{ - iSize = sqlite3_value_int(argv[1]); - if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){ - sqlite3_result_error(context, "SHA3 size should be one of: 224 256 " - "384 512", -1); - return; - } - } - if( eType==SQLITE_NULL ) return; - SHA3Init(&cx, iSize); - if( eType==SQLITE_BLOB ){ - SHA3Update(&cx, sqlite3_value_blob(argv[0]), nByte); - }else{ - SHA3Update(&cx, sqlite3_value_text(argv[0]), nByte); - } - sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT); -} - -/* Compute a string using sqlite3_vsnprintf() with a maximum length -** of 50 bytes and add it to the hash. -*/ -static void sha3_step_vformat( - SHA3Context *p, /* Add content to this context */ - const char *zFormat, - ... -){ - va_list ap; - int n; - char zBuf[50]; - va_start(ap, zFormat); - sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap); - va_end(ap); - n = (int)strlen(zBuf); - SHA3Update(p, (unsigned char*)zBuf, n); -} - -/* -** Update a SHA3Context using a single sqlite3_value. -*/ -static void sha3UpdateFromValue(SHA3Context *p, sqlite3_value *pVal){ - switch( sqlite3_value_type(pVal) ){ - case SQLITE_NULL: { - SHA3Update(p, (const unsigned char*)"N",1); - break; - } - case SQLITE_INTEGER: { - sqlite3_uint64 u; - int j; - unsigned char x[9]; - sqlite3_int64 v = sqlite3_value_int64(pVal); - memcpy(&u, &v, 8); - for(j=8; j>=1; j--){ - x[j] = u & 0xff; - u >>= 8; - } - x[0] = 'I'; - SHA3Update(p, x, 9); - break; - } - case SQLITE_FLOAT: { - sqlite3_uint64 u; - int j; - unsigned char x[9]; - double r = sqlite3_value_double(pVal); - memcpy(&u, &r, 8); - for(j=8; j>=1; j--){ - x[j] = u & 0xff; - u >>= 8; - } - x[0] = 'F'; - SHA3Update(p,x,9); - break; - } - case SQLITE_TEXT: { - int n2 = sqlite3_value_bytes(pVal); - const unsigned char *z2 = sqlite3_value_text(pVal); - sha3_step_vformat(p,"T%d:",n2); - SHA3Update(p, z2, n2); - break; - } - case SQLITE_BLOB: { - int n2 = sqlite3_value_bytes(pVal); - const unsigned char *z2 = sqlite3_value_blob(pVal); - sha3_step_vformat(p,"B%d:",n2); - SHA3Update(p, z2, n2); - break; - } - } -} - -/* -** Implementation of the sha3_query(SQL,SIZE) function. -** -** This function compiles and runs the SQL statement(s) given in the -** argument. The results are hashed using a SIZE-bit SHA3. The default -** size is 256. -** -** The format of the byte stream that is hashed is summarized as follows: -** -** S: -** R -** N -** I -** F -** B: -** T: -** -** is the original SQL text for each statement run and is -** the size of that text. The SQL text is UTF-8. A single R character -** occurs before the start of each row. N means a NULL value. -** I mean an 8-byte little-endian integer . F is a floating point -** number with an 8-byte little-endian IEEE floating point value . -** B means blobs of bytes. T means text rendered as -** bytes of UTF-8. The and values are expressed as an ASCII -** text integers. -** -** For each SQL statement in the X input, there is one S segment. Each -** S segment is followed by zero or more R segments, one for each row in the -** result set. After each R, there are one or more N, I, F, B, or T segments, -** one for each column in the result set. Segments are concatentated directly -** with no delimiters of any kind. -*/ -static void sha3QueryFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - sqlite3 *db = sqlite3_context_db_handle(context); - const char *zSql = (const char*)sqlite3_value_text(argv[0]); - sqlite3_stmt *pStmt = 0; - int nCol; /* Number of columns in the result set */ - int i; /* Loop counter */ - int rc; - int n; - const char *z; - SHA3Context cx; - int iSize; - - if( argc==1 ){ - iSize = 256; - }else{ - iSize = sqlite3_value_int(argv[1]); - if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){ - sqlite3_result_error(context, "SHA3 size should be one of: 224 256 " - "384 512", -1); - return; - } - } - if( zSql==0 ) return; - SHA3Init(&cx, iSize); - while( zSql[0] ){ - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql); - if( rc ){ - char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s", - zSql, sqlite3_errmsg(db)); - sqlite3_finalize(pStmt); - sqlite3_result_error(context, zMsg, -1); - sqlite3_free(zMsg); - return; - } - if( !sqlite3_stmt_readonly(pStmt) ){ - char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt)); - sqlite3_finalize(pStmt); - sqlite3_result_error(context, zMsg, -1); - sqlite3_free(zMsg); - return; - } - nCol = sqlite3_column_count(pStmt); - z = sqlite3_sql(pStmt); - if( z ){ - n = (int)strlen(z); - sha3_step_vformat(&cx,"S%d:",n); - SHA3Update(&cx,(unsigned char*)z,n); - } - - /* Compute a hash over the result of the query */ - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - SHA3Update(&cx,(const unsigned char*)"R",1); - for(i=0; inRate==0 ){ - int sz = 256; - if( argc==2 ){ - sz = sqlite3_value_int(argv[1]); - if( sz!=224 && sz!=384 && sz!=512 ){ - sz = 256; - } - } - SHA3Init(p, sz); - } - sha3UpdateFromValue(p, argv[0]); -} - - -/* -** xFinal function for sha3_agg(). -*/ -static void sha3AggFinal(sqlite3_context *context){ - SHA3Context *p; - p = (SHA3Context*)sqlite3_aggregate_context(context, sizeof(*p)); - if( p==0 ) return; - if( p->iSize ){ - sqlite3_result_blob(context, SHA3Final(p), p->iSize/8, SQLITE_TRANSIENT); - } -} - - - -#ifdef _WIN32 - -#endif -int sqlite3_shathree_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi -){ - int rc = SQLITE_OK; - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErrMsg; /* Unused parameter */ - rc = sqlite3_create_function(db, "sha3", 1, - SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC, - 0, sha3Func, 0, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "sha3", 2, - SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC, - 0, sha3Func, 0, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "sha3_agg", 1, - SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC, - 0, 0, sha3AggStep, sha3AggFinal); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "sha3_agg", 2, - SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC, - 0, 0, sha3AggStep, sha3AggFinal); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "sha3_query", 1, - SQLITE_UTF8 | SQLITE_DIRECTONLY, - 0, sha3QueryFunc, 0, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "sha3_query", 2, - SQLITE_UTF8 | SQLITE_DIRECTONLY, - 0, sha3QueryFunc, 0, 0); - } - return rc; -} - -/************************* End ext/misc/shathree.c ********************/ -/************************* Begin ext/misc/sha1.c ******************/ -/* -** 2017-01-27 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This SQLite extension implements functions that compute SHA1 hashes. -** Two SQL functions are implemented: -** -** sha1(X) -** sha1_query(Y) -** -** The sha1(X) function computes the SHA1 hash of the input X, or NULL if -** X is NULL. -** -** The sha1_query(Y) function evalutes all queries in the SQL statements of Y -** and returns a hash of their results. -*/ -/* #include "sqlite3ext.h" */ -SQLITE_EXTENSION_INIT1 -#include -#include -#include - -/****************************************************************************** -** The Hash Engine -*/ -/* Context for the SHA1 hash */ -typedef struct SHA1Context SHA1Context; -struct SHA1Context { - unsigned int state[5]; - unsigned int count[2]; - unsigned char buffer[64]; -}; - -#define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r)) -#define rol(x,k) SHA_ROT(x,k,32-(k)) -#define ror(x,k) SHA_ROT(x,32-(k),k) - -#define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \ - |(rol(block[i],8)&0x00FF00FF)) -#define blk0be(i) block[i] -#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \ - ^block[(i+2)&15]^block[i&15],1)) - -/* - * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1 - * - * Rl0() for little-endian and Rb0() for big-endian. Endianness is - * determined at run-time. - */ -#define Rl0(v,w,x,y,z,i) \ - z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2); -#define Rb0(v,w,x,y,z,i) \ - z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v,5);w=ror(w,2); -#define R1(v,w,x,y,z,i) \ - z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=ror(w,2); -#define R2(v,w,x,y,z,i) \ - z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=ror(w,2); -#define R3(v,w,x,y,z,i) \ - z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=ror(w,2); -#define R4(v,w,x,y,z,i) \ - z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2); - -/* - * Hash a single 512-bit block. This is the core of the algorithm. - */ -static void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]){ - unsigned int qq[5]; /* a, b, c, d, e; */ - static int one = 1; - unsigned int block[16]; - memcpy(block, buffer, 64); - memcpy(qq,state,5*sizeof(unsigned int)); - -#define a qq[0] -#define b qq[1] -#define c qq[2] -#define d qq[3] -#define e qq[4] - - /* Copy p->state[] to working vars */ - /* - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - */ - - /* 4 rounds of 20 operations each. Loop unrolled. */ - if( 1 == *(unsigned char*)&one ){ - Rl0(a,b,c,d,e, 0); Rl0(e,a,b,c,d, 1); Rl0(d,e,a,b,c, 2); Rl0(c,d,e,a,b, 3); - Rl0(b,c,d,e,a, 4); Rl0(a,b,c,d,e, 5); Rl0(e,a,b,c,d, 6); Rl0(d,e,a,b,c, 7); - Rl0(c,d,e,a,b, 8); Rl0(b,c,d,e,a, 9); Rl0(a,b,c,d,e,10); Rl0(e,a,b,c,d,11); - Rl0(d,e,a,b,c,12); Rl0(c,d,e,a,b,13); Rl0(b,c,d,e,a,14); Rl0(a,b,c,d,e,15); - }else{ - Rb0(a,b,c,d,e, 0); Rb0(e,a,b,c,d, 1); Rb0(d,e,a,b,c, 2); Rb0(c,d,e,a,b, 3); - Rb0(b,c,d,e,a, 4); Rb0(a,b,c,d,e, 5); Rb0(e,a,b,c,d, 6); Rb0(d,e,a,b,c, 7); - Rb0(c,d,e,a,b, 8); Rb0(b,c,d,e,a, 9); Rb0(a,b,c,d,e,10); Rb0(e,a,b,c,d,11); - Rb0(d,e,a,b,c,12); Rb0(c,d,e,a,b,13); Rb0(b,c,d,e,a,14); Rb0(a,b,c,d,e,15); - } - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - -#undef a -#undef b -#undef c -#undef d -#undef e -} - - -/* Initialize a SHA1 context */ -static void hash_init(SHA1Context *p){ - /* SHA1 initialization constants */ - p->state[0] = 0x67452301; - p->state[1] = 0xEFCDAB89; - p->state[2] = 0x98BADCFE; - p->state[3] = 0x10325476; - p->state[4] = 0xC3D2E1F0; - p->count[0] = p->count[1] = 0; -} - -/* Add new content to the SHA1 hash */ -static void hash_step( - SHA1Context *p, /* Add content to this context */ - const unsigned char *data, /* Data to be added */ - unsigned int len /* Number of bytes in data */ -){ - unsigned int i, j; - - j = p->count[0]; - if( (p->count[0] += len << 3) < j ){ - p->count[1] += (len>>29)+1; - } - j = (j >> 3) & 63; - if( (j + len) > 63 ){ - (void)memcpy(&p->buffer[j], data, (i = 64-j)); - SHA1Transform(p->state, p->buffer); - for(; i + 63 < len; i += 64){ - SHA1Transform(p->state, &data[i]); - } - j = 0; - }else{ - i = 0; - } - (void)memcpy(&p->buffer[j], &data[i], len - i); -} - -/* Compute a string using sqlite3_vsnprintf() and hash it */ -static void hash_step_vformat( - SHA1Context *p, /* Add content to this context */ - const char *zFormat, - ... -){ - va_list ap; - int n; - char zBuf[50]; - va_start(ap, zFormat); - sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap); - va_end(ap); - n = (int)strlen(zBuf); - hash_step(p, (unsigned char*)zBuf, n); -} - - -/* Add padding and compute the message digest. Render the -** message digest as lower-case hexadecimal and put it into -** zOut[]. zOut[] must be at least 41 bytes long. */ -static void hash_finish( - SHA1Context *p, /* The SHA1 context to finish and render */ - char *zOut, /* Store hex or binary hash here */ - int bAsBinary /* 1 for binary hash, 0 for hex hash */ -){ - unsigned int i; - unsigned char finalcount[8]; - unsigned char digest[20]; - static const char zEncode[] = "0123456789abcdef"; - - for (i = 0; i < 8; i++){ - finalcount[i] = (unsigned char)((p->count[(i >= 4 ? 0 : 1)] - >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ - } - hash_step(p, (const unsigned char *)"\200", 1); - while ((p->count[0] & 504) != 448){ - hash_step(p, (const unsigned char *)"\0", 1); - } - hash_step(p, finalcount, 8); /* Should cause a SHA1Transform() */ - for (i = 0; i < 20; i++){ - digest[i] = (unsigned char)((p->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); - } - if( bAsBinary ){ - memcpy(zOut, digest, 20); - }else{ - for(i=0; i<20; i++){ - zOut[i*2] = zEncode[(digest[i]>>4)&0xf]; - zOut[i*2+1] = zEncode[digest[i] & 0xf]; - } - zOut[i*2]= 0; - } -} -/* End of the hashing logic -*****************************************************************************/ - -/* -** Two SQL functions: sha1(X) and sha1b(X). -** -** sha1(X) returns a lower-case hexadecimal rendering of the SHA1 hash -** of the argument X. If X is a BLOB, it is hashed as is. For all other -** types of input, X is converted into a UTF-8 string and the string -** is hashed without the trailing 0x00 terminator. The hash of a NULL -** value is NULL. -** -** sha1b(X) is the same except that it returns a 20-byte BLOB containing -** the binary hash instead of a hexadecimal string. -*/ -static void sha1Func( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - SHA1Context cx; - int eType = sqlite3_value_type(argv[0]); - int nByte = sqlite3_value_bytes(argv[0]); - const unsigned char *pData; - char zOut[44]; - - assert( argc==1 ); - if( eType==SQLITE_NULL ) return; - hash_init(&cx); - if( eType==SQLITE_BLOB ){ - pData = (const unsigned char*)sqlite3_value_blob(argv[0]); - }else{ - pData = (const unsigned char*)sqlite3_value_text(argv[0]); - } - if( pData==0 ) return; - hash_step(&cx, pData, nByte); - if( sqlite3_user_data(context)!=0 ){ - /* sha1b() - binary result */ - hash_finish(&cx, zOut, 1); - sqlite3_result_blob(context, zOut, 20, SQLITE_TRANSIENT); - }else{ - /* sha1() - hexadecimal text result */ - hash_finish(&cx, zOut, 0); - sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT); - } -} - -/* -** Implementation of the sha1_query(SQL) function. -** -** This function compiles and runs the SQL statement(s) given in the -** argument. The results are hashed using SHA1 and that hash is returned. -** -** The original SQL text is included as part of the hash. -** -** The hash is not just a concatenation of the outputs. Each query -** is delimited and each row and value within the query is delimited, -** with all values being marked with their datatypes. -*/ -static void sha1QueryFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - sqlite3 *db = sqlite3_context_db_handle(context); - const char *zSql = (const char*)sqlite3_value_text(argv[0]); - sqlite3_stmt *pStmt = 0; - int nCol; /* Number of columns in the result set */ - int i; /* Loop counter */ - int rc; - int n; - const char *z; - SHA1Context cx; - char zOut[44]; - - assert( argc==1 ); - if( zSql==0 ) return; - hash_init(&cx); - while( zSql[0] ){ - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql); - if( rc ){ - char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s", - zSql, sqlite3_errmsg(db)); - sqlite3_finalize(pStmt); - sqlite3_result_error(context, zMsg, -1); - sqlite3_free(zMsg); - return; - } - if( !sqlite3_stmt_readonly(pStmt) ){ - char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt)); - sqlite3_finalize(pStmt); - sqlite3_result_error(context, zMsg, -1); - sqlite3_free(zMsg); - return; - } - nCol = sqlite3_column_count(pStmt); - z = sqlite3_sql(pStmt); - if( z==0 ) z = ""; - n = (int)strlen(z); - hash_step_vformat(&cx,"S%d:",n); - hash_step(&cx,(unsigned char*)z,n); - - /* Compute a hash over the result of the query */ - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - hash_step(&cx,(const unsigned char*)"R",1); - for(i=0; i=1; j--){ - x[j] = u & 0xff; - u >>= 8; - } - x[0] = 'I'; - hash_step(&cx, x, 9); - break; - } - case SQLITE_FLOAT: { - sqlite3_uint64 u; - int j; - unsigned char x[9]; - double r = sqlite3_column_double(pStmt,i); - memcpy(&u, &r, 8); - for(j=8; j>=1; j--){ - x[j] = u & 0xff; - u >>= 8; - } - x[0] = 'F'; - hash_step(&cx,x,9); - break; - } - case SQLITE_TEXT: { - int n2 = sqlite3_column_bytes(pStmt, i); - const unsigned char *z2 = sqlite3_column_text(pStmt, i); - hash_step_vformat(&cx,"T%d:",n2); - hash_step(&cx, z2, n2); - break; - } - case SQLITE_BLOB: { - int n2 = sqlite3_column_bytes(pStmt, i); - const unsigned char *z2 = sqlite3_column_blob(pStmt, i); - hash_step_vformat(&cx,"B%d:",n2); - hash_step(&cx, z2, n2); - break; - } - } - } - } - sqlite3_finalize(pStmt); - } - hash_finish(&cx, zOut, 0); - sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT); -} - - -#ifdef _WIN32 - -#endif -int sqlite3_sha_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi -){ - int rc = SQLITE_OK; - static int one = 1; - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErrMsg; /* Unused parameter */ - rc = sqlite3_create_function(db, "sha1", 1, - SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC, - 0, sha1Func, 0, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "sha1b", 1, - SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC, - (void*)&one, sha1Func, 0, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "sha1_query", 1, - SQLITE_UTF8|SQLITE_DIRECTONLY, 0, - sha1QueryFunc, 0, 0); - } - return rc; -} - -/************************* End ext/misc/sha1.c ********************/ -/************************* Begin ext/misc/uint.c ******************/ -/* -** 2020-04-14 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This SQLite extension implements the UINT collating sequence. -** -** UINT works like BINARY for text, except that embedded strings -** of digits compare in numeric order. -** -** * Leading zeros are handled properly, in the sense that -** they do not mess of the magnitude comparison of embedded -** strings of digits. "x00123y" is equal to "x123y". -** -** * Only unsigned integers are recognized. Plus and minus -** signs are ignored. Decimal points and exponential notation -** are ignored. -** -** * Embedded integers can be of arbitrary length. Comparison -** is *not* limited integers that can be expressed as a -** 64-bit machine integer. -*/ -/* #include "sqlite3ext.h" */ -SQLITE_EXTENSION_INIT1 -#include -#include -#include - -/* -** Compare text in lexicographic order, except strings of digits -** compare in numeric order. -*/ -static int uintCollFunc( - void *notUsed, - int nKey1, const void *pKey1, - int nKey2, const void *pKey2 -){ - const unsigned char *zA = (const unsigned char*)pKey1; - const unsigned char *zB = (const unsigned char*)pKey2; - int i=0, j=0, x; - (void)notUsed; - while( i -#include -#include -#include - -/* Mark a function parameter as unused, to suppress nuisance compiler -** warnings. */ -#ifndef UNUSED_PARAMETER -# define UNUSED_PARAMETER(X) (void)(X) -#endif - -#ifndef IsSpace -#define IsSpace(X) isspace((unsigned char)X) -#endif - -#ifndef SQLITE_DECIMAL_MAX_DIGIT -# define SQLITE_DECIMAL_MAX_DIGIT 10000000 -#endif - -/* A decimal object */ -typedef struct Decimal Decimal; -struct Decimal { - char sign; /* 0 for positive, 1 for negative */ - char oom; /* True if an OOM is encountered */ - char isNull; /* True if holds a NULL rather than a number */ - char isInit; /* True upon initialization */ - int nDigit; /* Total number of digits */ - int nFrac; /* Number of digits to the right of the decimal point */ - signed char *a; /* Array of digits. Most significant first. */ -}; - -/* -** Release memory held by a Decimal, but do not free the object itself. -*/ -static void decimal_clear(Decimal *p){ - sqlite3_free(p->a); -} - -/* -** Destroy a Decimal object -*/ -static void decimal_free(Decimal *p){ - if( p ){ - decimal_clear(p); - sqlite3_free(p); - } -} - -/* -** Allocate a new Decimal object initialized to the text in zIn[]. -** Return NULL if any kind of error occurs. -*/ -static Decimal *decimalNewFromText(const char *zIn, int n){ - Decimal *p = 0; - int i; - int iExp = 0; - - if( zIn==0 ) goto new_from_text_failed; - p = sqlite3_malloc64( sizeof(*p) ); - if( p==0 ) goto new_from_text_failed; - p->sign = 0; - p->oom = 0; - p->isInit = 1; - p->isNull = 0; - p->nDigit = 0; - p->nFrac = 0; - p->a = sqlite3_malloc64( n+1 ); - if( p->a==0 ) goto new_from_text_failed; - for(i=0; IsSpace(zIn[i]); i++){} - if( zIn[i]=='-' ){ - p->sign = 1; - i++; - }else if( zIn[i]=='+' ){ - i++; - } - while( i='0' && c<='9' ){ - p->a[p->nDigit++] = c - '0'; - }else if( c=='.' ){ - p->nFrac = p->nDigit + 1; - }else if( c=='e' || c=='E' ){ - int j = i+1; - int neg = 0; - if( j>=n ) break; - if( zIn[j]=='-' ){ - neg = 1; - j++; - }else if( zIn[j]=='+' ){ - j++; - } - while( j='0' && zIn[j]<='9' ){ - iExp = iExp*10 + zIn[j] - '0'; - } - j++; - } - if( neg ) iExp = -iExp; - break; - } - i++; - } - if( p->nFrac ){ - p->nFrac = p->nDigit - (p->nFrac - 1); - } - if( iExp>0 ){ - if( p->nFrac>0 ){ - if( iExp<=p->nFrac ){ - p->nFrac -= iExp; - iExp = 0; - }else{ - iExp -= p->nFrac; - p->nFrac = 0; - } - } - if( iExp>0 ){ - signed char *a = sqlite3_realloc64(p->a, (sqlite3_int64)p->nDigit - + (sqlite3_int64)iExp + 1 ); - if( a==0 ) goto new_from_text_failed; - p->a = a; - memset(p->a+p->nDigit, 0, iExp); - p->nDigit += iExp; - } - }else if( iExp<0 ){ - int nExtra; - iExp = -iExp; - nExtra = p->nDigit - p->nFrac - 1; - if( nExtra ){ - if( nExtra>=iExp ){ - p->nFrac += iExp; - iExp = 0; - }else{ - iExp -= nExtra; - p->nFrac = p->nDigit - 1; - } - } - if( iExp>0 ){ - signed char *a = sqlite3_realloc64(p->a, (sqlite3_int64)p->nDigit - + (sqlite3_int64)iExp + 1 ); - if( a==0 ) goto new_from_text_failed; - p->a = a; - memmove(p->a+iExp, p->a, p->nDigit); - memset(p->a, 0, iExp); - p->nDigit += iExp; - p->nFrac += iExp; - } - } - if( p->sign ){ - for(i=0; inDigit && p->a[i]==0; i++){} - if( i>=p->nDigit ) p->sign = 0; - } - if( p->nDigit>SQLITE_DECIMAL_MAX_DIGIT ) goto new_from_text_failed; - return p; - -new_from_text_failed: - if( p ){ - if( p->a ) sqlite3_free(p->a); - sqlite3_free(p); - } - return 0; -} - -/* Forward reference */ -static Decimal *decimalFromDouble(double); - -/* -** Allocate a new Decimal object from an sqlite3_value. Return a pointer -** to the new object, or NULL if there is an error. If the pCtx argument -** is not NULL, then errors are reported on it as well. -** -** If the pIn argument is SQLITE_TEXT or SQLITE_INTEGER, it is converted -** directly into a Decimal. For SQLITE_FLOAT or for SQLITE_BLOB of length -** 8 bytes, the resulting double value is expanded into its decimal equivalent. -** If pIn is NULL or if it is a BLOB that is not exactly 8 bytes in length, -** then NULL is returned. -*/ -static Decimal *decimal_new( - sqlite3_context *pCtx, /* Report error here, if not null */ - sqlite3_value *pIn, /* Construct the decimal object from this */ - int bTextOnly /* Always interpret pIn as text if true */ -){ - Decimal *p = 0; - int eType = sqlite3_value_type(pIn); - if( bTextOnly && (eType==SQLITE_FLOAT || eType==SQLITE_BLOB) ){ - eType = SQLITE_TEXT; - } - switch( eType ){ - case SQLITE_TEXT: - case SQLITE_INTEGER: { - const char *zIn = (const char*)sqlite3_value_text(pIn); - int n = sqlite3_value_bytes(pIn); - p = decimalNewFromText(zIn, n); - if( p==0 ) goto new_failed; - break; - } - - case SQLITE_FLOAT: { - p = decimalFromDouble(sqlite3_value_double(pIn)); - break; - } - - case SQLITE_BLOB: { - const unsigned char *x; - unsigned int i; - sqlite3_uint64 v = 0; - double r; - - if( sqlite3_value_bytes(pIn)!=sizeof(r) ) break; - x = sqlite3_value_blob(pIn); - for(i=0; ioom ){ - sqlite3_result_error_nomem(pCtx); - return; - } - if( p->isNull ){ - sqlite3_result_null(pCtx); - return; - } - z = sqlite3_malloc64( (sqlite3_int64)p->nDigit+4 ); - if( z==0 ){ - sqlite3_result_error_nomem(pCtx); - return; - } - i = 0; - if( p->nDigit==0 || (p->nDigit==1 && p->a[0]==0) ){ - p->sign = 0; - } - if( p->sign ){ - z[0] = '-'; - i = 1; - } - n = p->nDigit - p->nFrac; - if( n<=0 ){ - z[i++] = '0'; - } - j = 0; - while( n>1 && p->a[j]==0 ){ - j++; - n--; - } - while( n>0 ){ - z[i++] = p->a[j] + '0'; - j++; - n--; - } - if( p->nFrac ){ - z[i++] = '.'; - do{ - z[i++] = p->a[j] + '0'; - j++; - }while( jnDigit ); - } - z[i] = 0; - sqlite3_result_text(pCtx, z, i, sqlite3_free); -} - -/* -** Round a decimal value to N significant digits. N must be positive. -*/ -static void decimal_round(Decimal *p, int N){ - int i; - int nZero; - if( N<1 ) return; - if( p==0 ) return; - if( p->nDigit<=N ) return; - for(nZero=0; nZeronDigit && p->a[nZero]==0; nZero++){} - N += nZero; - if( p->nDigit<=N ) return; - if( p->a[N]>4 ){ - p->a[N-1]++; - for(i=N-1; i>0 && p->a[i]>9; i--){ - p->a[i] = 0; - p->a[i-1]++; - } - if( p->a[0]>9 ){ - p->a[0] = 1; - p->nFrac--; - } - } - memset(&p->a[N], 0, p->nDigit - N); -} - -/* -** Make the given Decimal the result in an format similar to '%+#e'. -** In other words, show exponential notation with leading and trailing -** zeros omitted. -*/ -static void decimal_result_sci(sqlite3_context *pCtx, Decimal *p, int N){ - char *z; /* The output buffer */ - int i; /* Loop counter */ - int nZero; /* Number of leading zeros */ - int nDigit; /* Number of digits not counting trailing zeros */ - int nFrac; /* Digits to the right of the decimal point */ - int exp; /* Exponent value */ - signed char zero; /* Zero value */ - signed char *a; /* Array of digits */ - - if( p==0 || p->oom ){ - sqlite3_result_error_nomem(pCtx); - return; - } - if( p->isNull ){ - sqlite3_result_null(pCtx); - return; - } - if( N<1 ) N = 0; - for(nDigit=p->nDigit; nDigit>N && p->a[nDigit-1]==0; nDigit--){} - for(nZero=0; nZeroa[nZero]==0; nZero++){} - nFrac = p->nFrac + (nDigit - p->nDigit); - nDigit -= nZero; - z = sqlite3_malloc64( (sqlite3_int64)nDigit+20 ); - if( z==0 ){ - sqlite3_result_error_nomem(pCtx); - return; - } - if( nDigit==0 ){ - zero = 0; - a = &zero; - nDigit = 1; - nFrac = 0; - }else{ - a = &p->a[nZero]; - } - if( p->sign && nDigit>0 ){ - z[0] = '-'; - }else{ - z[0] = '+'; - } - z[1] = a[0]+'0'; - z[2] = '.'; - if( nDigit==1 ){ - z[3] = '0'; - i = 4; - }else{ - for(i=1; iisNull==0 -** pB!=0 -** pB->isNull==0 -*/ -static int decimal_cmp(Decimal *pA, Decimal *pB){ - int nASig, nBSig, rc, n; - while( pA->nFrac>0 && pA->a[pA->nDigit-1]==0 ){ - pA->nDigit--; - pA->nFrac--; - } - while( pB->nFrac>0 && pB->a[pB->nDigit-1]==0 ){ - pB->nDigit--; - pB->nFrac--; - } - if( pA->sign!=pB->sign ){ - return pA->sign ? -1 : +1; - } - if( pA->sign ){ - Decimal *pTemp = pA; - pA = pB; - pB = pTemp; - } - nASig = pA->nDigit - pA->nFrac; - nBSig = pB->nDigit - pB->nFrac; - if( nASig!=nBSig ){ - return nASig - nBSig; - } - n = pA->nDigit; - if( n>pB->nDigit ) n = pB->nDigit; - rc = memcmp(pA->a, pB->a, n); - if( rc==0 ){ - rc = pA->nDigit - pB->nDigit; - } - return rc; -} - -/* -** SQL Function: decimal_cmp(X, Y) -** -** Return negative, zero, or positive if X is less then, equal to, or -** greater than Y. -*/ -static void decimalCmpFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - Decimal *pA = 0, *pB = 0; - int rc; - - UNUSED_PARAMETER(argc); - pA = decimal_new(context, argv[0], 1); - if( pA==0 || pA->isNull ) goto cmp_done; - pB = decimal_new(context, argv[1], 1); - if( pB==0 || pB->isNull ) goto cmp_done; - rc = decimal_cmp(pA, pB); - if( rc<0 ) rc = -1; - else if( rc>0 ) rc = +1; - sqlite3_result_int(context, rc); -cmp_done: - decimal_free(pA); - decimal_free(pB); -} - -/* -** Expand the Decimal so that it has a least nDigit digits and nFrac -** digits to the right of the decimal point. -*/ -static void decimal_expand(Decimal *p, int nDigit, int nFrac){ - int nAddSig; - int nAddFrac; - signed char *a; - if( p==0 ) return; - nAddFrac = nFrac - p->nFrac; - nAddSig = (nDigit - p->nDigit) - nAddFrac; - if( nAddFrac==0 && nAddSig==0 ) return; - if( nDigit+1>SQLITE_DECIMAL_MAX_DIGIT ){ p->oom = 1; return; } - a = sqlite3_realloc64(p->a, nDigit+1); - if( a==0 ){ - p->oom = 1; - return; - } - p->a = a; - if( nAddSig ){ - memmove(p->a+nAddSig, p->a, p->nDigit); - memset(p->a, 0, nAddSig); - p->nDigit += nAddSig; - } - if( nAddFrac ){ - memset(p->a+p->nDigit, 0, nAddFrac); - p->nDigit += nAddFrac; - p->nFrac += nAddFrac; - } -} - -/* -** Add the value pB into pA. A := A + B. -** -** Both pA and pB might become denormalized by this routine. -*/ -static void decimal_add(Decimal *pA, Decimal *pB){ - int nSig, nFrac, nDigit; - int i, rc; - if( pA==0 ){ - return; - } - if( pA->oom || pB==0 || pB->oom ){ - pA->oom = 1; - return; - } - if( pA->isNull || pB->isNull ){ - pA->isNull = 1; - return; - } - nSig = pA->nDigit - pA->nFrac; - if( nSig && pA->a[0]==0 ) nSig--; - if( nSignDigit-pB->nFrac ){ - nSig = pB->nDigit - pB->nFrac; - } - nFrac = pA->nFrac; - if( nFracnFrac ) nFrac = pB->nFrac; - nDigit = nSig + nFrac + 1; - decimal_expand(pA, nDigit, nFrac); - decimal_expand(pB, nDigit, nFrac); - if( pA->oom || pB->oom ){ - pA->oom = 1; - }else{ - if( pA->sign==pB->sign ){ - int carry = 0; - for(i=nDigit-1; i>=0; i--){ - int x = pA->a[i] + pB->a[i] + carry; - if( x>=10 ){ - carry = 1; - pA->a[i] = x - 10; - }else{ - carry = 0; - pA->a[i] = x; - } - } - }else{ - signed char *aA, *aB; - int borrow = 0; - rc = memcmp(pA->a, pB->a, nDigit); - if( rc<0 ){ - aA = pB->a; - aB = pA->a; - pA->sign = !pA->sign; - }else{ - aA = pA->a; - aB = pB->a; - } - for(i=nDigit-1; i>=0; i--){ - int x = aA[i] - aB[i] - borrow; - if( x<0 ){ - pA->a[i] = x+10; - borrow = 1; - }else{ - pA->a[i] = x; - borrow = 0; - } - } - } - } -} - -/* -** Multiply A by B. A := A * B -** -** All significant digits after the decimal point are retained. -** Trailing zeros after the decimal point are omitted as long as -** the number of digits after the decimal point is no less than -** either the number of digits in either input. -*/ -static void decimalMul(Decimal *pA, Decimal *pB){ - signed char *acc = 0; - int i, j, k; - int minFrac; - sqlite3_int64 sumDigit; - - if( pA==0 || pA->oom || pA->isNull - || pB==0 || pB->oom || pB->isNull - ){ - goto mul_end; - } - sumDigit = pA->nDigit; - sumDigit += pB->nDigit; - sumDigit += 2; - if( sumDigit>SQLITE_DECIMAL_MAX_DIGIT ){ pA->oom = 1; return; } - acc = sqlite3_malloc64( sumDigit ); - if( acc==0 ){ - pA->oom = 1; - goto mul_end; - } - memset(acc, 0, pA->nDigit + pB->nDigit + 2); - minFrac = pA->nFrac; - if( pB->nFracnFrac; - for(i=pA->nDigit-1; i>=0; i--){ - signed char f = pA->a[i]; - int carry = 0, x; - for(j=pB->nDigit-1, k=i+j+3; j>=0; j--, k--){ - x = acc[k] + f*pB->a[j] + carry; - acc[k] = x%10; - carry = x/10; - } - x = acc[k] + carry; - acc[k] = x%10; - acc[k-1] += x/10; - } - sqlite3_free(pA->a); - pA->a = acc; - acc = 0; - pA->nDigit += pB->nDigit + 2; - pA->nFrac += pB->nFrac; - pA->sign ^= pB->sign; - while( pA->nFrac>minFrac && pA->a[pA->nDigit-1]==0 ){ - pA->nFrac--; - pA->nDigit--; - } - -mul_end: - sqlite3_free(acc); -} - -/* -** Create a new Decimal object that contains an integer power of 2. -*/ -static Decimal *decimalPow2(int N){ - Decimal *pA = 0; /* The result to be returned */ - Decimal *pX = 0; /* Multiplier */ - if( N<-20000 || N>20000 ) goto pow2_fault; - pA = decimalNewFromText("1.0", 3); - if( pA==0 || pA->oom ) goto pow2_fault; - if( N==0 ) return pA; - if( N>0 ){ - pX = decimalNewFromText("2.0", 3); - }else{ - N = -N; - pX = decimalNewFromText("0.5", 3); - } - if( pX==0 || pX->oom ) goto pow2_fault; - while( 1 /* Exit by break */ ){ - if( N & 1 ){ - decimalMul(pA, pX); - if( pA->oom ) goto pow2_fault; - } - N >>= 1; - if( N==0 ) break; - decimalMul(pX, pX); - } - decimal_free(pX); - return pA; - -pow2_fault: - decimal_free(pA); - decimal_free(pX); - return 0; -} - -/* -** Use an IEEE754 binary64 ("double") to generate a new Decimal object. -*/ -static Decimal *decimalFromDouble(double r){ - sqlite3_int64 m, a; - int e; - int isNeg; - Decimal *pA; - Decimal *pX; - char zNum[100]; - if( r<0.0 ){ - isNeg = 1; - r = -r; - }else{ - isNeg = 0; - } - memcpy(&a,&r,sizeof(a)); - if( a==0 || a==(sqlite3_int64)0x8000000000000000LL){ - e = 0; - m = 0; - }else{ - e = a>>52; - m = a & ((((sqlite3_int64)1)<<52)-1); - if( e==0 ){ - m <<= 1; - }else{ - m |= ((sqlite3_int64)1)<<52; - } - while( e<1075 && m>0 && (m&1)==0 ){ - m >>= 1; - e++; - } - if( isNeg ) m = -m; - e = e - 1075; - if( e>971 ){ - return 0; /* A NaN or an Infinity */ - } - } - - /* At this point m is the integer significand and e is the exponent */ - sqlite3_snprintf(sizeof(zNum), zNum, "%lld", m); - pA = decimalNewFromText(zNum, (int)strlen(zNum)); - pX = decimalPow2(e); - decimalMul(pA, pX); - decimal_free(pX); - return pA; -} - -/* -** SQL Function: decimal(X) -** OR: decimal_exp(X) -** -** Convert input X into decimal and then back into text. -** -** If X is originally a float, then a full decimal expansion of that floating -** point value is done. Or if X is an 8-byte blob, it is interpreted -** as a float and similarly expanded. -** -** The decimal_exp(X) function returns the result in exponential notation. -** decimal(X) returns a complete decimal, without the e+NNN at the end. -*/ -static void decimalFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - Decimal *p = decimal_new(context, argv[0], 0); - int N; - if( argc==2 ){ - N = sqlite3_value_int(argv[1]); - if( N>0 ) decimal_round(p, N); - }else{ - N = 0; - } - if( p ){ - if( sqlite3_user_data(context)!=0 ){ - decimal_result_sci(context, p, N); - }else{ - decimal_result(context, p); - } - decimal_free(p); - } -} - -/* -** Compare text in decimal order. -*/ -static int decimalCollFunc( - void *notUsed, - int nKey1, const void *pKey1, - int nKey2, const void *pKey2 -){ - const unsigned char *zA = (const unsigned char*)pKey1; - const unsigned char *zB = (const unsigned char*)pKey2; - Decimal *pA = decimalNewFromText((const char*)zA, nKey1); - Decimal *pB = decimalNewFromText((const char*)zB, nKey2); - int rc; - UNUSED_PARAMETER(notUsed); - if( pA==0 || pB==0 ){ - rc = 0; - }else{ - rc = decimal_cmp(pA, pB); - } - decimal_free(pA); - decimal_free(pB); - return rc; -} - - -/* -** SQL Function: decimal_add(X, Y) -** decimal_sub(X, Y) -** -** Return the sum or difference of X and Y. -*/ -static void decimalAddFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - Decimal *pA = decimal_new(context, argv[0], 1); - Decimal *pB = decimal_new(context, argv[1], 1); - UNUSED_PARAMETER(argc); - decimal_add(pA, pB); - decimal_result(context, pA); - decimal_free(pA); - decimal_free(pB); -} -static void decimalSubFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - Decimal *pA = decimal_new(context, argv[0], 1); - Decimal *pB = decimal_new(context, argv[1], 1); - UNUSED_PARAMETER(argc); - if( pB ){ - pB->sign = !pB->sign; - decimal_add(pA, pB); - decimal_result(context, pA); - } - decimal_free(pA); - decimal_free(pB); -} - -/* Aggregate function: decimal_sum(X) -** -** Works like sum() except that it uses decimal arithmetic for unlimited -** precision. -*/ -static void decimalSumStep( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - Decimal *p; - Decimal *pArg; - UNUSED_PARAMETER(argc); - p = sqlite3_aggregate_context(context, sizeof(*p)); - if( p==0 ) return; - if( !p->isInit ){ - p->isInit = 1; - p->a = sqlite3_malloc64(2); - if( p->a==0 ){ - p->oom = 1; - }else{ - p->a[0] = 0; - } - p->nDigit = 1; - p->nFrac = 0; - } - if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; - pArg = decimal_new(context, argv[0], 1); - decimal_add(p, pArg); - decimal_free(pArg); -} -static void decimalSumInverse( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - Decimal *p; - Decimal *pArg; - UNUSED_PARAMETER(argc); - p = sqlite3_aggregate_context(context, sizeof(*p)); - if( p==0 ) return; - if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; - pArg = decimal_new(context, argv[0], 1); - if( pArg ) pArg->sign = !pArg->sign; - decimal_add(p, pArg); - decimal_free(pArg); -} -static void decimalSumValue(sqlite3_context *context){ - Decimal *p = sqlite3_aggregate_context(context, 0); - if( p==0 ) return; - decimal_result(context, p); -} -static void decimalSumFinalize(sqlite3_context *context){ - Decimal *p = sqlite3_aggregate_context(context, 0); - if( p==0 ) return; - decimal_result(context, p); - decimal_clear(p); -} - -/* -** SQL Function: decimal_mul(X, Y) -** -** Return the product of X and Y. -*/ -static void decimalMulFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - Decimal *pA = decimal_new(context, argv[0], 1); - Decimal *pB = decimal_new(context, argv[1], 1); - UNUSED_PARAMETER(argc); - if( pA==0 || pA->oom || pA->isNull - || pB==0 || pB->oom || pB->isNull - ){ - goto mul_end; - } - decimalMul(pA, pB); - if( pA->oom ){ - goto mul_end; - } - decimal_result(context, pA); - -mul_end: - decimal_free(pA); - decimal_free(pB); -} - -/* -** SQL Function: decimal_pow2(N) -** -** Return the N-th power of 2. N must be an integer. -*/ -static void decimalPow2Func( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - UNUSED_PARAMETER(argc); - if( sqlite3_value_type(argv[0])==SQLITE_INTEGER ){ - Decimal *pA = decimalPow2(sqlite3_value_int(argv[0])); - decimal_result_sci(context, pA, 0); - decimal_free(pA); - } -} - -#ifdef _WIN32 - -#endif -int sqlite3_decimal_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi -){ - int rc = SQLITE_OK; - static const struct { - const char *zFuncName; - int nArg; - int iArg; - void (*xFunc)(sqlite3_context*,int,sqlite3_value**); - } aFunc[] = { - { "decimal", 1, 0, decimalFunc }, - { "decimal", 2, 0, decimalFunc }, - { "decimal_exp", 1, 1, decimalFunc }, - { "decimal_exp", 2, 1, decimalFunc }, - { "decimal_cmp", 2, 0, decimalCmpFunc }, - { "decimal_add", 2, 0, decimalAddFunc }, - { "decimal_sub", 2, 0, decimalSubFunc }, - { "decimal_mul", 2, 0, decimalMulFunc }, - { "decimal_pow2", 1, 0, decimalPow2Func }, - }; - unsigned int i; - (void)pzErrMsg; /* Unused parameter */ - - SQLITE_EXTENSION_INIT2(pApi); - - for(i=0; i<(int)(sizeof(aFunc)/sizeof(aFunc[0])) && rc==SQLITE_OK; i++){ - rc = sqlite3_create_function(db, aFunc[i].zFuncName, aFunc[i].nArg, - SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, - aFunc[i].iArg ? db : 0, aFunc[i].xFunc, 0, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_create_window_function(db, "decimal_sum", 1, - SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 0, - decimalSumStep, decimalSumFinalize, - decimalSumValue, decimalSumInverse, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_create_collation(db, "decimal", SQLITE_UTF8, - 0, decimalCollFunc); - } - return rc; -} - -/************************* End ext/misc/decimal.c ********************/ -/************************* Begin ext/misc/base64.c ******************/ -/* -** 2022-11-18 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -** This is a SQLite extension for converting in either direction -** between a (binary) blob and base64 text. Base64 can transit a -** sane USASCII channel unmolested. It also plays nicely in CSV or -** written as TCL brace-enclosed literals or SQL string literals, -** and can be used unmodified in XML-like documents. -** -** This is an independent implementation of conversions specified in -** RFC 4648, done on the above date by the author (Larry Brasfield) -** who thereby has the right to put this into the public domain. -** -** The conversions meet RFC 4648 requirements, provided that this -** C source specifies that line-feeds are included in the encoded -** data to limit visible line lengths to 72 characters and to -** terminate any encoded blob having non-zero length. -** -** Length limitations are not imposed except that the runtime -** SQLite string or blob length limits are respected. Otherwise, -** any length binary sequence can be represented and recovered. -** Generated base64 sequences, with their line-feeds included, -** can be concatenated; the result converted back to binary will -** be the concatenation of the represented binary sequences. -** -** This SQLite3 extension creates a function, base64(x), which -** either: converts text x containing base64 to a returned blob; -** or converts a blob x to returned text containing base64. An -** error will be thrown for other input argument types. -** -** This code relies on UTF-8 encoding only with respect to the -** meaning of the first 128 (7-bit) codes matching that of USASCII. -** It will fail miserably if somehow made to try to convert EBCDIC. -** Because it is table-driven, it could be enhanced to handle that, -** but the world and SQLite have moved on from that anachronism. -** -** To build the extension: -** Set shell variable SQDIR= -** *Nix: gcc -O2 -shared -I$SQDIR -fPIC -o base64.so base64.c -** OSX: gcc -O2 -dynamiclib -fPIC -I$SQDIR -o base64.dylib base64.c -** Win32: gcc -O2 -shared -I%SQDIR% -o base64.dll base64.c -** Win32: cl /Os -I%SQDIR% base64.c -link -dll -out:base64.dll -*/ - -#include - -/* #include "sqlite3ext.h" */ - -#ifndef deliberate_fall_through -/* Quiet some compilers about some of our intentional code. */ -# if GCC_VERSION>=7000000 -# define deliberate_fall_through __attribute__((fallthrough)); -# else -# define deliberate_fall_through -# endif -#endif - -SQLITE_EXTENSION_INIT1; - -#define PC 0x80 /* pad character */ -#define WS 0x81 /* whitespace */ -#define ND 0x82 /* Not above or digit-value */ -#define PAD_CHAR '=' - -#ifndef U8_TYPEDEF -/* typedef unsigned char u8; */ -#define U8_TYPEDEF -#endif - -/* Decoding table, ASCII (7-bit) value to base 64 digit value or other */ -static const u8 b64DigitValues[128] = { - /* HT LF VT FF CR */ - ND,ND,ND,ND, ND,ND,ND,ND, ND,WS,WS,WS, WS,WS,ND,ND, - /* US */ - ND,ND,ND,ND, ND,ND,ND,ND, ND,ND,ND,ND, ND,ND,ND,ND, - /*sp + / */ - WS,ND,ND,ND, ND,ND,ND,ND, ND,ND,ND,62, ND,ND,ND,63, - /* 0 1 5 9 = */ - 52,53,54,55, 56,57,58,59, 60,61,ND,ND, ND,PC,ND,ND, - /* A O */ - ND, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, - /* P Z */ - 15,16,17,18, 19,20,21,22, 23,24,25,ND, ND,ND,ND,ND, - /* a o */ - ND,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, - /* p z */ - 41,42,43,44, 45,46,47,48, 49,50,51,ND, ND,ND,ND,ND -}; - -static const char b64Numerals[64+1] -= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -#define BX_DV_PROTO(c) \ - ((((u8)(c))<0x80)? (u8)(b64DigitValues[(u8)(c)]) : 0x80) -#define IS_BX_DIGIT(bdp) (((u8)(bdp))<0x80) -#define IS_BX_WS(bdp) ((bdp)==WS) -#define IS_BX_PAD(bdp) ((bdp)==PC) -#define BX_NUMERAL(dv) (b64Numerals[(u8)(dv)]) -/* Width of base64 lines. Should be an integer multiple of 4. */ -#define B64_DARK_MAX 72 - -/* Encode a byte buffer into base64 text with linefeeds appended to limit -** encoded group lengths to B64_DARK_MAX or to terminate the last group. -*/ -static char* toBase64( u8 *pIn, int nbIn, char *pOut ){ - int nCol = 0; - while( nbIn >= 3 ){ - /* Do the bit-shuffle, exploiting unsigned input to avoid masking. */ - pOut[0] = BX_NUMERAL(pIn[0]>>2); - pOut[1] = BX_NUMERAL(((pIn[0]<<4)|(pIn[1]>>4))&0x3f); - pOut[2] = BX_NUMERAL(((pIn[1]&0xf)<<2)|(pIn[2]>>6)); - pOut[3] = BX_NUMERAL(pIn[2]&0x3f); - pOut += 4; - nbIn -= 3; - pIn += 3; - if( (nCol += 4)>=B64_DARK_MAX || nbIn<=0 ){ - *pOut++ = '\n'; - nCol = 0; - } - } - if( nbIn > 0 ){ - signed char nco = nbIn+1; - int nbe; - unsigned long qv = *pIn++; - for( nbe=1; nbe<3; ++nbe ){ - qv <<= 8; - if( nbe=0; --nbe ){ - char ce = (nbe>= 6; - pOut[nbe] = ce; - } - pOut += 4; - *pOut++ = '\n'; - } - *pOut = 0; - return pOut; -} - -/* Skip over text which is not base64 numeral(s). */ -static char * skipNonB64( char *s, int nc ){ - char c; - while( nc-- > 0 && (c = *s) && !IS_BX_DIGIT(BX_DV_PROTO(c)) ) ++s; - return s; -} - -/* Decode base64 text into a byte buffer. */ -static u8* fromBase64( char *pIn, int ncIn, u8 *pOut ){ - if( ncIn>0 && pIn[ncIn-1]=='\n' ) --ncIn; - while( ncIn>0 && *pIn!=PAD_CHAR ){ - static signed char nboi[] = { 0, 0, 1, 2, 3 }; - char *pUse = skipNonB64(pIn, ncIn); - unsigned long qv = 0L; - int nti, nbo, nac; - ncIn -= (pUse - pIn); - pIn = pUse; - nti = (ncIn>4)? 4 : ncIn; - ncIn -= nti; - nbo = nboi[nti]; - if( nbo==0 ) break; - for( nac=0; nac<4; ++nac ){ - char c = (nac>8) & 0xff; - deliberate_fall_through; /* FALLTHRU */ - case 1: - pOut[0] = (qv>>16) & 0xff; - break; - } - pOut += nbo; - } - return pOut; -} - -/* This function does the work for the SQLite base64(x) UDF. */ -static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){ - sqlite3_int64 nb; - sqlite3_int64 nv = sqlite3_value_bytes(av[0]); - sqlite3_int64 nc; - int nvMax = sqlite3_limit(sqlite3_context_db_handle(context), - SQLITE_LIMIT_LENGTH, -1); - char *cBuf; - u8 *bBuf; - assert(na==1); - switch( sqlite3_value_type(av[0]) ){ - case SQLITE_BLOB: - nb = nv; - nc = 4*((nv+2)/3); /* quads needed */ - nc += (nc+(B64_DARK_MAX-1))/B64_DARK_MAX + 1; /* LFs and a 0-terminator */ - if( nvMax < nc ){ - sqlite3_result_error(context, "blob expanded to base64 too big", -1); - return; - } - bBuf = (u8*)sqlite3_value_blob(av[0]); - if( !bBuf ){ - if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){ - goto memFail; - } - sqlite3_result_text(context,"",-1,SQLITE_STATIC); - break; - } - cBuf = sqlite3_malloc64(nc); - if( !cBuf ) goto memFail; - nc = (int)(toBase64(bBuf, nb, cBuf) - cBuf); - sqlite3_result_text(context, cBuf, nc, sqlite3_free); - break; - case SQLITE_TEXT: - nc = nv; - nb = 3*((nv+3)/4); /* may overestimate due to LF and padding */ - if( nvMax < nb ){ - sqlite3_result_error(context, "blob from base64 may be too big", -1); - return; - }else if( nb<1 ){ - nb = 1; - } - cBuf = (char *)sqlite3_value_text(av[0]); - if( !cBuf ){ - if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){ - goto memFail; - } - sqlite3_result_zeroblob(context, 0); - break; - } - bBuf = sqlite3_malloc64(nb); - if( !bBuf ) goto memFail; - nb = (int)(fromBase64(cBuf, nc, bBuf) - bBuf); - sqlite3_result_blob(context, bBuf, nb, sqlite3_free); - break; - default: - sqlite3_result_error(context, "base64 accepts only blob or text", -1); - return; - } - return; - memFail: - sqlite3_result_error(context, "base64 OOM", -1); -} - -/* -** Establish linkage to running SQLite library. -*/ -#ifndef SQLITE_SHELL_EXTFUNCS -#ifdef _WIN32 - -#endif -int sqlite3_base64_init -#else -static int sqlite3_base64_init -#endif -(sqlite3 *db, char **pzErr, const sqlite3_api_routines *pApi){ - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErr; - return sqlite3_create_function - (db, "base64", 1, - SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS|SQLITE_DIRECTONLY|SQLITE_UTF8, - 0, base64, 0, 0); -} - -/* -** Define some macros to allow this extension to be built into the shell -** conveniently, in conjunction with use of SQLITE_SHELL_EXTFUNCS. This -** allows shell.c, as distributed, to have this extension built in. -*/ -#define BASE64_INIT(db) sqlite3_base64_init(db, 0, 0) -#define BASE64_EXPOSE(db, pzErr) /* Not needed, ..._init() does this. */ - -/************************* End ext/misc/base64.c ********************/ -/************************* Begin ext/misc/base85.c ******************/ -/* -** 2022-11-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 is a utility for converting binary to base85 or vice-versa. -** It can be built as a standalone program or an SQLite3 extension. -** -** Much like base64 representations, base85 can be sent through a -** sane USASCII channel unmolested. It also plays nicely in CSV or -** written as TCL brace-enclosed literals or SQL string literals. -** It is not suited for unmodified use in XML-like documents. -** -** The encoding used resembles Ascii85, but was devised by the author -** (Larry Brasfield) before Mozilla, Adobe, ZMODEM or other Ascii85 -** variant sources existed, in the 1984 timeframe on a VAX mainframe. -** Further, this is an independent implementation of a base85 system. -** Hence, the author has rightfully put this into the public domain. -** -** Base85 numerals are taken from the set of 7-bit USASCII codes, -** excluding control characters and Space ! " ' ( ) { | } ~ Del -** in code order representing digit values 0 to 84 (base 10.) -** -** Groups of 4 bytes, interpreted as big-endian 32-bit values, -** are represented as 5-digit base85 numbers with MS to LS digit -** order. Groups of 1-3 bytes are represented with 2-4 digits, -** still big-endian but 8-24 bit values. (Using big-endian yields -** the simplest transition to byte groups smaller than 4 bytes. -** These byte groups can also be considered base-256 numbers.) -** Groups of 0 bytes are represented with 0 digits and vice-versa. -** No pad characters are used; Encoded base85 numeral sequence -** (aka "group") length maps 1-to-1 to the decoded binary length. -** -** Any character not in the base85 numeral set delimits groups. -** When base85 is streamed or stored in containers of indefinite -** size, newline is used to separate it into sub-sequences of no -** more than 80 digits so that fgets() can be used to read it. -** -** Length limitations are not imposed except that the runtime -** SQLite string or blob length limits are respected. Otherwise, -** any length binary sequence can be represented and recovered. -** Base85 sequences can be concatenated by separating them with -** a non-base85 character; the conversion to binary will then -** be the concatenation of the represented binary sequences. - -** The standalone program either converts base85 on stdin to create -** a binary file or converts a binary file to base85 on stdout. -** Read or make it blurt its help for invocation details. -** -** The SQLite3 extension creates a function, base85(x), which will -** either convert text base85 to a blob or a blob to text base85 -** and return the result (or throw an error for other types.) -** Unless built with OMIT_BASE85_CHECKER defined, it also creates a -** function, is_base85(t), which returns 1 iff the text t contains -** nothing other than base85 numerals and whitespace, or 0 otherwise. -** -** To build the extension: -** Set shell variable SQDIR= -** and variable OPTS to -DOMIT_BASE85_CHECKER if is_base85() unwanted. -** *Nix: gcc -O2 -shared -I$SQDIR $OPTS -fPIC -o base85.so base85.c -** OSX: gcc -O2 -dynamiclib -fPIC -I$SQDIR $OPTS -o base85.dylib base85.c -** Win32: gcc -O2 -shared -I%SQDIR% %OPTS% -o base85.dll base85.c -** Win32: cl /Os -I%SQDIR% %OPTS% base85.c -link -dll -out:base85.dll -** -** To build the standalone program, define PP symbol BASE85_STANDALONE. Eg. -** *Nix or OSX: gcc -O2 -DBASE85_STANDALONE base85.c -o base85 -** Win32: gcc -O2 -DBASE85_STANDALONE -o base85.exe base85.c -** Win32: cl /Os /MD -DBASE85_STANDALONE base85.c -*/ - -#include -#include -#include -#include -#ifndef OMIT_BASE85_CHECKER -# include -#endif - -#ifndef BASE85_STANDALONE - -/* # include "sqlite3ext.h" */ - -SQLITE_EXTENSION_INIT1; - -#else - -# ifdef _WIN32 -# include -# include -# else -# define setmode(fd,m) -# endif - -static char *zHelp = - "Usage: base85 \n" - " is either -r to read or -w to write ,\n" - " content to be converted to/from base85 on stdout/stdin.\n" - " names a binary file to be rendered or created.\n" - " Or, the name '-' refers to the stdin or stdout stream.\n" - ; - -static void sayHelp(){ - printf("%s", zHelp); -} -#endif - -#ifndef U8_TYPEDEF -/* typedef unsigned char u8; */ -#define U8_TYPEDEF -#endif - -/* Classify c according to interval within USASCII set w.r.t. base85 - * Values of 1 and 3 are base85 numerals. Values of 0, 2, or 4 are not. - */ -#define B85_CLASS( c ) (((c)>='#')+((c)>'&')+((c)>='*')+((c)>'z')) - -/* Provide digitValue to b85Numeral offset as a function of above class. */ -static u8 b85_cOffset[] = { 0, '#', 0, '*'-4, 0 }; -#define B85_DNOS( c ) b85_cOffset[B85_CLASS(c)] - -/* Say whether c is a base85 numeral. */ -#define IS_B85( c ) (B85_CLASS(c) & 1) - -#if 0 /* Not used, */ -static u8 base85DigitValue( char c ){ - u8 dv = (u8)(c - '#'); - if( dv>87 ) return 0xff; - return (dv > 3)? dv-3 : dv; -} -#endif - -/* Width of base64 lines. Should be an integer multiple of 5. */ -#define B85_DARK_MAX 80 - - -static char * skipNonB85( char *s, int nc ){ - char c; - while( nc-- > 0 && (c = *s) && !IS_B85(c) ) ++s; - return s; -} - -/* Convert small integer, known to be in 0..84 inclusive, to base85 numeral. - * Do not use the macro form with argument expression having a side-effect.*/ -#if 0 -static char base85Numeral( u8 b ){ - return (b < 4)? (char)(b + '#') : (char)(b - 4 + '*'); -} -#else -# define base85Numeral( dn )\ - ((char)(((dn) < 4)? (char)((dn) + '#') : (char)((dn) - 4 + '*'))) -#endif - -static char *putcs(char *pc, char *s){ - char c; - while( (c = *s++)!=0 ) *pc++ = c; - return pc; -} - -/* Encode a byte buffer into base85 text. If pSep!=0, it's a C string -** to be appended to encoded groups to limit their length to B85_DARK_MAX -** or to terminate the last group (to aid concatenation.) -*/ -static char* toBase85( u8 *pIn, int nbIn, char *pOut, char *pSep ){ - int nCol = 0; - while( nbIn >= 4 ){ - int nco = 5; - unsigned long qbv = (((unsigned long)pIn[0])<<24) | - (pIn[1]<<16) | (pIn[2]<<8) | pIn[3]; - while( nco > 0 ){ - unsigned nqv = (unsigned)(qbv/85UL); - unsigned char dv = qbv - 85UL*nqv; - qbv = nqv; - pOut[--nco] = base85Numeral(dv); - } - nbIn -= 4; - pIn += 4; - pOut += 5; - if( pSep && (nCol += 5)>=B85_DARK_MAX ){ - pOut = putcs(pOut, pSep); - nCol = 0; - } - } - if( nbIn > 0 ){ - int nco = nbIn + 1; - unsigned long qv = *pIn++; - int nbe = 1; - while( nbe++ < nbIn ){ - qv = (qv<<8) | *pIn++; - } - nCol += nco; - while( nco > 0 ){ - u8 dv = (u8)(qv % 85); - qv /= 85; - pOut[--nco] = base85Numeral(dv); - } - pOut += (nbIn+1); - } - if( pSep && nCol>0 ) pOut = putcs(pOut, pSep); - *pOut = 0; - return pOut; -} - -/* Decode base85 text into a byte buffer. */ -static u8* fromBase85( char *pIn, int ncIn, u8 *pOut ){ - if( ncIn>0 && pIn[ncIn-1]=='\n' ) --ncIn; - while( ncIn>0 ){ - static signed char nboi[] = { 0, 0, 1, 2, 3, 4 }; - char *pUse = skipNonB85(pIn, ncIn); - unsigned long qv = 0L; - int nti, nbo; - ncIn -= (pUse - pIn); - pIn = pUse; - nti = (ncIn>5)? 5 : ncIn; - nbo = nboi[nti]; - if( nbo==0 ) break; - while( nti>0 ){ - char c = *pIn++; - u8 cdo = B85_DNOS(c); - --ncIn; - if( cdo==0 ) break; - qv = 85 * qv + (c - cdo); - --nti; - } - nbo -= nti; /* Adjust for early (non-digit) end of group. */ - switch( nbo ){ - case 4: - *pOut++ = (qv >> 24)&0xff; - /* FALLTHRU */ - case 3: - *pOut++ = (qv >> 16)&0xff; - /* FALLTHRU */ - case 2: - *pOut++ = (qv >> 8)&0xff; - /* FALLTHRU */ - case 1: - *pOut++ = qv&0xff; - /* FALLTHRU */ - case 0: - break; - } - } - return pOut; -} - -#ifndef OMIT_BASE85_CHECKER -/* Say whether input char sequence is all (base85 and/or whitespace).*/ -static int allBase85( char *p, int len ){ - char c; - while( len-- > 0 && (c = *p++) != 0 ){ - if( !IS_B85(c) && !isspace(c) ) return 0; - } - return 1; -} -#endif - -#ifndef BASE85_STANDALONE - -#ifndef OMIT_BASE85_CHECKER -/* This function does the work for the SQLite is_base85(t) UDF. */ -static void is_base85(sqlite3_context *context, int na, sqlite3_value *av[]){ - assert(na==1); - switch( sqlite3_value_type(av[0]) ){ - case SQLITE_TEXT: - { - int rv = allBase85( (char *)sqlite3_value_text(av[0]), - sqlite3_value_bytes(av[0]) ); - sqlite3_result_int(context, rv); - } - break; - case SQLITE_NULL: - sqlite3_result_null(context); - break; - default: - sqlite3_result_error(context, "is_base85 accepts only text or NULL", -1); - return; - } -} -#endif - -/* This function does the work for the SQLite base85(x) UDF. */ -static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){ - sqlite3_int64 nb, nc, nv = sqlite3_value_bytes(av[0]); - int nvMax = sqlite3_limit(sqlite3_context_db_handle(context), - SQLITE_LIMIT_LENGTH, -1); - char *cBuf; - u8 *bBuf; - assert(na==1); - switch( sqlite3_value_type(av[0]) ){ - case SQLITE_BLOB: - nb = nv; - /* ulongs tail newlines tailenc+nul*/ - nc = 5*(nv/4) + nv%4 + nv/64+1 + 2; - if( nvMax < nc ){ - sqlite3_result_error(context, "blob expanded to base85 too big", -1); - return; - } - bBuf = (u8*)sqlite3_value_blob(av[0]); - if( !bBuf ){ - if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){ - goto memFail; - } - sqlite3_result_text(context,"",-1,SQLITE_STATIC); - break; - } - cBuf = sqlite3_malloc64(nc); - if( !cBuf ) goto memFail; - nc = (int)(toBase85(bBuf, nb, cBuf, "\n") - cBuf); - sqlite3_result_text(context, cBuf, nc, sqlite3_free); - break; - case SQLITE_TEXT: - nc = nv; - nb = 4*(nv/5) + nv%5; /* may overestimate */ - if( nvMax < nb ){ - sqlite3_result_error(context, "blob from base85 may be too big", -1); - return; - }else if( nb<1 ){ - nb = 1; - } - cBuf = (char *)sqlite3_value_text(av[0]); - if( !cBuf ){ - if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){ - goto memFail; - } - sqlite3_result_zeroblob(context, 0); - break; - } - bBuf = sqlite3_malloc64(nb); - if( !bBuf ) goto memFail; - nb = (int)(fromBase85(cBuf, nc, bBuf) - bBuf); - sqlite3_result_blob(context, bBuf, nb, sqlite3_free); - break; - default: - sqlite3_result_error(context, "base85 accepts only blob or text.", -1); - return; - } - return; - memFail: - sqlite3_result_error(context, "base85 OOM", -1); -} - -/* -** Establish linkage to running SQLite library. -*/ -#ifndef SQLITE_SHELL_EXTFUNCS -#ifdef _WIN32 - -#endif -int sqlite3_base85_init -#else -static int sqlite3_base85_init -#endif -(sqlite3 *db, char **pzErr, const sqlite3_api_routines *pApi){ - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErr; -#ifndef OMIT_BASE85_CHECKER - { - int rc = sqlite3_create_function - (db, "is_base85", 1, - SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS|SQLITE_UTF8, - 0, is_base85, 0, 0); - if( rc!=SQLITE_OK ) return rc; - } -#endif - return sqlite3_create_function - (db, "base85", 1, - SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS|SQLITE_DIRECTONLY|SQLITE_UTF8, - 0, base85, 0, 0); -} - -/* -** Define some macros to allow this extension to be built into the shell -** conveniently, in conjunction with use of SQLITE_SHELL_EXTFUNCS. This -** allows shell.c, as distributed, to have this extension built in. -*/ -# define BASE85_INIT(db) sqlite3_base85_init(db, 0, 0) -# define BASE85_EXPOSE(db, pzErr) /* Not needed, ..._init() does this. */ - -#else /* standalone program */ - -int main(int na, char *av[]){ - int cin; - int rc = 0; - u8 bBuf[4*(B85_DARK_MAX/5)]; - char cBuf[5*(sizeof(bBuf)/4)+2]; - size_t nio; -# ifndef OMIT_BASE85_CHECKER - int b85Clean = 1; -# endif - char rw; - FILE *fb = 0, *foc = 0; - char fmode[3] = "xb"; - if( na < 3 || av[1][0]!='-' || (rw = av[1][1])==0 || (rw!='r' && rw!='w') ){ - sayHelp(); - return 0; - } - fmode[0] = rw; - if( av[2][0]=='-' && av[2][1]==0 ){ - switch( rw ){ - case 'r': - fb = stdin; - setmode(fileno(stdin), O_BINARY); - break; - case 'w': - fb = stdout; - setmode(fileno(stdout), O_BINARY); - break; - } - }else{ - fb = fopen(av[2], fmode); - foc = fb; - } - if( !fb ){ - fprintf(stderr, "Cannot open %s for %c\n", av[2], rw); - rc = 1; - }else{ - switch( rw ){ - case 'r': - while( (nio = fread( bBuf, 1, sizeof(bBuf), fb))>0 ){ - toBase85( bBuf, (int)nio, cBuf, 0 ); - fprintf(stdout, "%s\n", cBuf); - } - break; - case 'w': - while( 0 != fgets(cBuf, sizeof(cBuf), stdin) ){ - int nc = strlen(cBuf); - size_t nbo = fromBase85( cBuf, nc, bBuf ) - bBuf; - if( 1 != fwrite(bBuf, nbo, 1, fb) ) rc = 1; -#ifndef OMIT_BASE85_CHECKER - b85Clean &= allBase85( cBuf, nc ); -#endif - } - break; - default: - sayHelp(); - rc = 1; - } - if( foc ) fclose(foc); - } -# ifndef OMIT_BASE85_CHECKER - if( !b85Clean ){ - fprintf(stderr, "Base85 input had non-base85 dark or control content.\n"); - } -# endif - return rc; -} - -#endif - -/************************* End ext/misc/base85.c ********************/ -/************************* Begin ext/misc/ieee754.c ******************/ -/* -** 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 -** -** Two additional functions break apart the one-argument ieee754() -** result into separate integer values: -** -** ieee754_mantissa(45.25) -> 181 -** ieee754_exponent(45.25) -> -2 -** -** These functions convert binary64 numbers into blobs and back again. -** -** ieee754_from_blob(x'3ff0000000000000') -> 1.0 -** ieee754_to_blob(1.0) -> x'3ff0000000000000' -** -** In all single-argument functions, if the argument is an 8-byte blob -** then that blob is interpreted as a big-endian binary64 value. -** -** -** EXACT DECIMAL REPRESENTATION OF BINARY64 VALUES -** ----------------------------------------------- -** -** This extension in combination with the separate 'decimal' extension -** can be used to compute the exact decimal representation of binary64 -** values. To begin, first compute a table of exponent values: -** -** CREATE TABLE pow2(x INTEGER PRIMARY KEY, v TEXT); -** WITH RECURSIVE c(x,v) AS ( -** VALUES(0,'1') -** UNION ALL -** SELECT x+1, decimal_mul(v,'2') FROM c WHERE x+1<=971 -** ) INSERT INTO pow2(x,v) SELECT x, v FROM c; -** WITH RECURSIVE c(x,v) AS ( -** VALUES(-1,'0.5') -** UNION ALL -** SELECT x-1, decimal_mul(v,'0.5') FROM c WHERE x-1>=-1075 -** ) INSERT INTO pow2(x,v) SELECT x, v FROM c; -** -** Then, to compute the exact decimal representation of a floating -** point value (the value 47.49 is used in the example) do: -** -** WITH c(n) AS (VALUES(47.49)) -** ---------------^^^^^---- Replace with whatever you want -** SELECT decimal_mul(ieee754_mantissa(c.n),pow2.v) -** FROM pow2, c WHERE pow2.x=ieee754_exponent(c.n); -** -** Here is a query to show various boundry values for the binary64 -** number format: -** -** WITH c(name,bin) AS (VALUES -** ('minimum positive value', x'0000000000000001'), -** ('maximum subnormal value', x'000fffffffffffff'), -** ('minimum positive normal value', x'0010000000000000'), -** ('maximum value', x'7fefffffffffffff')) -** SELECT c.name, decimal_mul(ieee754_mantissa(c.bin),pow2.v) -** FROM pow2, c WHERE pow2.x=ieee754_exponent(c.bin); -** -*/ -/* #include "sqlite3ext.h" */ -SQLITE_EXTENSION_INIT1 -#include -#include - -/* Mark a function parameter as unused, to suppress nuisance compiler -** warnings. */ -#ifndef UNUSED_PARAMETER -# define UNUSED_PARAMETER(X) (void)(X) -#endif - -/* -** 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_BLOB - && sqlite3_value_bytes(argv[0])==sizeof(r) - ){ - const unsigned char *x = sqlite3_value_blob(argv[0]); - unsigned int i; - sqlite3_uint64 v = 0; - for(i=0; i>52; - m = a & ((((sqlite3_int64)1)<<52)-1); - if( e==0 ){ - m <<= 1; - }else{ - m |= ((sqlite3_int64)1)<<52; - } - while( e<1075 && m>0 && (m&1)==0 ){ - m >>= 1; - e++; - } - if( isNeg ) m = -m; - } - switch( *(int*)sqlite3_user_data(context) ){ - case 0: - sqlite3_snprintf(sizeof(zResult), zResult, "ieee754(%lld,%d)", - m, e-1075); - sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT); - break; - case 1: - sqlite3_result_int64(context, m); - break; - case 2: - sqlite3_result_int(context, e-1075); - break; - } - }else{ - sqlite3_int64 m, e, a; - double r; - int isNeg = 0; - m = sqlite3_value_int64(argv[0]); - e = sqlite3_value_int64(argv[1]); - - /* Limit the range of e. Ticket 22dea1cfdb9151e4 2021-03-02 */ - if( e>10000 ){ - e = 10000; - }else if( e<-10000 ){ - e = -10000; - } - - if( m<0 ){ - if( m<(-9223372036854775807LL) ) return; - isNeg = 1; - m = -m; - }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 ){ - /* Subnormal */ - if( 1-e >= 64 ){ - m = 0; - }else{ - m >>= 1-e; - } - e = 0; - }else 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); - } -} - -/* -** Functions to convert between blobs and floats. -*/ -static void ieee754func_from_blob( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - UNUSED_PARAMETER(argc); - if( sqlite3_value_type(argv[0])==SQLITE_BLOB - && sqlite3_value_bytes(argv[0])==sizeof(double) - ){ - double r; - const unsigned char *x = sqlite3_value_blob(argv[0]); - unsigned int i; - sqlite3_uint64 v = 0; - for(i=0; i>= 8; - } - sqlite3_result_blob(context, a, sizeof(r), SQLITE_TRANSIENT); - } -} - -/* -** Functions to convert between 64-bit integers and floats. -** -** The bit patterns are copied. The numeric values are different. -*/ -static void ieee754func_from_int( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - UNUSED_PARAMETER(argc); - if( sqlite3_value_type(argv[0])==SQLITE_INTEGER ){ - double r; - sqlite3_int64 v = sqlite3_value_int64(argv[0]); - memcpy(&r, &v, sizeof(r)); - sqlite3_result_double(context, r); - } -} -static void ieee754func_to_int( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - UNUSED_PARAMETER(argc); - if( sqlite3_value_type(argv[0])==SQLITE_FLOAT ){ - double r = sqlite3_value_double(argv[0]); - sqlite3_uint64 v; - memcpy(&v, &r, sizeof(v)); - sqlite3_result_int64(context, v); - } -} - -/* -** SQL Function: ieee754_inc(r,N) -** -** Move the floating point value r by N quantums and return the new -** values. -** -** Behind the scenes: this routine merely casts r into a 64-bit unsigned -** integer, adds N, then casts the value back into float. -** -** Example: To find the smallest positive number: -** -** SELECT ieee754_inc(0.0,+1); -*/ -static void ieee754inc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - double r; - sqlite3_int64 N; - sqlite3_uint64 m1, m2; - double r2; - UNUSED_PARAMETER(argc); - r = sqlite3_value_double(argv[0]); - N = sqlite3_value_int64(argv[1]); - memcpy(&m1, &r, 8); - m2 = m1 + N; - memcpy(&r2, &m2, 8); - sqlite3_result_double(context, r2); -} - - -#ifdef _WIN32 - -#endif -int sqlite3_ieee_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi -){ - static const struct { - char *zFName; - int nArg; - int iAux; - void (*xFunc)(sqlite3_context*,int,sqlite3_value**); - } aFunc[] = { - { "ieee754", 1, 0, ieee754func }, - { "ieee754", 2, 0, ieee754func }, - { "ieee754_mantissa", 1, 1, ieee754func }, - { "ieee754_exponent", 1, 2, ieee754func }, - { "ieee754_to_blob", 1, 0, ieee754func_to_blob }, - { "ieee754_from_blob", 1, 0, ieee754func_from_blob }, - { "ieee754_to_int", 1, 0, ieee754func_to_int }, - { "ieee754_from_int", 1, 0, ieee754func_from_int }, - { "ieee754_inc", 2, 0, ieee754inc }, - }; - unsigned int i; - int rc = SQLITE_OK; - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErrMsg; /* Unused parameter */ - for(i=0; i= 0 ) -** for each produced value (independent of production time ordering.) -** -** All parameters must be either integer or convertable to integer. -** The start parameter is required. -** The stop parameter defaults to (1<<32)-1 (aka 4294967295 or 0xffffffff) -** The step parameter defaults to 1 and 0 is treated as 1. -** -** Examples: -** -** SELECT * FROM generate_series(0,100,5); -** -** The query above returns integers from 0 through 100 counting by steps -** of 5. In other words, 0, 5, 10, 15, ..., 90, 95, 100. There are a total -** of 21 rows. -** -** SELECT * FROM generate_series(0,100); -** -** Integers from 0 through 100 with a step size of 1. 101 rows. -** -** SELECT * FROM generate_series(20) LIMIT 10; -** -** Integers 20 through 29. 10 rows. -** -** SELECT * FROM generate_series(0,-100,-5); -** -** Integers 0 -5 -10 ... -100. 21 rows. -** -** SELECT * FROM generate_series(0,-1); -** -** Empty sequence. -** -** HOW IT WORKS -** -** The generate_series "function" is really a virtual table with the -** following schema: -** -** CREATE TABLE generate_series( -** value, -** start HIDDEN, -** stop HIDDEN, -** step HIDDEN -** ); -** -** The virtual table also has a rowid which is an alias for the value. -** -** Function arguments in queries against this virtual table are translated -** into equality constraints against successive hidden columns. In other -** words, the following pairs of queries are equivalent to each other: -** -** SELECT * FROM generate_series(0,100,5); -** SELECT * FROM generate_series WHERE start=0 AND stop=100 AND step=5; -** -** SELECT * FROM generate_series(0,100); -** SELECT * FROM generate_series WHERE start=0 AND stop=100; -** -** SELECT * FROM generate_series(20) LIMIT 10; -** SELECT * FROM generate_series WHERE start=20 LIMIT 10; -** -** The generate_series virtual table implementation leaves the xCreate method -** set to NULL. This means that it is not possible to do a CREATE VIRTUAL -** TABLE command with "generate_series" as the USING argument. Instead, there -** is a single generate_series virtual table that is always available without -** having to be created first. -** -** The xBestIndex method looks for equality constraints against the hidden -** start, stop, and step columns, and if present, it uses those constraints -** to bound the sequence of generated values. If the equality constraints -** are missing, it uses 0 for start, 4294967295 for stop, and 1 for step. -** xBestIndex returns a small cost when both start and stop are available, -** and a very large cost if either start or stop are unavailable. This -** encourages the query planner to order joins such that the bounds of the -** series are well-defined. -** -** Update on 2024-08-22: -** xBestIndex now also looks for equality and inequality constraints against -** the value column and uses those constraints as additional bounds against -** the sequence range. Thus, a query like this: -** -** SELECT value FROM generate_series($SA,$EA) -** WHERE value BETWEEN $SB AND $EB; -** -** Is logically the same as: -** -** SELECT value FROM generate_series(max($SA,$SB),min($EA,$EB)); -** -** Constraints on the value column can server as substitutes for constraints -** on the hidden start and stop columns. So, the following two queries -** are equivalent: -** -** SELECT value FROM generate_series($S,$E); -** SELECT value FROM generate_series WHERE value BETWEEN $S and $E; -** -*/ -/* #include "sqlite3ext.h" */ -SQLITE_EXTENSION_INIT1 -#include -#include -#include -#include - -#ifndef SQLITE_OMIT_VIRTUALTABLE - -/* series_cursor is a subclass of sqlite3_vtab_cursor which will -** serve as the underlying representation of a cursor that scans -** over rows of the result. -** -** iOBase, iOTerm, and iOStep are the original values of the -** start=, stop=, and step= constraints on the query. These are -** the values reported by the start, stop, and step columns of the -** virtual table. -** -** iBase, iTerm, iStep, and bDescp are the actual values used to generate -** the sequence. These might be different from the iOxxxx values. -** For example in -** -** SELECT value FROM generate_series(1,11,2) -** WHERE value BETWEEN 4 AND 8; -** -** The iOBase is 1, but the iBase is 5. iOTerm is 11 but iTerm is 7. -** Another example: -** -** SELECT value FROM generate_series(1,15,3) ORDER BY value DESC; -** -** The cursor initialization for the above query is: -** -** iOBase = 1 iBase = 13 -** iOTerm = 15 iTerm = 1 -** iOStep = 3 iStep = 3 bDesc = 1 -** -** The actual step size is unsigned so that can have a value of -** +9223372036854775808 which is needed for querys like this: -** -** SELECT value -** FROM generate_series(9223372036854775807, -** -9223372036854775808, -** -9223372036854775808) -** ORDER BY value ASC; -** -** The setup for the previous query will be: -** -** iOBase = 9223372036854775807 iBase = -1 -** iOTerm = -9223372036854775808 iTerm = 9223372036854775807 -** iOStep = -9223372036854775808 iStep = 9223372036854775808 bDesc = 0 -*/ -/* typedef unsigned char u8; */ -typedef struct series_cursor series_cursor; -struct series_cursor { - sqlite3_vtab_cursor base; /* Base class - must be first */ - sqlite3_int64 iOBase; /* Original starting value ("start") */ - sqlite3_int64 iOTerm; /* Original terminal value ("stop") */ - sqlite3_int64 iOStep; /* Original step value */ - sqlite3_int64 iBase; /* Starting value to actually use */ - sqlite3_int64 iTerm; /* Terminal value to actually use */ - sqlite3_uint64 iStep; /* The step size */ - sqlite3_int64 iValue; /* Current value */ - u8 bDesc; /* iStep is really negative */ - u8 bDone; /* True if stepped past last element */ -}; - -/* -** Computed the difference between two 64-bit signed integers using a -** convoluted computation designed to work around the silly restriction -** against signed integer overflow in C. -*/ -static sqlite3_uint64 span64(sqlite3_int64 a, sqlite3_int64 b){ - assert( a>=b ); - return (*(sqlite3_uint64*)&a) - (*(sqlite3_uint64*)&b); -} - -/* -** Add or substract an unsigned 64-bit integer from a signed 64-bit integer -** and return the new signed 64-bit integer. -*/ -static sqlite3_int64 add64(sqlite3_int64 a, sqlite3_uint64 b){ - sqlite3_uint64 x = *(sqlite3_uint64*)&a; - x += b; - return *(sqlite3_int64*)&x; -} -static sqlite3_int64 sub64(sqlite3_int64 a, sqlite3_uint64 b){ - sqlite3_uint64 x = *(sqlite3_uint64*)&a; - x -= b; - return *(sqlite3_int64*)&x; -} - -/* -** The seriesConnect() method is invoked to create a new -** series_vtab that describes the generate_series virtual table. -** -** Think of this routine as the constructor for series_vtab objects. -** -** All this routine needs to do is: -** -** (1) Allocate the series_vtab object and initialize all fields. -** -** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the -** result set of queries against generate_series will look like. -*/ -static int seriesConnect( - sqlite3 *db, - void *pUnused, - int argcUnused, const char *const*argvUnused, - sqlite3_vtab **ppVtab, - char **pzErrUnused -){ - sqlite3_vtab *pNew; - int rc; - -/* Column numbers */ -#define SERIES_COLUMN_ROWID (-1) -#define SERIES_COLUMN_VALUE 0 -#define SERIES_COLUMN_START 1 -#define SERIES_COLUMN_STOP 2 -#define SERIES_COLUMN_STEP 3 - - (void)pUnused; - (void)argcUnused; - (void)argvUnused; - (void)pzErrUnused; - rc = sqlite3_declare_vtab(db, - "CREATE TABLE x(value,start hidden,stop hidden,step hidden)"); - if( rc==SQLITE_OK ){ - pNew = *ppVtab = sqlite3_malloc64( sizeof(*pNew) ); - if( pNew==0 ) return SQLITE_NOMEM; - memset(pNew, 0, sizeof(*pNew)); - sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); - } - return rc; -} - -/* -** This method is the destructor for series_cursor objects. -*/ -static int seriesDisconnect(sqlite3_vtab *pVtab){ - sqlite3_free(pVtab); - return SQLITE_OK; -} - -/* -** Constructor for a new series_cursor object. -*/ -static int seriesOpen(sqlite3_vtab *pUnused, sqlite3_vtab_cursor **ppCursor){ - series_cursor *pCur; - (void)pUnused; - pCur = sqlite3_malloc64( sizeof(*pCur) ); - if( pCur==0 ) return SQLITE_NOMEM; - memset(pCur, 0, sizeof(*pCur)); - *ppCursor = &pCur->base; - return SQLITE_OK; -} - -/* -** Destructor for a series_cursor. -*/ -static int seriesClose(sqlite3_vtab_cursor *cur){ - sqlite3_free(cur); - return SQLITE_OK; -} - - -/* -** Advance a series_cursor to its next row of output. -*/ -static int seriesNext(sqlite3_vtab_cursor *cur){ - series_cursor *pCur = (series_cursor*)cur; - if( pCur->iValue==pCur->iTerm ){ - pCur->bDone = 1; - }else if( pCur->bDesc ){ - pCur->iValue = sub64(pCur->iValue, pCur->iStep); - assert( pCur->iValue>=pCur->iTerm ); - }else{ - pCur->iValue = add64(pCur->iValue, pCur->iStep); - assert( pCur->iValue<=pCur->iTerm ); - } - return SQLITE_OK; -} - -/* -** Return values of columns for the row at which the series_cursor -** is currently pointing. -*/ -static int seriesColumn( - sqlite3_vtab_cursor *cur, /* The cursor */ - sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ - int i /* Which column to return */ -){ - series_cursor *pCur = (series_cursor*)cur; - sqlite3_int64 x = 0; - switch( i ){ - case SERIES_COLUMN_START: x = pCur->iOBase; break; - case SERIES_COLUMN_STOP: x = pCur->iOTerm; break; - case SERIES_COLUMN_STEP: x = pCur->iOStep; break; - default: x = pCur->iValue; break; - } - sqlite3_result_int64(ctx, x); - return SQLITE_OK; -} - -#ifndef LARGEST_UINT64 -#define LARGEST_INT64 ((sqlite3_int64)0x7fffffffffffffffLL) -#define LARGEST_UINT64 ((sqlite3_uint64)0xffffffffffffffffULL) -#define SMALLEST_INT64 ((sqlite3_int64)0x8000000000000000LL) -#endif - -/* -** The rowid is the same as the value. -*/ -static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ - series_cursor *pCur = (series_cursor*)cur; - *pRowid = pCur->iValue; - return SQLITE_OK; -} - -/* -** Return TRUE if the cursor has been moved off of the last -** row of output. -*/ -static int seriesEof(sqlite3_vtab_cursor *cur){ - series_cursor *pCur = (series_cursor*)cur; - return pCur->bDone; -} - -/* True to cause run-time checking of the start=, stop=, and/or step= -** parameters. The only reason to do this is for testing the -** constraint checking logic for virtual tables in the SQLite core. -*/ -#ifndef SQLITE_SERIES_CONSTRAINT_VERIFY -# define SQLITE_SERIES_CONSTRAINT_VERIFY 0 -#endif - -/* -** Return the number of steps between pCur->iBase and pCur->iTerm if -** the step width is pCur->iStep. -*/ -static sqlite3_uint64 seriesSteps(series_cursor *pCur){ - if( pCur->bDesc ){ - assert( pCur->iBase >= pCur->iTerm ); - return span64(pCur->iBase, pCur->iTerm)/pCur->iStep; - }else{ - assert( pCur->iBase <= pCur->iTerm ); - return span64(pCur->iTerm, pCur->iBase)/pCur->iStep; - } -} - -#if defined(SQLITE_ENABLE_MATH_FUNCTIONS) || defined(_WIN32) -/* -** Case 1 (the most common case): -** The standard math library is available so use ceil() and floor() from there. -*/ -static double seriesCeil(double r){ return ceil(r); } -static double seriesFloor(double r){ return floor(r); } -#elif defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC) -/* -** Case 2 (2nd most common): Use GCC/Clang builtins -*/ -static double seriesCeil(double r){ return __builtin_ceil(r); } -static double seriesFloor(double r){ return __builtin_floor(r); } -#else -/* -** Case 3 (rarely happens): Use home-grown ceil() and floor() routines. -*/ -static double seriesCeil(double r){ - sqlite3_int64 x; - if( r!=r ) return r; - if( r<=(-4503599627370496.0) ) return r; - if( r>=(+4503599627370496.0) ) return r; - x = (sqlite3_int64)r; - if( r==(double)x ) return r; - if( r>(double)x ) x++; - return (double)x; -} -static double seriesFloor(double r){ - sqlite3_int64 x; - if( r!=r ) return r; - if( r<=(-4503599627370496.0) ) return r; - if( r>=(+4503599627370496.0) ) return r; - x = (sqlite3_int64)r; - if( r==(double)x ) return r; - if( r<(double)x ) x--; - return (double)x; -} -#endif - -/* -** This method is called to "rewind" the series_cursor object back -** to the first row of output. This method is always called at least -** once prior to any call to seriesColumn() or seriesRowid() or -** seriesEof(). -** -** The query plan selected by seriesBestIndex is passed in the idxNum -** parameter. (idxStr is not used in this implementation.) idxNum -** is a bitmask showing which constraints are available: -** -** 0x0001: start=VALUE -** 0x0002: stop=VALUE -** 0x0004: step=VALUE -** 0x0008: descending order -** 0x0010: ascending order -** 0x0020: LIMIT VALUE -** 0x0040: OFFSET VALUE -** 0x0080: value=VALUE -** 0x0100: value>=VALUE -** 0x0200: value>VALUE -** 0x1000: value<=VALUE -** 0x2000: value0, the value of the LIMIT */ - sqlite3_int64 iOffset = 0; /* if >0, the value of the OFFSET */ - - (void)idxStrUnused; - - /* If any constraints have a NULL value, then return no rows. - ** See ticket https://sqlite.org/src/info/fac496b61722daf2 - */ - for(i=0; i