Merge trunk changes into covering-index-expr branch.

FossilOrigin-Name: 89d775ada39aed4dc532374ace02156d07dc06e8ae54a194608af0c5a582d20f
This commit is contained in:
drh
2022-11-28 16:11:10 +00:00
13 changed files with 1046 additions and 15 deletions
+1
View File
@@ -446,6 +446,7 @@ TESTSRC += \
$(TOP)/ext/expert/test_expert.c \
$(TOP)/ext/misc/amatch.c \
$(TOP)/ext/misc/appendvfs.c \
$(TOP)/ext/misc/basexx.c \
$(TOP)/ext/misc/carray.c \
$(TOP)/ext/misc/cksumvfs.c \
$(TOP)/ext/misc/closure.c \
+269
View File
@@ -0,0 +1,269 @@
/*
** 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=<your favorite SQLite checkout directory>
** *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 <assert.h>
#ifndef SQLITE_SHELL_EXTFUNCS /* Guard for #include as built-in extension. */
#include "sqlite3ext.h"
#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 UBYTE_TYPEDEF
typedef unsigned char ubyte;
# define UBYTE_TYPEDEF
#endif
static const ubyte 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) ((((ubyte)(c))<0x80)? b64DigitValues[c] : 0x80)
#define IS_BX_DIGIT(bdp) (((ubyte)(bdp))<0x80)
#define IS_BX_WS(bdp) ((bdp)==WS)
#define IS_BX_PAD(bdp) ((bdp)==PC)
#define BX_NUMERAL(dv) (b64Numerals[(ubyte)(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( ubyte *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<nbIn ) qv |= *pIn++;
}
for( nbe=3; nbe>=0; --nbe ){
char ce = (nbe<nco)? BX_NUMERAL((ubyte)(qv & 0x3f)) : PAD_CHAR;
qv >>= 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 ){
char c;
while( (c = *s) && !IS_BX_DIGIT(BX_DV_PROTO(c)) ) ++s;
return s;
}
/* Decode base64 text into a byte buffer. */
static ubyte* fromBase64( char *pIn, int ncIn, ubyte *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);
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<nti)? *pIn++ : b64Numerals[0];
ubyte bdp = BX_DV_PROTO(c);
switch( bdp ){
case ND:
/* Treat dark non-digits as pad, but they terminate decode too. */
ncIn = 0;
/* fall thru */
case WS:
/* Treat whitespace as pad and terminate this group.*/
nti = nac;
/* fall thru */
case PC:
bdp = 0;
--nbo;
/* fall thru */
default: /* bdp is the digit value. */
qv = qv<<6 | bdp;
break;
}
}
switch( nbo ){
case 3:
pOut[2] = (qv) & 0xff;
case 2:
pOut[1] = (qv>>8) & 0xff;
case 1:
pOut[0] = (qv>>16) & 0xff;
}
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[]){
int nb, nc, nv = sqlite3_value_bytes(av[0]);
int nvMax = sqlite3_limit(sqlite3_context_db_handle(context),
SQLITE_LIMIT_LENGTH, -1);
char *cBuf;
ubyte *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;
}
cBuf = sqlite3_malloc(nc);
if( !cBuf ) goto memFail;
bBuf = (ubyte*)sqlite3_value_blob(av[0]);
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;
}
bBuf = sqlite3_malloc(nb);
if( !bBuf ) goto memFail;
cBuf = (char *)sqlite3_value_text(av[0]);
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
__declspec(dllexport)
#endif
int sqlite3_base_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. */
+437
View File
@@ -0,0 +1,437 @@
/*
** 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=<your favorite SQLite checkout directory>
** 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 <stdio.h>
#include <memory.h>
#include <string.h>
#include <assert.h>
#ifndef OMIT_BASE85_CHECKER
# include <ctype.h>
#endif
#ifndef BASE85_STANDALONE
#ifndef SQLITE_SHELL_EXTFUNCS /* Guard for #include as built-in extension. */
# include "sqlite3ext.h"
#endif
SQLITE_EXTENSION_INIT1;
#else
# ifdef _WIN32
# include <io.h>
# include <fcntl.h>
# else
# define setmode(fd,m)
# endif
static char *zHelp =
"Usage: base85 <dirFlag> <binFile>\n"
" <dirFlag> is either -r to read or -w to write <binFile>,\n"
" content to be converted to/from base85 on stdout/stdin.\n"
" <binFile> 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 UBYTE_TYPEDEF
typedef unsigned char ubyte;
# define UBYTE_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 ubyte 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 ubyte base85DigitValue( char c ){
ubyte dv = (ubyte)(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 ){
char c;
while( (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( ubyte 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( ubyte *pIn, int nbIn, char *pOut, char *pSep ){
int nCol = 0;
while( nbIn >= 4 ){
int nco = 5;
unsigned long qbv = (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 ){
ubyte dv = (ubyte)(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 ubyte* fromBase85( char *pIn, int ncIn, ubyte *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);
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++;
ubyte 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;
case 3:
*pOut++ = (qv >> 16)&0xff;
case 2:
*pOut++ = (qv >> 8)&0xff;
case 1:
*pOut++ = qv&0xff;
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[]){
int nb, nc, nv = sqlite3_value_bytes(av[0]);
int nvMax = sqlite3_limit(sqlite3_context_db_handle(context),
SQLITE_LIMIT_LENGTH, -1);
char *cBuf;
ubyte *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;
}
cBuf = sqlite3_malloc(nc);
if( !cBuf ) goto memFail;
bBuf = (ubyte*)sqlite3_value_blob(av[0]);
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;
}
bBuf = sqlite3_malloc(nb);
if( !bBuf ) goto memFail;
cBuf = (char *)sqlite3_value_text(av[0]);
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
__declspec(dllexport)
#endif
int sqlite3_base_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;
ubyte 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
+84
View File
@@ -0,0 +1,84 @@
/*
** 2022-11-20
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
**
** This source allows multiple SQLite extensions to be either: combined
** into a single runtime-loadable library; or built into the SQLite shell
** using a preprocessing convention set by src/shell.c.in (and shell.c).
**
** Presently, it combines the base64.c and base85.c extensions. However,
** it can be used as a template for other combinations.
**
** Example usages:
**
** - Build a runtime-loadable extension from SQLite checkout directory:
** *Nix, OSX: gcc -O2 -shared -I. -fPIC -o basexx.so ext/misc/basexx.c
** Win32: cl /Os -I. ext/misc/basexx.c -link -dll -out:basexx.dll
**
** - Incorporate as built-in in sqlite3 shell:
** *Nix, OSX with gcc on a like platform:
** export mop1=-DSQLITE_SHELL_EXTSRC=ext/misc/basexx.c
** export mop2=-DSQLITE_SHELL_EXTFUNCS=BASEXX
** make sqlite3 "OPTS=$mop1 $mop2"
** Win32 with Microsoft toolset on Windows:
** set mop1=-DSQLITE_SHELL_EXTSRC=ext/misc/basexx.c
** set mop2=-DSQLITE_SHELL_EXTFUNCS=BASEXX
** set mops="OPTS=%mop1% %mop2%"
** nmake -f Makefile.msc sqlite3.exe %mops%
*/
#ifndef SQLITE_SHELL_EXTFUNCS /* Guard for #include as built-in extension. */
# include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1;
#endif
static void init_api_ptr(const sqlite3_api_routines *pApi){
SQLITE_EXTENSION_INIT2(pApi);
}
#undef SQLITE_EXTENSION_INIT1
#define SQLITE_EXTENSION_INIT1 /* */
#undef SQLITE_EXTENSION_INIT2
#define SQLITE_EXTENSION_INIT2(v) (void)v
/* These next 2 undef's are only needed because the entry point names
* collide when formulated per the rules stated for loadable extension
* entry point names that will be deduced from the file basenames.
*/
#undef sqlite3_base_init
#define sqlite3_base_init sqlite3_base64_init
#include "base64.c"
#undef sqlite3_base_init
#define sqlite3_base_init sqlite3_base85_init
#include "base85.c"
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_basexx_init(sqlite3 *db, char **pzErr,
const sqlite3_api_routines *pApi){
init_api_ptr(pApi);
int rc1 = BASE64_INIT(db);
int rc2 = BASE85_INIT(db);
int rc = SQLITE_OK;
if( rc1==SQLITE_OK && rc2==SQLITE_OK ){
BASE64_EXPOSE(db, pzErr);
BASE64_EXPOSE(db, pzErr);
return SQLITE_OK;
}else{
return SQLITE_ERROR;
}
}
# define BASEXX_INIT(db) sqlite3_basexx_init(db, 0, 0)
# define BASEXX_EXPOSE(db, pzErr) /* Not needed, ..._init() does this. */
+16
View File
@@ -29,6 +29,22 @@
This file represents an implementation detail of a larger piece of
code, and not a public interface. Its details may change at any time
and are not intended to be used by any client-level code.
2022-11-27: Chrome v108 changes some async methods to synchronous, as
documented at:
https://developer.chrome.com/blog/sync-methods-for-accesshandles/
We cannot change to the sync forms at this point without breaking
clients who use Chrome v104-ish or higher. truncate(), getSize(),
flush(), and close() are now (as of v108) synchronous. Calling them
with an "await", as we have to for the async forms, is still legal
with the sync forms but is superfluous. Calling the async forms with
theFunc().then(...) is not compatible with the change to
synchronous, but we do do not use those APIs that way. i.e. we don't
_need_ to change anything for this, but at some point (after Chrome
versions (approximately) 104-107 are extinct) should change our
usage of those methods to remove the "await".
*/
"use strict";
const toss = function(...args){throw new Error(args.join(' '))};
+16 -12
View File
@@ -1,9 +1,9 @@
C Rework\sthe\scovering\sindex\schecking\sroutine,\swhereIsCoveringIndex(),\sso\sthat\nit\scan\sreturn\sa\s"maybe"\sresult\sfor\saggregate\squeries\swhere\swe\sare\snot\sexactly\nsure.\s\sThe\sindex\sis\sscored\sas\sif\sit\sis\scovering,\sbut\sthe\smain\stable\sis\nstill\sopened.
D 2022-11-28T15:23:53.775
C Merge\strunk\schanges\sinto\scovering-index-expr\sbranch.
D 2022-11-28T16:11:10.036
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F Makefile.in 9a1228fd6406cc607958ccf1386a9a8f74f8255a7e98bc9c0a2792b56bd3a309
F Makefile.in c223963d7b0828f26cb62ea3e0f583d26839b7d3ef0d1cca87f35c4b222ff01b
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
F Makefile.msc e7a564ceec71f0d9666031d5638cf0d4f88b050b44e8df5d32125137cd259ac0
F README.md 8b8df9ca852aeac4864eb1e400002633ee6db84065bd01b78c33817f97d31f5e
@@ -289,6 +289,9 @@ F ext/misc/README.md d6dd0fe1d8af77040216798a6a2b0c46c73054d2f0ea544fbbcdccf6f23
F ext/misc/amatch.c e3ad5532799cee9a97647f483f67f43b38796b84b5a8c60594fe782a4338f358
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
F ext/misc/appendvfs.c 9642c7a194a2a25dca7ad3e36af24a0a46d7702168c4ad7e59c9f9b0e16a3824
F ext/misc/base64.c fb140039d4e15710298e28cafe12d2bdff1b927fc57540cbcd07996f82bf9800 x
F ext/misc/base85.c ace591246855806a70e63eb6705ce8736f4b782da2137bdbb5d39cc337346e0d
F ext/misc/basexx.c b37ea21f00deea1029d2ddc670f5701d9370ae06f7d173c5bed79d0f26a67ec1
F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0edb2a
F ext/misc/btreeinfo.c d28ce349b40054eaa9473e835837bad7a71deec33ba13e39f963d50933bfa0f9
F ext/misc/carray.c b752f46411e4e47e34dce6f0c88bc8e51bb821ba9e49bfcd882506451c928f69
@@ -506,7 +509,7 @@ F ext/wasm/api/sqlite3-api-opfs.js e98a8bd67dea8c20b0ec17332698b44658a6fbc4be18d
F ext/wasm/api/sqlite3-api-prologue.js 7fce4c6a138ec3d7c285b7c125cee809e6b668d2cb0d2328a1b790b7037765bd
F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f
F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3
F ext/wasm/api/sqlite3-opfs-async-proxy.js d933d4a3c84e6dc614b57355fc9029645cfcdfbfde096ed42f4c979a6f60c18a
F ext/wasm/api/sqlite3-opfs-async-proxy.js 798383f6b46fd5dac122d6e35962d25b10401ddb825b5c66df1d21e6b1d8aacc
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
F ext/wasm/api/sqlite3-wasm.c 8b32787a3b6bb2990cbaba2304bd5b75a9652acbc8d29909b3279019b6cbaef5
F ext/wasm/api/sqlite3-worker1-promiser.js 0c7a9826dbf82a5ed4e4f7bf7816e825a52aff253afbf3350431f5773faf0e4b
@@ -642,7 +645,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
F src/resolve.c efea4e5fbecfd6d0a9071b0be0d952620991673391b6ffaaf4c277b0bb674633
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c c1eb8f3ee25152327f2e7e87db8cea549e57c104b63638bff4fc584d479c33f0
F src/shell.c.in 09cb15d7421c475f2d308f6a4312d8d690916ea5cb62ea1618f2f4ce5703af35
F src/shell.c.in 9fda74d40b206a707aaa69fc5dc38e2c6a9137a3f4a1dcd7af581d59d92c063c
F src/sqlite.h.in 100fc660c2f19961b8ed8437b9d53d687de2f8eb2b96437ec6da216adcb643ca
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h c4b9fa7a7e2bcdf850cfeb4b8a91d5ec47b7a00033bc996fd2ee96cbf2741f5f
@@ -651,7 +654,7 @@ F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a3
F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F src/tclsqlite.c 4e64ba300a5a26e0f1170e09032429faeb65e45e8f3d1a7833e8edb69fc2979e
F src/test1.c 40c9a40975512985762f87b83d0c63e4904833a9fe78cbcca664a37095301b1d
F src/test1.c 09ad3f2bf5f0efe70eb16e460054954b36be8ed09dfcafa0642b37d25d379f6f
F src/test2.c 827446e259a3b7ab949da1542953edda7b5117982576d3e6f1c24a0dd20a5cef
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
F src/test4.c 4533b76419e7feb41b40582554663ed3cd77aaa54e135cf76b3205098cd6e664
@@ -707,7 +710,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c 1305797eab3542a0896b552c6e7669c972c1468e11e92b370533c1f37a37082b
F src/treeview.c 29b1dc7e0f84ba090734febe27393d4719682af0cae1b902d5ebf0236ecebea4
F src/trigger.c 4163ada044af89d51caba1cb713a73165347b2ec05fe84a283737c134d61fcd5
F src/trigger.c 5e68b790f022b8dafbfb0eb244786512a95c9575fc198719d2557d73e5795858
F src/update.c 5b0302c47cf31b533d5dff04c497ca1d8b9d89c39727e633fbe7b882fd5ac5aa
F src/upsert.c 5303dc6c518fa7d4b280ec65170f465c7a70b7ac2b22491598f6d0b4875b3145
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
@@ -813,6 +816,7 @@ F test/backup_ioerr.test 4c3c7147cee85b024ecf6e150e090c32fdbb5135
F test/backup_malloc.test 0c9abdf74c51e7bedb66d504cd684f28d4bd4027
F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f
F test/badutf2.test f310fd3b24a491b6b77bccdf14923b85d6ebcce751068c180d93a6b8ff854399
F test/basexx1.test d8a50f0744b93dca656625597bcd3499ff4b9a4ea2a82432b119b7d46e3e0c08
F test/bc_common.tcl b5e42d80305be95697e6370e015af571e5333a1c
F test/bestindex1.test 856a453dff8c68b4568601eed5a8b5e20b4763af9229f3947c215729ed878db0
F test/bestindex2.test 394ff8fbf34703391247116d6a44e1c50ee7282236ee77909044573cefc37bc0
@@ -1421,7 +1425,7 @@ F test/reindex.test cd9d6021729910ece82267b4f5e1b5ac2911a7566c43b43c176a6a4732e2
F test/releasetest_data.tcl 0db8aee0c348090fd06da47020ab4ed8ec692e0723427b2f3947d4dfb806f3b0
F test/resetdb.test 8062cf10a09d8c048f8de7711e94571c38b38168db0e5877ba7561789e5eeb2b
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
F test/returning1.test c43b8370a351f77aec6d71f4a2cde59b849369ed1933261a2c2c69e23e34ff5e
F test/returning1.test 1366e04566cfe1a082d17b1e0f195ec64473c79374b3a5d4ae00c43d885dea31
F test/returningfault.test ae4c4b5e8745813287a359d9ccdb9d5c883c2e68afb18fb0767937d5de5692a4
F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa
F test/rollback2.test 3f3a4e20401825017df7e7671e9f31b6de5fae5620c2b9b49917f52f8c160a8f
@@ -1497,7 +1501,7 @@ F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
F test/shell1.test e4b4de56f454708e0747b52915135baa2cbfec4965406d6eaf02a4a5c22a9880
F test/shell2.test c536c2aab4852608f8a606262330797abc4d964a4c2c782a7760f54ea1f17a6a
F test/shell3.test 91febeac0412812bf6370abb8ed72700e32bf8f9878849414518f662dfd55e8a
F test/shell4.test 7dc8a515705bc093d8ffe381670e8fa7a969661e8ed177c35c847e3c6dfc35e2
F test/shell4.test 9abd0c12a7e20a4c49e84d5be208d2124fa6c09e728f56f1f4bee0f02853935f
F test/shell5.test c8b6c54f26ec537f8558273d7ed293ca3725ef42e6b12b8f151718628bd1473b
F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f
@@ -2060,8 +2064,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 17ebcf316b91042c823eea7bb6f1309325023cb5c70538cdb2ce932caee2ef05
R 254ab4db9b1e239ec16eb2e1a31dc657
P b8eec4214363192e6f3e12b3faa5810d8269a5fdaecab3ec09b02e5002cf798a b44ab10c49bc2895483a9d40813be3798710ee713cc4bf04e449dce55a68452a
R 5944640ae5b4a3237e1d8a4c46c48db4
U drh
Z 489a805b1f3c740affbc27a0febf881c
Z 9aa95e661b7edb77eed478b829e7796d
# Remove this line to create a well-formed Fossil manifest.
+1 -1
View File
@@ -1 +1 @@
b8eec4214363192e6f3e12b3faa5810d8269a5fdaecab3ec09b02e5002cf798a
89d775ada39aed4dc532374ace02156d07dc06e8ae54a194608af0c5a582d20f
+34 -1
View File
@@ -1072,6 +1072,9 @@ INCLUDE ../ext/recover/dbdata.c
INCLUDE ../ext/recover/sqlite3recover.c
# endif
#endif
#ifdef SQLITE_SHELL_EXTSRC
# include SHELL_STRINGIFY(SQLITE_SHELL_EXTSRC)
#endif
#if defined(SQLITE_ENABLE_SESSION)
/*
@@ -5117,6 +5120,7 @@ static void open_db(ShellState *p, int openFlags){
}
exit(1);
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
sqlite3_enable_load_extension(p->db, 1);
#endif
@@ -5139,6 +5143,34 @@ static void open_db(ShellState *p, int openFlags){
sqlite3_sqlar_init(p->db, 0, 0);
}
#endif
#ifdef SQLITE_SHELL_EXTFUNCS
/* Create a preprocessing mechanism for extensions to make
* their own provisions for being built into the shell.
* This is a short-span macro. See further below for usage.
*/
#define SHELL_SUB_MACRO(base, variant) base ## _ ## variant
#define SHELL_SUBMACRO(base, variant) SHELL_SUB_MACRO(base, variant)
/* Let custom-included extensions get their ..._init() called.
* The WHATEVER_INIT( db, pzErrorMsg, pApi ) macro should cause
* the extension's sqlite3_*_init( db, pzErrorMsg, pApi )
* inititialization routine to be called.
*/
{
int irc = SHELL_SUBMACRO(SQLITE_SHELL_EXTFUNCS, INIT)(p->db);
/* Let custom-included extensions expose their functionality.
* The WHATEVER_EXPOSE( db, pzErrorMsg ) macro should cause
* the SQL functions, virtual tables, collating sequences or
* VFS's implemented by the extension to be registered.
*/
if( irc==SQLITE_OK
|| irc==SQLITE_OK_LOAD_PERMANENTLY ){
SHELL_SUBMACRO(SQLITE_SHELL_EXTFUNCS, EXPOSE)(p->db, 0);
}
#undef SHELL_SUB_MACRO
#undef SHELL_SUBMACRO
}
#endif
sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0,
shellAddSchemaName, 0, 0);
sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0,
@@ -5159,6 +5191,7 @@ static void open_db(ShellState *p, int openFlags){
sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0,
editFunc, 0, 0);
#endif
if( p->openMode==SHELL_OPEN_ZIPFILE ){
char *zSql = sqlite3_mprintf(
"CREATE VIRTUAL TABLE zip USING zipfile(%Q);", zDbFilename);
@@ -10658,7 +10691,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else{
output_file_close(p->traceOut);
p->traceOut = output_file_open(azArg[1], 0);
p->traceOut = output_file_open(z, 0);
}
}
if( p->traceOut==0 ){
+2
View File
@@ -7709,6 +7709,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
){
extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_appendvfs_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_basexx_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_carray_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_csv_init(sqlite3*,char**,const sqlite3_api_routines*);
@@ -7740,6 +7741,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
} aExtension[] = {
{ "amatch", sqlite3_amatch_init },
{ "appendvfs", sqlite3_appendvfs_init },
{ "basexx", sqlite3_basexx_init },
{ "carray", sqlite3_carray_init },
{ "closure", sqlite3_closure_init },
{ "csv", sqlite3_csv_init },
+1 -1
View File
@@ -61,7 +61,7 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
if( pTrig->pTabSchema==pTab->pSchema
&& pTrig->table
&& 0==sqlite3StrICmp(pTrig->table, pTab->zName)
&& pTrig->pTabSchema!=pTmpSchema
&& (pTrig->pTabSchema!=pTmpSchema || pTrig->bReturning)
){
pTrig->pNext = pList;
pList = pTrig;
+155
View File
@@ -0,0 +1,155 @@
# 2022 November 22
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix basexx
if {[catch {load_static_extension db basexx} error]} {
puts "Skipping basexx tests, hit load error: $error"
finish_test; return
}
# Empty blobs encode to empty strings.
do_execsql_test 100 {
SELECT base64(x'')||base85(x'');
} {{}}
# Empty strings decode to empty blobs.
do_execsql_test 101 {
SELECT hex(x'01'||base64('')||base85('')||x'02');
} {0102}
# Basic base64 encoding
do_execsql_test 102 {
SELECT base64(x'000102030405');
SELECT base64(x'0001020304');
SELECT base64(x'00010203');
} {{AAECAwQF
} {AAECAwQ=
} {AAECAw==
}}
# Basic base64 decoding with pad chars
do_execsql_test 103 {
SELECT hex(base64('AAECAwQF'));
SELECT hex(base64('AAECAwQ='));
SELECT hex(base64('AAECAw=='));
} {000102030405 0001020304 00010203}
# Basic base64 decoding without pad chars and with whitespace
do_execsql_test 104 {
SELECT hex(base64(' AAECAwQF '));
SELECT hex(base64(' AAECAwQ'));
SELECT hex(base64('AAECAw '));
} {000102030405 0001020304 00010203}
# Basic base85 encoding
do_execsql_test 105 {
SELECT base85(x'000102030405');
SELECT base85(x'0001020304');
SELECT base85(x'00010203');
} {{##/2,#2/
} {##/2,#*
} {##/2,
}}
# Basic base85 decoding with and without whitespace
do_execsql_test 106 {
SELECT hex(base85('##/2,#2/'));
SELECT hex(base85('##/2,#*'));
SELECT hex(base85('##/2,'));
SELECT hex(base85(' ##/2,#2/ '));
SELECT hex(base85(' ##/2,#*'));
SELECT hex(base85('##/2, '));
} {000102030405 0001020304 00010203 000102030405 0001020304 00010203}
# Round-trip some random blobs.
do_execsql_test 107 {
CREATE TEMP TABLE rb( len int, b blob ) STRICT;
INSERT INTO rb(len) VALUES (1),(2),(3),(4),(5),(150),(151),(152),(153),(1054);
UPDATE rb SET b = randomblob(len);
SELECT len, base64(base64(b))=b, base85(base85(b))=b
FROM rb ORDER BY len;
} {1 1 1 2 1 1 3 1 1 4 1 1 5 1 1 150 1 1 151 1 1 152 1 1 153 1 1 1054 1 1}
# Same round-trip but with space or junk prepended and/or appended or not.
do_execsql_test 108 {
CREATE TEMP TABLE junk(j text, rank int);
INSERT INTO junk VALUES ('',0),(' ',1),('~',2);
SELECT len, base64(j.j||base64(b)||j.j)=b, base85(j.j||base85(b)||j.j)=b
FROM rb r, junk j WHERE j.rank=(r.len+r.len/25)%3 ORDER BY len;
} {1 1 1 2 1 1 3 1 1 4 1 1 5 1 1 150 1 1 151 1 1 152 1 1 153 1 1 1054 1 1}
# Exercise the fail-on-too-large result feature.
set inLimit [sqlite3_limit db SQLITE_LIMIT_LENGTH -1]
sqlite3_limit db SQLITE_LIMIT_LENGTH 1300
do_catchsql_test 109 {
SELECT len, base64(b) FROM rb WHERE len>200;
} {1 {blob expanded to base64 too big}}
do_catchsql_test 110 {
SELECT len, base85(b) FROM rb WHERE len>200;
} {1 {blob expanded to base85 too big}}
do_catchsql_test 111 {
SELECT length(base85(b))=1335 FROM rb WHERE len=1054;
} {1 {blob expanded to base85 too big}}
sqlite3_limit db SQLITE_LIMIT_LENGTH $inLimit
# Exercise is_base85(t)
do_execsql_test 112 {
SELECT is_base85(' '||base85(x'123456')||char(10)),
is_base85('#$%&*+,-./0123456789:;<=>?@'
||'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
||'[\]^_`'
||'abcdefghijklmnopqrstuvwxyz'),
is_base85('!'), is_base85('"'), is_base85(''''), is_base85('('),
is_base85(')'), is_base85(char(123)), is_base85('|'), is_base85(char(125)),
is_base85('~'), is_base85(char(127));
} {1 1 0 0 0 0 0 0 0 0 0 0}
do_execsql_test 113 {
SELECT is_base85(NULL) IS NULL;
} {1}
do_catchsql_test 114 {
SELECT is_base85(1);
} {1 {is_base85 accepts only text or NULL}}
do_catchsql_test 115 {
SELECT is_base85(1.1);
} {1 {is_base85 accepts only text or NULL}}
do_catchsql_test 116 {
SELECT is_base85(x'00');
} {1 {is_base85 accepts only text or NULL}}
# Round-trip many bigger random blobs.
do_execsql_test 117 {
CREATE TABLE bs(b blob, num);
INSERT INTO bs SELECT randomblob(4000 + n%3), n
FROM (
WITH RECURSIVE seq(n) AS (
VALUES(1) UNION ALL SELECT n+1
FROM seq WHERE n<100
) SELECT n FROM seq);
SELECT num FROM bs WHERE base64(base64(b))!=b;
SELECT num FROM bs WHERE base85(base85(b))!=b;
} {}
finish_test
+24
View File
@@ -376,4 +376,28 @@ do_execsql_test 16.1 {
SELECT * FROM t2;
} {1 2 3 a b c}
foreach {tn temp} {
1 ""
2 TEMP
} {
reset_db
do_execsql_test 17.$tn.0 "
CREATE $temp TABLE foo (
fooid INTEGER PRIMARY KEY,
fooval INTEGER NOT NULL UNIQUE,
refcnt INTEGER NOT NULL DEFAULT 1
);
"
do_execsql_test 17.$tn.1 {
INSERT INTO foo (fooval) VALUES (17), (4711), (17)
ON CONFLICT DO
UPDATE SET refcnt = refcnt+1
RETURNING fooid;
} {
1 2 1
}
}
finish_test
+6
View File
@@ -125,6 +125,12 @@ SELECT * FROM t1;}}
do_test shell4-2.5 {
catchcmd ":memory:" "CREATE TABLE t1(x);\n.trace stdout\nSELECT * FROM t1;"
} {0 {SELECT * FROM t1;}}
do_test shell4-2.6 {
catchcmd ":memory:" {
CREATE TABLE t1(x);
.trace --stmt stdout
SELECT * FROM t1;}
} {0 {SELECT * FROM t1;}}
}
do_test shell4-3.1 {