mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-27 20:41:58 +03:00
Merge trunk changes into this branch.
FossilOrigin-Name: 4a26a4e0015bc42b1d007def3750caf7baefe429270a295cc2f4499c98c07247
This commit is contained in:
@ -428,6 +428,8 @@ do_execsql_test 5.0 {
|
||||
|
||||
WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100)
|
||||
INSERT INTO t2 SELECT (i-1)/20, (i-1)/5 FROM s;
|
||||
|
||||
CREATE INDEX i1 ON t1( lower(a) );
|
||||
}
|
||||
do_candidates_test 5.1 {
|
||||
SELECT * FROM t1,t2 WHERE (b=? OR a=?) AND (c=? OR d=?)
|
||||
@ -457,6 +459,7 @@ do_execsql_test 5.3 {
|
||||
ANALYZE;
|
||||
SELECT * FROM sqlite_stat1 ORDER BY 1, 2;
|
||||
} {
|
||||
t1 i1 {100 50}
|
||||
t1 t1_idx_00000061 {100 50}
|
||||
t1 t1_idx_00000062 {100 20}
|
||||
t1 t1_idx_000123a7 {100 50 17}
|
||||
@ -491,4 +494,17 @@ USE TEMP B-TREE FOR ORDER BY
|
||||
}}
|
||||
}
|
||||
|
||||
do_execsql_test 6.0 {
|
||||
CREATE TABLE x1(a, b, c, d);
|
||||
CREATE INDEX x1ab ON x1(a, lower(b));
|
||||
CREATE INDEX x1dcba ON x1(d, b+c, a);
|
||||
}
|
||||
|
||||
do_candidates_test 6.1 {
|
||||
SELECT * FROM x1 WHERE b=? ORDER BY a;
|
||||
} {
|
||||
CREATE INDEX x1_idx_0001267f ON x1(b, a);
|
||||
CREATE INDEX x1_idx_00000062 ON x1(b);
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
@ -1623,6 +1623,12 @@ static int idxPopulateOneStat1(
|
||||
const char *zComma = zCols==0 ? "" : ", ";
|
||||
const char *zName = (const char*)sqlite3_column_text(pIndexXInfo, 0);
|
||||
const char *zColl = (const char*)sqlite3_column_text(pIndexXInfo, 1);
|
||||
if( zName==0 ){
|
||||
/* This index contains an expression. Ignore it. */
|
||||
sqlite3_free(zCols);
|
||||
sqlite3_free(zOrder);
|
||||
return sqlite3_reset(pIndexXInfo);
|
||||
}
|
||||
zCols = idxAppendText(&rc, zCols,
|
||||
"%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %s",
|
||||
zComma, zName, nCol, zName, zColl
|
||||
|
@ -40,7 +40,7 @@
|
||||
** modification-time of the target file is set to this value before
|
||||
** returning.
|
||||
**
|
||||
** If three or more arguments are passed to this function and an
|
||||
** If five or more arguments are passed to this function and an
|
||||
** error is encountered, an exception is raised.
|
||||
**
|
||||
** READFILE(FILE):
|
||||
@ -110,6 +110,13 @@ SQLITE_EXTENSION_INIT1
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* When used as part of the CLI, the sqlite3_stdio.h module will have
|
||||
** been included before this one. In that case use the sqlite3_stdio.h
|
||||
** #defines. If not, create our own for fopen().
|
||||
*/
|
||||
#ifndef _SQLITE3_STDIO_H_
|
||||
# define sqlite3_fopen fopen
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Structure of the fsdir() table-valued function
|
||||
@ -142,7 +149,7 @@ static void readFileContents(sqlite3_context *ctx, const char *zName){
|
||||
sqlite3 *db;
|
||||
int mxBlob;
|
||||
|
||||
in = fopen(zName, "rb");
|
||||
in = sqlite3_fopen(zName, "rb");
|
||||
if( in==0 ){
|
||||
/* File does not exist or is unreadable. Leave the result set to NULL. */
|
||||
return;
|
||||
@ -397,7 +404,7 @@ static int writeFile(
|
||||
sqlite3_int64 nWrite = 0;
|
||||
const char *z;
|
||||
int rc = 0;
|
||||
FILE *out = fopen(zFile, "wb");
|
||||
FILE *out = sqlite3_fopen(zFile, "wb");
|
||||
if( out==0 ) return 1;
|
||||
z = (const char*)sqlite3_value_blob(pData);
|
||||
if( z ){
|
||||
|
@ -196,7 +196,8 @@ static void hash_step_vformat(
|
||||
** zOut[]. zOut[] must be at least 41 bytes long. */
|
||||
static void hash_finish(
|
||||
SHA1Context *p, /* The SHA1 context to finish and render */
|
||||
char *zOut /* Store hexadecimal hash here */
|
||||
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];
|
||||
@ -215,11 +216,15 @@ static void hash_finish(
|
||||
for (i = 0; i < 20; i++){
|
||||
digest[i] = (unsigned char)((p->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
|
||||
}
|
||||
for(i=0; i<20; i++){
|
||||
zOut[i*2] = zEncode[(digest[i]>>4)&0xf];
|
||||
zOut[i*2+1] = zEncode[digest[i] & 0xf];
|
||||
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;
|
||||
}
|
||||
zOut[i*2]= 0;
|
||||
}
|
||||
/* End of the hashing logic
|
||||
*****************************************************************************/
|
||||
@ -251,8 +256,13 @@ static void sha1Func(
|
||||
}else{
|
||||
hash_step(&cx, sqlite3_value_text(argv[0]), nByte);
|
||||
}
|
||||
hash_finish(&cx, zOut);
|
||||
sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
|
||||
if( sqlite3_user_data(context)!=0 ){
|
||||
hash_finish(&cx, zOut, 1);
|
||||
sqlite3_result_blob(context, zOut, 20, SQLITE_TRANSIENT);
|
||||
}else{
|
||||
hash_finish(&cx, zOut, 0);
|
||||
sqlite3_result_blob(context, zOut, 40, SQLITE_TRANSIENT);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -365,7 +375,7 @@ static void sha1QueryFunc(
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
hash_finish(&cx, zOut);
|
||||
hash_finish(&cx, zOut, 0);
|
||||
sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
@ -379,11 +389,17 @@ int sqlite3_sha_init(
|
||||
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);
|
||||
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,
|
||||
|
211
ext/misc/sqlite3_stdio.c
Normal file
211
ext/misc/sqlite3_stdio.c
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
** 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 <windows.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "sqlite3.h"
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/*
|
||||
** If the SQLITE_U8TEXT_ONLY option is defined, then only use
|
||||
** _O_U8TEXT, _O_WTEXT, and similar together with the UTF-16
|
||||
** interfaces to the Windows CRT. The use of ANSI-only routines
|
||||
** like fputs() and ANSI modes like _O_TEXT and _O_BINARY is
|
||||
** avoided.
|
||||
**
|
||||
** The downside of using SQLITE_U8TEXT_ONLY is that it becomes
|
||||
** impossible to output a bare newline character (0x0a) - that is,
|
||||
** a newline that is not preceded by a carriage return (0x0d).
|
||||
** And without that capability, sometimes the output will be slightly
|
||||
** incorrect, as extra 0x0d characters will have been inserted where
|
||||
** they do not belong.
|
||||
**
|
||||
** The SQLITE_U8TEXT_STDIO compile-time option is a compromise.
|
||||
** It always enables _O_WTEXT or similar for stdin, stdout, stderr,
|
||||
** but allows other streams to be _O_TEXT and/or O_BINARY. The
|
||||
** SQLITE_U8TEXT_STDIO option has the same downside as SQLITE_U8TEXT_ONLY
|
||||
** in that stray 0x0d characters might appear where they ought not, but
|
||||
** at least with this option those characters only appear on standard
|
||||
** I/O streams, and not on new streams that might be created by the
|
||||
** application using sqlite3_fopen() or sqlite3_popen().
|
||||
*/
|
||||
#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
|
||||
|
||||
/*
|
||||
** 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 = malloc( (sz1+1)*sizeof(b1[0]) );
|
||||
b2 = malloc( (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);
|
||||
}
|
||||
free(b1);
|
||||
free(b2);
|
||||
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 = malloc( (sz1+1)*sizeof(b1[0]) );
|
||||
b2 = malloc( (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);
|
||||
}
|
||||
free(b1);
|
||||
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 = malloc( sz*sizeof(wchar_t) );
|
||||
if( b1==0 ) return 0;
|
||||
_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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Work-alike for fputs() from the standard C library.
|
||||
*/
|
||||
int sqlite3_fputs(const char *z, FILE *out){
|
||||
if( UseWtextForOutput(out) ){
|
||||
/* When writing to the command-prompt in Windows, it is necessary
|
||||
** to use _O_WTEXT input mode and write UTF-16 characters.
|
||||
*/
|
||||
int sz = (int)strlen(z);
|
||||
wchar_t *b1 = malloc( (sz+1)*sizeof(wchar_t) );
|
||||
if( b1==0 ) return 0;
|
||||
sz = MultiByteToWideChar(CP_UTF8, 0, z, sz, b1, sz);
|
||||
b1[sz] = 0;
|
||||
_setmode(_fileno(out), _O_U8TEXT);
|
||||
fputws(b1, out);
|
||||
sqlite3_free(b1);
|
||||
return 0;
|
||||
}else{
|
||||
/* Writing to a file or other destination, just write bytes without
|
||||
** any translation. */
|
||||
return fputs(z, out);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Work-alike for fprintf() from the standard C library.
|
||||
*/
|
||||
int sqlite3_fprintf(FILE *out, const char *zFormat, ...){
|
||||
int rc;
|
||||
if( UseWtextForOutput(out) ){
|
||||
/* When writing to the command-prompt in Windows, it is necessary
|
||||
** to use _O_WTEXT input mode and write UTF-16 characters.
|
||||
*/
|
||||
char *z;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, zFormat);
|
||||
z = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
sqlite3_fputs(z, out);
|
||||
rc = (int)strlen(z);
|
||||
sqlite3_free(z);
|
||||
}else{
|
||||
/* Writing to a file or other destination, just write bytes without
|
||||
** any translation. */
|
||||
va_list ap;
|
||||
va_start(ap, zFormat);
|
||||
rc = vfprintf(out, zFormat, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the mode for an output stream. mode argument is typically _O_BINARY or
|
||||
** _O_TEXT.
|
||||
*/
|
||||
void sqlite3_fsetmode(FILE *fp, int mode){
|
||||
if( !UseWtextForOutput(fp) ){
|
||||
fflush(fp);
|
||||
_setmode(_fileno(fp), mode);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* defined(_WIN32) */
|
55
ext/misc/sqlite3_stdio.h
Normal file
55
ext/misc/sqlite3_stdio.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
** 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 <stdio.h>
|
||||
#include <windows.h>
|
||||
|
||||
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, ...);
|
||||
void sqlite3_fsetmode(FILE *stream, int mode);
|
||||
|
||||
|
||||
#else
|
||||
/**** Definitions For All Other Platforms ****/
|
||||
#include <stdio.h>
|
||||
#define sqlite3_fopen fopen
|
||||
#define sqlite3_popen popen
|
||||
#define sqlite3_fgets fgets
|
||||
#define sqlite3_fputs fputs
|
||||
#define sqlite3_fprintf fprintf
|
||||
#define sqlite3_fsetmode(F,X) /*no-op*/
|
||||
|
||||
#endif
|
||||
#endif /* _SQLITE3_STDIO_H_ */
|
@ -416,7 +416,7 @@ static const char *lockName(int eLock){
|
||||
const char *azLockNames[] = {
|
||||
"NONE", "SHARED", "RESERVED", "PENDING", "EXCLUSIVE"
|
||||
};
|
||||
if( eLock<0 || eLock>=sizeof(azLockNames)/sizeof(azLockNames[0]) ){
|
||||
if( eLock<0 || eLock>=(int)(sizeof(azLockNames)/sizeof(azLockNames[0])) ){
|
||||
return "???";
|
||||
}else{
|
||||
return azLockNames[eLock];
|
||||
|
@ -35,6 +35,14 @@ SQLITE_EXTENSION_INIT1
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
/* When used as part of the CLI, the sqlite3_stdio.h module will have
|
||||
** been included before this one. In that case use the sqlite3_stdio.h
|
||||
** #defines. If not, create our own for fopen().
|
||||
*/
|
||||
#ifndef _SQLITE3_STDIO_H_
|
||||
# define sqlite3_fopen fopen
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
@ -1291,7 +1299,7 @@ static int zipfileFilter(
|
||||
}
|
||||
|
||||
if( 0==pTab->pWriteFd && 0==bInMemory ){
|
||||
pCsr->pFile = zFile ? fopen(zFile, "rb") : 0;
|
||||
pCsr->pFile = zFile ? sqlite3_fopen(zFile, "rb") : 0;
|
||||
if( pCsr->pFile==0 ){
|
||||
zipfileCursorErr(pCsr, "cannot open file: %s", zFile);
|
||||
rc = SQLITE_ERROR;
|
||||
@ -1481,7 +1489,7 @@ static int zipfileBegin(sqlite3_vtab *pVtab){
|
||||
** structure into memory. During the transaction any new file data is
|
||||
** appended to the archive file, but the central directory is accumulated
|
||||
** in main-memory until the transaction is committed. */
|
||||
pTab->pWriteFd = fopen(pTab->zFile, "ab+");
|
||||
pTab->pWriteFd = sqlite3_fopen(pTab->zFile, "ab+");
|
||||
if( pTab->pWriteFd==0 ){
|
||||
pTab->base.zErrMsg = sqlite3_mprintf(
|
||||
"zipfile: failed to open file %s for writing", pTab->zFile
|
||||
|
@ -202,6 +202,7 @@ foreach {tn sql1 at sql2} {
|
||||
|
||||
sqlite3changegroup grp
|
||||
grp schema db main
|
||||
breakpoint
|
||||
grp add $C1
|
||||
grp add $C2
|
||||
set T1 [grp output]
|
||||
|
@ -56,4 +56,28 @@ do_faultsim_test 1 -faults oom* -prep {
|
||||
faultsim_test_result {0 {}} {1 SQLITE_NOMEM}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
INSERT INTO t1 VALUES(1, 'one');
|
||||
INSERT INTO t1 VALUES(2, 'two');
|
||||
ALTER TABLE t1 ADD COLUMN c DEFAULT 'abcdefghijklmnopqrstuvwxyz';
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 2 -faults oom-t* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
db eval {SELECT * FROM sqlite_schema}
|
||||
} -body {
|
||||
sqlite3session S db main
|
||||
S attach *
|
||||
execsql {
|
||||
DELETE FROM t1 WHERE a = 1;
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}} {1 SQLITE_NOMEM}
|
||||
catch { S delete }
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
@ -82,6 +82,7 @@ do_execsql_test 1.5 {
|
||||
UPDATE p1 SET c=12345 WHERE a = 45;
|
||||
}
|
||||
|
||||
breakpoint
|
||||
sqlite3changeset_apply_v2 -noaction db $C conflict
|
||||
do_execsql_test 1.6 {
|
||||
SELECT * FROM c1
|
||||
|
@ -74,6 +74,10 @@ struct SessionBuffer {
|
||||
** input data. Input data may be supplied either as a single large buffer
|
||||
** (e.g. sqlite3changeset_start()) or using a stream function (e.g.
|
||||
** sqlite3changeset_start_strm()).
|
||||
**
|
||||
** bNoDiscard:
|
||||
** If true, then the only time data is discarded is as a result of explicit
|
||||
** sessionDiscardData() calls. Not within every sessionInputBuffer() call.
|
||||
*/
|
||||
struct SessionInput {
|
||||
int bNoDiscard; /* If true, do not discard in InputBuffer() */
|
||||
@ -1757,16 +1761,19 @@ static void sessionPreupdateOneChange(
|
||||
for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
|
||||
sqlite3_value *p = 0;
|
||||
if( op!=SQLITE_INSERT ){
|
||||
TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p);
|
||||
assert( trc==SQLITE_OK );
|
||||
/* This may fail if the column has a non-NULL default and was added
|
||||
** using ALTER TABLE ADD COLUMN after this record was created. */
|
||||
rc = pSession->hook.xOld(pSession->hook.pCtx, i, &p);
|
||||
}else if( pTab->abPK[i] ){
|
||||
TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p);
|
||||
assert( trc==SQLITE_OK );
|
||||
}
|
||||
|
||||
/* This may fail if SQLite value p contains a utf-16 string that must
|
||||
** be converted to utf-8 and an OOM error occurs while doing so. */
|
||||
rc = sessionSerializeValue(0, p, &nByte);
|
||||
if( rc==SQLITE_OK ){
|
||||
/* This may fail if SQLite value p contains a utf-16 string that must
|
||||
** be converted to utf-8 and an OOM error occurs while doing so. */
|
||||
rc = sessionSerializeValue(0, p, &nByte);
|
||||
}
|
||||
if( rc!=SQLITE_OK ) goto error_out;
|
||||
}
|
||||
if( pTab->bRowid ){
|
||||
@ -5124,15 +5131,21 @@ static int sessionChangesetApply(
|
||||
int nTab = 0; /* Result of sqlite3Strlen30(zTab) */
|
||||
SessionApplyCtx sApply; /* changeset_apply() context object */
|
||||
int bPatchset;
|
||||
u64 savedFlag = db->flags & SQLITE_FkNoAction;
|
||||
|
||||
assert( xConflict!=0 );
|
||||
|
||||
sqlite3_mutex_enter(sqlite3_db_mutex(db));
|
||||
if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){
|
||||
db->flags |= ((u64)SQLITE_FkNoAction);
|
||||
db->aDb[0].pSchema->schema_cookie -= 32;
|
||||
}
|
||||
|
||||
pIter->in.bNoDiscard = 1;
|
||||
memset(&sApply, 0, sizeof(sApply));
|
||||
sApply.bRebase = (ppRebase && pnRebase);
|
||||
sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
|
||||
sApply.bIgnoreNoop = !!(flags & SQLITE_CHANGESETAPPLY_IGNORENOOP);
|
||||
sqlite3_mutex_enter(sqlite3_db_mutex(db));
|
||||
if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
|
||||
rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
|
||||
}
|
||||
@ -5294,6 +5307,12 @@ static int sessionChangesetApply(
|
||||
sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */
|
||||
sqlite3_free((char*)sApply.constraints.aBuf);
|
||||
sqlite3_free((char*)sApply.rebase.aBuf);
|
||||
|
||||
if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){
|
||||
assert( db->flags & SQLITE_FkNoAction );
|
||||
db->flags &= ~((u64)SQLITE_FkNoAction);
|
||||
db->aDb[0].pSchema->schema_cookie -= 32;
|
||||
}
|
||||
sqlite3_mutex_leave(sqlite3_db_mutex(db));
|
||||
return rc;
|
||||
}
|
||||
@ -5322,12 +5341,6 @@ int sqlite3changeset_apply_v2(
|
||||
sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
|
||||
int bInv = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
|
||||
int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset, bInv, 1);
|
||||
u64 savedFlag = db->flags & SQLITE_FkNoAction;
|
||||
|
||||
if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){
|
||||
db->flags |= ((u64)SQLITE_FkNoAction);
|
||||
db->aDb[0].pSchema->schema_cookie -= 32;
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sessionChangesetApply(
|
||||
@ -5335,11 +5348,6 @@ int sqlite3changeset_apply_v2(
|
||||
);
|
||||
}
|
||||
|
||||
if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){
|
||||
assert( db->flags & SQLITE_FkNoAction );
|
||||
db->flags &= ~((u64)SQLITE_FkNoAction);
|
||||
db->aDb[0].pSchema->schema_cookie -= 32;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -5660,6 +5668,9 @@ static int sessionChangesetExtendRecord(
|
||||
sessionAppendBlob(pOut, aRec, nRec, &rc);
|
||||
if( rc==SQLITE_OK && pTab->pDfltStmt==0 ){
|
||||
rc = sessionPrepareDfltStmt(pGrp->db, pTab, &pTab->pDfltStmt);
|
||||
if( rc==SQLITE_OK && SQLITE_ROW!=sqlite3_step(pTab->pDfltStmt) ){
|
||||
rc = sqlite3_errcode(pGrp->db);
|
||||
}
|
||||
}
|
||||
for(ii=nCol; rc==SQLITE_OK && ii<pTab->nCol; ii++){
|
||||
int eType = sqlite3_column_type(pTab->pDfltStmt, ii);
|
||||
@ -5676,6 +5687,7 @@ static int sessionChangesetExtendRecord(
|
||||
}
|
||||
if( SQLITE_OK==sessionBufferGrow(pOut, 8, &rc) ){
|
||||
sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal);
|
||||
pOut->nBuf += 8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -5815,6 +5827,8 @@ static int sessionOneChangeToHash(
|
||||
u8 *aRec = &pIter->in.aData[pIter->in.iCurrent + 2];
|
||||
int nRec = (pIter->in.iNext - pIter->in.iCurrent) - 2;
|
||||
|
||||
assert( nRec>0 );
|
||||
|
||||
/* Ensure that only changesets, or only patchsets, but not a mixture
|
||||
** of both, are being combined. It is an error to try to combine a
|
||||
** changeset and a patchset. */
|
||||
@ -5892,6 +5906,7 @@ static int sessionChangesetToHash(
|
||||
int nRec;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
pIter->in.bNoDiscard = 1;
|
||||
while( SQLITE_ROW==(sessionChangesetNext(pIter, &aRec, &nRec, 0)) ){
|
||||
rc = sessionOneChangeToHash(pGrp, pIter, bRebase);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
|
Reference in New Issue
Block a user