Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 02f441e408 | |||
| 8c0b44a552 | |||
| a6db3f058a | |||
| 985be1bce6 | |||
| 99f24349ea | |||
| 890b69fb83 | |||
| f5d6f1e0c5 | |||
| 5ec0cfe070 | |||
| 3b3b1a538d | |||
| b0fa210aa3 | |||
| 801829c812 | |||
| 9b3c15e860 | |||
| 61d3bfb78b | |||
| 45d55a254b | |||
| 51e5db70b6 | |||
| f219bba933 | |||
| a0166e1873 | |||
| aff0449d8f | |||
| c55e9b815f | |||
| 03ba419b3c | |||
| c4098a3d9f | |||
| 21ce77989a | |||
| 91973abb4b | |||
| 722db051c6 | |||
| 87dd60cd8d | |||
| 7244fdc446 | |||
| 4f7e8fcded | |||
| 95063a5774 | |||
| ad7c2a87f5 | |||
| cc3ec7cb2b | |||
| 3942b4b147 | |||
| 9aa0012a08 | |||
| efd8e3b33d | |||
| 0b90b2209f | |||
| 9782039bde | |||
| 332aa832ce | |||
| bf4cad1e4c | |||
| b0c5edcd06 | |||
| 2250799f0c | |||
| ca071dfd75 | |||
| ac0c39980a | |||
| 04d4227255 | |||
| e6c3c72c1b |
+14
@@ -325,6 +325,9 @@ SRC += \
|
||||
SRC += \
|
||||
$(TOP)/ext/rtree/rtree.h \
|
||||
$(TOP)/ext/rtree/rtree.c
|
||||
SRC += \
|
||||
$(TOP)/ext/sqlrr/sqlrr.h \
|
||||
$(TOP)/ext/sqlrr/sqlrr.c
|
||||
|
||||
|
||||
# Generated source code files
|
||||
@@ -460,6 +463,17 @@ EXTHDR += \
|
||||
$(TOP)/ext/rtree/rtree.h
|
||||
EXTHDR += \
|
||||
$(TOP)/ext/icu/sqliteicu.h
|
||||
EXTHDR += \
|
||||
$(TOP)/ext/sqlrr/sqlrr.h
|
||||
|
||||
# If using the amalgamation, use sqlite3.c directly to build the test
|
||||
# fixture. Otherwise link against libsqlite3.la. (This distinction is
|
||||
# necessary because the test fixture requires non-API symbols which are
|
||||
# hidden when the library is built via the amalgamation).
|
||||
#
|
||||
TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la
|
||||
TESTFIXTURE_SRC1 = sqlite3.c
|
||||
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)/src/tclsqlite.c $(TESTFIXTURE_SRC$(USE_AMALGAMATION))
|
||||
|
||||
# This is the default Makefile target. The objects listed here
|
||||
# are what get build when you type just "make" with no arguments.
|
||||
|
||||
+2
-1
@@ -63,6 +63,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
typedef sqlite3_int64 i64;
|
||||
@@ -2709,7 +2710,7 @@ static int rtreeInit(
|
||||
Rtree *pRtree;
|
||||
int nDb; /* Length of string argv[1] */
|
||||
int nName; /* Length of string argv[2] */
|
||||
int eCoordType = (int)pAux;
|
||||
int eCoordType = (int)(intptr_t)pAux;
|
||||
|
||||
const char *aErrMsg[] = {
|
||||
0, /* 0 */
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
|
||||
sqlrr - 10/19/2009
|
||||
|
||||
SQL Replay Recording
|
||||
|
||||
SUMMARY
|
||||
-------------------------------------------------------
|
||||
This extension enables recording sqlite API calls that access the database so that they can be replayed or examined.
|
||||
|
||||
USAGE
|
||||
------------------------------------------------------
|
||||
Recording is enabled by compiling sqlite with symbolic constant SQLITE_ENABLE_SQLRR defined.
|
||||
By default logs are written to /tmp/<databasename>_<pid>_<connection_number>.sqlrr, to choose another directory, set the environment variable SQLITE_REPLAY_RECORD_DIR to that path.
|
||||
|
||||
FILE FORMAT
|
||||
-----------------------------------------------------
|
||||
file: <header>[<sql-command>]*
|
||||
|
||||
header: <signature><format-version>
|
||||
signature: SQLRR (5 bytes)
|
||||
format-version: n (1 byte)
|
||||
|
||||
sql-command: <timestamp><type><arg-data>
|
||||
timestamp: n (16 bytes)
|
||||
type: n (1 byte)
|
||||
open 0
|
||||
close 1
|
||||
exec 8
|
||||
bind-text 16
|
||||
bind-double 17
|
||||
bind-int 18
|
||||
bind-null 19
|
||||
bind-value 20
|
||||
bind-clear 21
|
||||
prep 32
|
||||
step 33
|
||||
reset 34
|
||||
finalize 35
|
||||
|
||||
open-arg-data: <connection><path><flags>
|
||||
close-arg-data: <connection>
|
||||
exec-arg-data: <connection><len><statement-text>
|
||||
bind-text-arg-data: <statement-ref><index><len><data>
|
||||
bind-double-arg-data: <statement-ref><index><data>
|
||||
bind-int-arg-data: <statement-ref><index><data>
|
||||
bind-null-arg-data: <statement-ref><index>
|
||||
bind-value-arg-data: <statement-ref><index><len><data> ???
|
||||
bind-clear-arg-data: <statement-ref>
|
||||
prep-arg-data: <connection><len><statement-text>
|
||||
step-arg-data: <statement-ref>
|
||||
reset-arg-data: <statement-ref>
|
||||
finalize-arg-data: <statement-ref>
|
||||
|
||||
NOTES
|
||||
@@ -0,0 +1,581 @@
|
||||
/*
|
||||
* sqlrr.c
|
||||
*/
|
||||
|
||||
#include "sqlrr.h"
|
||||
|
||||
#if defined(SQLITE_ENABLE_SQLRR)
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/param.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
|
||||
#define LOGSUFFIXLEN 48
|
||||
|
||||
/*
|
||||
* Data types
|
||||
*/
|
||||
typedef struct SRRLogRef SRRLogRef;
|
||||
struct SRRLogRef {
|
||||
int fd;
|
||||
sqlite3 *db;
|
||||
const char *dbPath;
|
||||
char *logPath;
|
||||
int connection;
|
||||
int depth;
|
||||
SRRLogRef *nextRef;
|
||||
};
|
||||
|
||||
/*
|
||||
* Globals
|
||||
*/
|
||||
SRRLogRef *logRefHead = NULL;
|
||||
int dbLogCount = 0;
|
||||
static int srr_enabled = 1;
|
||||
pthread_mutex_t srr_log_mutex;
|
||||
static volatile int32_t srr_initialized = 0;
|
||||
|
||||
/*
|
||||
* Log management
|
||||
*/
|
||||
extern void SRRecInitialize() {
|
||||
int go = OSAtomicCompareAndSwap32Barrier(0, 1, &srr_initialized);
|
||||
if( go ){
|
||||
pthread_mutex_init(&srr_log_mutex, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static SRRLogRef *createLog(sqlite3 *db, const char *dbPath) {
|
||||
SRRLogRef *ref = NULL;
|
||||
char *baseDir = getenv("SQLITE_REPLAY_RECORD_DIR");
|
||||
char logPath[MAXPATHLEN] = "";
|
||||
char suffix[LOGSUFFIXLEN] = "";
|
||||
const char *dbName = dbPath;
|
||||
int len = 0;
|
||||
int index = 0;
|
||||
int fd = -1;
|
||||
size_t out;
|
||||
unsigned char version = SRR_FILE_VERSION;
|
||||
|
||||
SRRecInitialize();
|
||||
|
||||
/* construct the path for the log file
|
||||
* ${SQLITE_REPLAY_DIR}/<dbname>_<pid>_<connection_number>.sqlrr
|
||||
*/
|
||||
if (baseDir == NULL) {
|
||||
baseDir = "/tmp"; /* getenv(TMPDIR) */
|
||||
}
|
||||
len = strlen(baseDir);
|
||||
strlcat(logPath, baseDir, MAXPATHLEN);
|
||||
if ((len>0) && (baseDir[len-1] != '/')) {
|
||||
strlcat(logPath, "/", MAXPATHLEN);
|
||||
}
|
||||
len = strlen(dbPath);
|
||||
for (index = len-2; index >= 0; index --){
|
||||
if (dbPath[index] == '/') {
|
||||
dbName = &dbPath[index+1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
strlcat(logPath, dbName, MAXPATHLEN);
|
||||
int cNum = ++dbLogCount;
|
||||
snprintf(suffix, sizeof(suffix), "_%d_%d_XXXX.sqlrr", getpid(), cNum);
|
||||
len = strlcat(logPath, suffix, MAXPATHLEN);
|
||||
/* make it unique if we have the space */
|
||||
if ((len + 1) < MAXPATHLEN) {
|
||||
fd = mkstemps(logPath, 6);
|
||||
} else {
|
||||
fprintf(stderr, "Failed to create sqlite replay log path for %s [%s]\n", dbPath, logPath);
|
||||
return NULL;
|
||||
}
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "Failed to create sqlite replay log file for %s with path %s [%s]\n", dbPath, logPath, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
fprintf(stdout, "Writing sqlite replay log file %s\n", logPath);
|
||||
out = write(fd, SRR_FILE_SIGNATURE, SRR_FILE_SIGNATURE_LEN);
|
||||
if (out!=-1) {
|
||||
out = write(fd, &version, 1);
|
||||
}
|
||||
if (out == -1){
|
||||
fprintf(stderr, "Write failure on log [%s]: %s\n", logPath, strerror(errno));
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = strlen(logPath) + 1;
|
||||
ref = (SRRLogRef *)malloc(sizeof(SRRLogRef));
|
||||
|
||||
ref->db = db;
|
||||
ref->dbPath = dbPath;
|
||||
ref->logPath = (char *)malloc(len * sizeof(char));
|
||||
strlcpy(ref->logPath, logPath, len);
|
||||
ref->fd = fd;
|
||||
ref->connection = cNum;
|
||||
ref->depth = 0;
|
||||
|
||||
pthread_mutex_lock(&srr_log_mutex);
|
||||
ref->nextRef = logRefHead;
|
||||
logRefHead = ref;
|
||||
pthread_mutex_unlock(&srr_log_mutex);
|
||||
return ref;
|
||||
}
|
||||
|
||||
static void closeLog(sqlite3 *db) {
|
||||
SRRLogRef *ref = NULL;
|
||||
SRRLogRef *lastRef = NULL;
|
||||
|
||||
pthread_mutex_lock(&srr_log_mutex);
|
||||
for (ref = logRefHead; ref != NULL; ref = ref->nextRef) {
|
||||
if (ref->db == db) {
|
||||
if (lastRef == NULL) {
|
||||
logRefHead = ref->nextRef;
|
||||
} else {
|
||||
lastRef->nextRef = ref->nextRef;
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&srr_log_mutex);
|
||||
|
||||
if (ref != NULL) {
|
||||
fprintf(stdout, "Closing sqlite replay log file %s\n", ref->logPath);
|
||||
close(ref->fd);
|
||||
free(ref->logPath);
|
||||
free(ref);
|
||||
}
|
||||
}
|
||||
|
||||
static SRRLogRef *getLog(sqlite3 *db) {
|
||||
pthread_mutex_lock(&srr_log_mutex);
|
||||
SRRLogRef *ref = logRefHead;
|
||||
for (ref = logRefHead; ref != NULL; ref = ref->nextRef) {
|
||||
if (ref->db == db) {
|
||||
pthread_mutex_unlock(&srr_log_mutex);
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&srr_log_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SQLite recording API
|
||||
*/
|
||||
void SQLiteReplayRecorder(int flag) {
|
||||
srr_enabled = flag;
|
||||
}
|
||||
|
||||
// open-arg-data: <connection><len><path><flags>
|
||||
void _SRRecOpen(sqlite3 *db, const char *path, int flags) {
|
||||
if (!srr_enabled) return;
|
||||
if (db) {
|
||||
SRRLogRef *ref = createLog(db, path);
|
||||
if (ref) {
|
||||
SRRCommand code = SRROpen;
|
||||
int len = strlen(path);
|
||||
struct timeval tv;
|
||||
size_t out;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
out = write(ref->fd, &tv, sizeof(tv));
|
||||
if (out!=-1) { out=write(ref->fd, &code, sizeof(SRRCommand)); }
|
||||
if (out!=-1) { out=write(ref->fd, &(ref->connection), sizeof(ref->connection)); }
|
||||
if (out!=-1) { out=write(ref->fd, &len, sizeof(len)); }
|
||||
if (out!=-1) { out=write(ref->fd, path, len); }
|
||||
if (out!=-1) { out=write(ref->fd, &flags, sizeof(flags)); }
|
||||
if (out==-1) {
|
||||
fprintf(stderr, "Error writing open to log file [%s]: %s\n", ref->logPath, strerror(errno));
|
||||
closeLog(db);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//close-arg-data: <connection>
|
||||
void SRRecClose(sqlite3 *db) {
|
||||
if (!srr_enabled) return;
|
||||
if (db) {
|
||||
SRRLogRef *ref = getLog(db);
|
||||
if (ref) {
|
||||
SRRCommand code = SRRClose;
|
||||
struct timeval tv;
|
||||
size_t out;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
out = write(ref->fd, &tv, sizeof(tv));
|
||||
if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
|
||||
if (out!=-1) { out = write(ref->fd, &(ref->connection), sizeof(ref->connection)); }
|
||||
if (out==-1) {
|
||||
fprintf(stderr, "Error writing close to log file [%s]: %s\n", ref->logPath, strerror(errno));
|
||||
}
|
||||
closeLog(db);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// exec-arg-data: <connection><len><statement-text>
|
||||
void SRRecExec(sqlite3 *db, const char *sql) {
|
||||
if (!srr_enabled) return;
|
||||
if (db) {
|
||||
SRRLogRef *ref = getLog(db);
|
||||
if (ref) {
|
||||
if (ref->depth == 0) {
|
||||
SRRCommand code = SRRExec;
|
||||
int len = strlen(sql);
|
||||
struct timeval tv;
|
||||
size_t out;
|
||||
|
||||
ref->depth = 1;
|
||||
gettimeofday(&tv, NULL);
|
||||
out = write(ref->fd, &tv, sizeof(tv));
|
||||
if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
|
||||
if (out!=-1) { out = write(ref->fd, &(ref->connection), sizeof(ref->connection)); }
|
||||
if (out!=-1) { out = write(ref->fd, &len, sizeof(len)); }
|
||||
if (out!=-1) { out = write(ref->fd, sql, len); }
|
||||
if (out==-1) {
|
||||
fprintf(stderr, "Error writing exec to log file [%s]: %s\n", ref->logPath, strerror(errno));
|
||||
closeLog(db);
|
||||
}
|
||||
} else {
|
||||
ref->depth ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SRRecExecEnd(sqlite3 *db) {
|
||||
if (!srr_enabled) return;
|
||||
if (db) {
|
||||
SRRLogRef *ref = getLog(db);
|
||||
if (ref) {
|
||||
ref->depth --;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// prep-arg-data: <connection><len><statement-text><savesql><statement-ref>
|
||||
void _SRRecPrepare(sqlite3 *db, const char *sql, int nBytes, int saveSql, sqlite3_stmt *pStmt) {
|
||||
if (!srr_enabled) return;
|
||||
if ((db!=NULL)&&(pStmt!=NULL)) {
|
||||
SRRLogRef *ref = getLog(db);
|
||||
if (ref && (ref->depth == 0)) {
|
||||
SRRCommand code = SRRPrepare;
|
||||
struct timeval tv;
|
||||
size_t out;
|
||||
int sqlLen = nBytes;
|
||||
|
||||
if (sqlLen == -1) {
|
||||
sqlLen = strlen(sql);
|
||||
}
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
out = write(ref->fd, &tv, sizeof(tv));
|
||||
if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
|
||||
if (out!=-1) { out = write(ref->fd, &(ref->connection), sizeof(ref->connection)); }
|
||||
if (out!=-1) { out = write(ref->fd, &sqlLen, sizeof(sqlLen)); }
|
||||
if (out!=-1) { out = write(ref->fd, sql, sqlLen); }
|
||||
if (out!=-1) { out = write(ref->fd, &saveSql, sizeof(saveSql)); }
|
||||
if (out!=-1) {
|
||||
int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
|
||||
out = write(ref->fd, &stmtInt, sizeof(int64_t));
|
||||
}
|
||||
if (out==-1) {
|
||||
fprintf(stderr, "Error writing prepare to log file [%s]: %s\n", ref->logPath, strerror(errno));
|
||||
closeLog(db);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//step-arg-data: <statement-ref>
|
||||
void SRRecStep(sqlite3_stmt *pStmt) {
|
||||
if (!srr_enabled) return;
|
||||
if(pStmt!=NULL) {
|
||||
Vdbe *v = (Vdbe *)pStmt;
|
||||
SRRLogRef *ref = getLog(v->db);
|
||||
if (ref) {
|
||||
if (ref->depth == 0) {
|
||||
SRRCommand code = SRRStep;
|
||||
struct timeval tv;
|
||||
size_t out;
|
||||
|
||||
ref->depth = 1;
|
||||
gettimeofday(&tv, NULL);
|
||||
out = write(ref->fd, &tv, sizeof(tv));
|
||||
if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
|
||||
if (out!=-1) {
|
||||
int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
|
||||
out = write(ref->fd, &stmtInt, sizeof(int64_t));
|
||||
}
|
||||
if (out==-1) {
|
||||
fprintf(stderr, "Error writing step to log file [%s]: %s\n", ref->logPath, strerror(errno));
|
||||
closeLog(ref->db);
|
||||
}
|
||||
} else {
|
||||
ref->depth ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SRRecStepEnd(sqlite3_stmt *pStmt) {
|
||||
if (!srr_enabled) return;
|
||||
if(pStmt!=NULL) {
|
||||
Vdbe *v = (Vdbe *)pStmt;
|
||||
SRRLogRef *ref = getLog(v->db);
|
||||
if (ref) {
|
||||
ref->depth --;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// reset-arg-data: <statement-ref>
|
||||
void SRRecReset(sqlite3_stmt *pStmt) {
|
||||
if (!srr_enabled) return;
|
||||
if(pStmt!=NULL) {
|
||||
Vdbe *v = (Vdbe *)pStmt;
|
||||
SRRLogRef *ref = getLog(v->db);
|
||||
if (ref && (ref->depth == 0)) {
|
||||
SRRCommand code = SRRReset;
|
||||
struct timeval tv;
|
||||
size_t out;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
out = write(ref->fd, &tv, sizeof(tv));
|
||||
if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
|
||||
if (out!=-1) {
|
||||
int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
|
||||
out = write(ref->fd, &stmtInt, sizeof(int64_t));
|
||||
}
|
||||
if (out==-1) {
|
||||
fprintf(stderr, "Error writing reset to log file [%s]: %s\n", ref->logPath, strerror(errno));
|
||||
closeLog(ref->db);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finalize-arg-data: <statement-ref>
|
||||
void SRRecFinalize(sqlite3_stmt *pStmt) {
|
||||
if (!srr_enabled) return;
|
||||
if(pStmt!=NULL) {
|
||||
Vdbe *v = (Vdbe *)pStmt;
|
||||
SRRLogRef *ref = getLog(v->db);
|
||||
if (ref && (ref->depth == 0)) {
|
||||
SRRCommand code = SRRFinalize;
|
||||
struct timeval tv;
|
||||
size_t out;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
out = write(ref->fd, &tv, sizeof(tv));
|
||||
if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
|
||||
if (out!=-1) {
|
||||
int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
|
||||
out = write(ref->fd, &stmtInt, sizeof(int64_t));
|
||||
}
|
||||
if (out==-1) {
|
||||
fprintf(stderr, "Error writing finalize to log file [%s]: %s\n", ref->logPath, strerror(errno));
|
||||
closeLog(ref->db);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bind-text-arg-data: <statement-ref><index><len><data>
|
||||
void SRRecBindText(sqlite3_stmt *pStmt, int i, const char *zData, int64_t nData) {
|
||||
if (!srr_enabled) return;
|
||||
if(pStmt!=NULL) {
|
||||
Vdbe *v = (Vdbe *)pStmt;
|
||||
SRRLogRef *ref = getLog(v->db);
|
||||
if (ref && (ref->depth == 0)) {
|
||||
SRRCommand code = SRRBindText;
|
||||
struct timeval tv;
|
||||
size_t out;
|
||||
int64_t textLen = nData;
|
||||
if (textLen == -1) {
|
||||
textLen = strlen(zData);
|
||||
}
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
out = write(ref->fd, &tv, sizeof(tv));
|
||||
if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
|
||||
if (out!=-1) {
|
||||
int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
|
||||
out = write(ref->fd, &stmtInt, sizeof(int64_t));
|
||||
}
|
||||
if (out!=-1) { out = write(ref->fd, &i, sizeof(i)); }
|
||||
if (out!=-1) { out = write(ref->fd, &textLen, sizeof(textLen)); }
|
||||
if (out!=-1) { out = write(ref->fd, zData, textLen); }
|
||||
if (out==-1) {
|
||||
fprintf(stderr, "Error writing bind text to log file [%s]: %s\n", ref->logPath, strerror(errno));
|
||||
closeLog(ref->db);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bind-blob-arg-data: <statement-ref><index><len>[<data>]
|
||||
void SRRecBindBlob(sqlite3_stmt *pStmt, int i, const char *zData, int64_t nData) {
|
||||
if (!srr_enabled) return;
|
||||
if(pStmt!=NULL) {
|
||||
Vdbe *v = (Vdbe *)pStmt;
|
||||
SRRLogRef *ref = getLog(v->db);
|
||||
if (ref && (ref->depth == 0)) {
|
||||
SRRCommand code = SRRBindBlob;
|
||||
struct timeval tv;
|
||||
size_t out;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
out = write(ref->fd, &tv, sizeof(tv));
|
||||
if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
|
||||
if (out!=-1) {
|
||||
int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
|
||||
out = write(ref->fd, &stmtInt, sizeof(int64_t));
|
||||
}
|
||||
if (out!=-1) { out = write(ref->fd, &i, sizeof(i)); }
|
||||
if (zData == NULL) {
|
||||
int64_t negNData = -nData;
|
||||
if (out!=-1) { out = write(ref->fd, &negNData, sizeof(negNData)); }
|
||||
} else {
|
||||
if (out!=-1) { out = write(ref->fd, &nData, sizeof(nData)); }
|
||||
if (out!=-1) { out = write(ref->fd, zData, nData); }
|
||||
}
|
||||
if (out==-1) {
|
||||
fprintf(stderr, "Error writing bind blob to log file [%s]: %s\n", ref->logPath, strerror(errno));
|
||||
closeLog(ref->db);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bind-double-arg-data: <statement-ref><index><data>
|
||||
void SRRecBindDouble(sqlite3_stmt *pStmt, int i, double value) {
|
||||
if (!srr_enabled) return;
|
||||
if(pStmt!=NULL) {
|
||||
Vdbe *v = (Vdbe *)pStmt;
|
||||
SRRLogRef *ref = getLog(v->db);
|
||||
if (ref && (ref->depth == 0)) {
|
||||
SRRCommand code = SRRBindDouble;
|
||||
struct timeval tv;
|
||||
size_t out;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
out = write(ref->fd, &tv, sizeof(tv));
|
||||
if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
|
||||
if (out!=-1) {
|
||||
int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
|
||||
out = write(ref->fd, &stmtInt, sizeof(int64_t));
|
||||
}
|
||||
if (out!=-1) { out = write(ref->fd, &i, sizeof(i)); }
|
||||
if (out!=-1) { out = write(ref->fd, &value, sizeof(value)); }
|
||||
if (out==-1) {
|
||||
fprintf(stderr, "Error writing bind double to log file [%s]: %s\n", ref->logPath, strerror(errno));
|
||||
closeLog(ref->db);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bind-int-arg-data: <statement-ref><index><data>
|
||||
void SRRecBindInt64(sqlite3_stmt *pStmt, int i, int64_t value) {
|
||||
if (!srr_enabled) return;
|
||||
if(pStmt!=NULL) {
|
||||
Vdbe *v = (Vdbe *)pStmt;
|
||||
SRRLogRef *ref = getLog(v->db);
|
||||
if (ref && (ref->depth == 0)) {
|
||||
SRRCommand code = SRRBindInt;
|
||||
struct timeval tv;
|
||||
size_t out;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
out = write(ref->fd, &tv, sizeof(tv));
|
||||
if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
|
||||
if (out!=-1) {
|
||||
int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
|
||||
out = write(ref->fd, &stmtInt, sizeof(int64_t));
|
||||
}
|
||||
if (out!=-1) { out = write(ref->fd, &i, sizeof(i)); }
|
||||
if (out!=-1) { out = write(ref->fd, &value, sizeof(value)); }
|
||||
if (out==-1) {
|
||||
fprintf(stderr, "Error writing bind int to log file [%s]: %s\n", ref->logPath, strerror(errno));
|
||||
closeLog(ref->db);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bind-null-arg-data: <statement-ref><index>
|
||||
void SRRecBindNull(sqlite3_stmt *pStmt, int i) {
|
||||
if (!srr_enabled) return;
|
||||
if(pStmt!=NULL) {
|
||||
Vdbe *v = (Vdbe *)pStmt;
|
||||
SRRLogRef *ref = getLog(v->db);
|
||||
if (ref && (ref->depth == 0)) {
|
||||
SRRCommand code = SRRBindNull;
|
||||
struct timeval tv;
|
||||
size_t out;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
out = write(ref->fd, &tv, sizeof(tv));
|
||||
if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
|
||||
if (out!=-1) {
|
||||
int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
|
||||
out = write(ref->fd, &stmtInt, sizeof(int64_t));
|
||||
}
|
||||
if (out!=-1) { out = write(ref->fd, &i, sizeof(i)); }
|
||||
if (out==-1) {
|
||||
fprintf(stderr, "Error writing bind null to log file [%s]: %s\n", ref->logPath, strerror(errno));
|
||||
closeLog(ref->db);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bind-value-arg-data: <statement-ref><index><len><data> ???
|
||||
void SRRecBindValue(sqlite3_stmt *pStmt, int i, const sqlite3_value *value) {
|
||||
if (!srr_enabled) return;
|
||||
if(pStmt!=NULL) {
|
||||
Vdbe *v = (Vdbe *)pStmt;
|
||||
SRRLogRef *ref = getLog(v->db);
|
||||
if (ref && (ref->depth == 0)) {
|
||||
fprintf(stderr, "SRRecBindValue(sqlite3_bind_value) is not yet supported, closing [%s]: %s\n", ref->logPath, strerror(errno));
|
||||
closeLog(ref->db);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bind-clear-arg-data: <statement-ref>
|
||||
void SRRecClearBindings(sqlite3_stmt *pStmt) {
|
||||
if (!srr_enabled) return;
|
||||
if(pStmt!=NULL) {
|
||||
Vdbe *v = (Vdbe *)pStmt;
|
||||
SRRLogRef *ref = getLog(v->db);
|
||||
if (ref && (ref->depth == 0)) {
|
||||
SRRCommand code = SRRBindClear;
|
||||
struct timeval tv;
|
||||
size_t out;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
out = write(ref->fd, &tv, sizeof(tv));
|
||||
if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
|
||||
if (out!=-1) {
|
||||
int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
|
||||
out = write(ref->fd, &stmtInt, sizeof(int64_t));
|
||||
}
|
||||
if (out==-1) {
|
||||
fprintf(stderr, "Error writing clear bindings to log file [%s]: %s\n", ref->logPath, strerror(errno));
|
||||
closeLog(ref->db);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SQLITE_ENABLE_SQLRR */
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* sqlrr.h
|
||||
*/
|
||||
|
||||
#ifndef _SQLRR_H_
|
||||
#define _SQLRR_H_
|
||||
|
||||
/*
|
||||
** Header constants
|
||||
*/
|
||||
#define SRR_FILE_SIGNATURE "SQLRR"
|
||||
#define SRR_FILE_SIGNATURE_LEN 5
|
||||
#define SRR_FILE_VERSION 0x1
|
||||
#define SRR_FILE_VERSION_LEN 1
|
||||
|
||||
#if defined(SQLITE_ENABLE_SQLRR)
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include <sys/types.h>
|
||||
|
||||
#define SRRecOpen(A,B,C) if(!rc){_SRRecOpen(A,B,C);}
|
||||
#define SRRecPrepare(A,B,C,D,E) if(!rc){_SRRecPrepare(A,B,C,D,E);}
|
||||
|
||||
typedef enum {
|
||||
SRROpen = 0,
|
||||
SRRClose = 1,
|
||||
SRRExec = 8,
|
||||
SRRBindText = 16,
|
||||
SRRBindBlob = 17,
|
||||
SRRBindDouble = 18,
|
||||
SRRBindInt = 19,
|
||||
SRRBindNull = 20,
|
||||
SRRBindValue = 21,
|
||||
SRRBindClear = 22,
|
||||
SRRPrepare = 32,
|
||||
SRRStep = 33,
|
||||
SRRReset = 34,
|
||||
SRRFinalize = 35
|
||||
} SRRCommand;
|
||||
|
||||
extern void SQLiteReplayRecorder(int flag);
|
||||
extern void _SRRecOpen(sqlite3 *db, const char *path, int flags);
|
||||
extern void SRRecClose(sqlite3 *db);
|
||||
extern void SRRecExec(sqlite3 *db, const char *sql);
|
||||
extern void SRRecExecEnd(sqlite3 *db);
|
||||
extern void _SRRecPrepare(sqlite3 *db, const char *sql, int nBytes, int saveSql, sqlite3_stmt *stmt);
|
||||
extern void SRRecStep(sqlite3_stmt *pStmt);
|
||||
extern void SRRecStepEnd(sqlite3_stmt *pStmt);
|
||||
extern void SRRecReset(sqlite3_stmt *pStmt);
|
||||
extern void SRRecFinalize(sqlite3_stmt *pStmt);
|
||||
extern void SRRecBindText(sqlite3_stmt *pStmt, int i, const char *zData, int64_t nData);
|
||||
extern void SRRecBindBlob(sqlite3_stmt *pStmt, int i, const char *zData, int64_t nData);
|
||||
extern void SRRecBindDouble(sqlite3_stmt *pStmt, int i, double value);
|
||||
extern void SRRecBindInt64(sqlite3_stmt *pStmt, int i, int64_t value);
|
||||
extern void SRRecBindNull(sqlite3_stmt *pStmt, int i);
|
||||
extern void SRRecBindValue(sqlite3_stmt *pStmt, int i, const sqlite3_value *value);
|
||||
extern void SRRecClearBindings(sqlite3_stmt *pStmt);
|
||||
|
||||
#endif /* defined(SQLITE_ENABLE_SQLRR) */
|
||||
|
||||
#endif /* _SQLRR_H_ */
|
||||
Executable → Regular
@@ -203,6 +203,8 @@ SRC += \
|
||||
SRC += \
|
||||
$(TOP)/ext/rtree/rtree.h \
|
||||
$(TOP)/ext/rtree/rtree.c
|
||||
SRC += \
|
||||
$(TOP)/ext/sqlrr/sqlrr.c
|
||||
|
||||
|
||||
# Generated source code files
|
||||
@@ -335,6 +337,8 @@ EXTHDR += \
|
||||
$(TOP)/ext/rtree/rtree.h
|
||||
EXTHDR += \
|
||||
$(TOP)/ext/icu/sqliteicu.h
|
||||
EXTHDR += \
|
||||
$(TOP)/ext/sqlrr/sqlrr.h
|
||||
|
||||
# This is the default Makefile target. The objects listed here
|
||||
# are what get build when you type just "make" with no arguments.
|
||||
@@ -356,10 +360,10 @@ sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h
|
||||
# files are automatically generated. This target takes care of
|
||||
# all that automatic generation.
|
||||
#
|
||||
target_source: $(SRC) $(TOP)/tool/vdbe-compress.tcl
|
||||
target_source: $(SRC) $(EXTHDR) $(TOP)/tool/vdbe-compress.tcl
|
||||
rm -rf tsrc
|
||||
mkdir tsrc
|
||||
cp -f $(SRC) tsrc
|
||||
cp -f $(SRC) $(EXTHDR) tsrc
|
||||
rm tsrc/sqlite.h.in tsrc/parse.y
|
||||
tclsh $(TOP)/tool/vdbe-compress.tcl <tsrc/vdbe.c >vdbe.new
|
||||
mv vdbe.new tsrc/vdbe.c
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
C The\sR-tree\smodule\sshould\snot\sassume\sthat\sits\sshadow\stables\sare\sconsistent.\nIf\sa\sproblem\sis\sfound\sin\sa\sshadow\stable,\sreturn\sSQLITE_CORRUPT.
|
||||
D 2010-08-24T01:49:48
|
||||
C Add\s"PRAGMA\scheckpoint_fullfsync".\sSimilar\sto\s"PRAGMA\sfullfsync",\sbut\senables\sfull\sfsyncs\sonly\sduring\scheckpoint\soperations.
|
||||
D 2010-11-09T20:08:02
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 543f91f24cd7fee774ecc0a61c19704c0c3e78fd
|
||||
F Makefile.in c58f7d37ad0f9b28655ba4e28c6cb0f879569cd7
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.vxworks c85ec1d8597fe2f7bc225af12ac1666e21379151
|
||||
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
|
||||
@@ -24,7 +21,7 @@ F art/src_logo.gif 9341ef09f0e53cd44c0c9b6fc3c16f7f3d6c2ad9
|
||||
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
|
||||
F config.h.in 868fdb48c028421a203470e15c69ada15b9ba673
|
||||
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
|
||||
F configure a5dab32df872ed3fe248c7f0cbc324595c169781 x
|
||||
F configure a5dab32df872ed3fe248c7f0cbc324595c169781
|
||||
F configure.ac 699040cc9abb7465dca5a2972bc89d227fd8f734
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538
|
||||
@@ -81,7 +78,7 @@ F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
|
||||
F ext/icu/icu.c 850e9a36567bbcce6bd85a4b68243cad8e3c2de2
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c 1a39ad566196d2342f4a5ef337e165b7a016e6cd
|
||||
F ext/rtree/rtree.c 4646fb3f52f11842450c6465af382589d8a232ab
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
F ext/rtree/rtree1.test 51bb0cd0405970501e63258401ae5ad235a4f468
|
||||
F ext/rtree/rtree2.test 7b665c44d25e51b3098068d983a39902b2e2d7a1
|
||||
@@ -94,9 +91,12 @@ F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
|
||||
F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
|
||||
F ext/rtree/tkt3363.test 2bf324f7908084a5f463de3109db9c6e607feb1b
|
||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ext/sqlrr/README.txt 4239030e73023e72a2e727808cd433577d5bf730
|
||||
F ext/sqlrr/sqlrr.c 8d1e6571cd6a6beabdb5bcdfe3a0e723b914db41
|
||||
F ext/sqlrr/sqlrr.h 09e4f8929ad9bc2638732c0cc0db5eef8c417824
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F main.mk 26ad86cf0689940f19b3d608bbfdb3956b2fb9a7
|
||||
F main.mk c65aaec3a68162beb49281cbfed56cf17f1701a1
|
||||
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
|
||||
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
|
||||
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
|
||||
@@ -128,20 +128,20 @@ F src/delete.c 7ed8a8c8b5f748ece92df173d7e0f7810c899ebd
|
||||
F src/expr.c 9ee507c3dc6eaa5657cbd1dad026cdeda89c559f
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 58bbf52c6ddd3f64ca40a3230f9e548a83a5cb16
|
||||
F src/func.c 464b0dc70618b896c402c574eb04bc5eacf35341
|
||||
F src/func.c 62373e488ecf8b29a28548ff9d922a9fae36b808
|
||||
F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3
|
||||
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
|
||||
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c a4995747c062256582a90b4f87f716e11b067050
|
||||
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/legacy.c 015826a958f690302d27e096a68d50b3657e4201
|
||||
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
|
||||
F src/loadext.c 6d422ea91cf3d2d00408c5a8f2391cd458da85f8
|
||||
F src/main.c 99622181f36d68e9f2a851c7b34263b3dcd03470
|
||||
F src/main.c 79573a52c9746bdc3e7942e0127556fa39cdbae5
|
||||
F src/malloc.c 19a468460c7df72de245f10c06bd0625777b7c83
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 89d4ea8d5cdd55635cbaa48ad53132af6294cbb2
|
||||
F src/mem1.c 0f36f1eecd786240924a56f8796ffa850d47a96f
|
||||
F src/mem2.c 9e5f72e38573db9598fe60d3fa530d473cc8714e
|
||||
F src/mem3.c 9b237d911ba9904142a804be727cc6664873f8a3
|
||||
F src/mem5.c eb7a5cb98915dd7a086fa415ce3a5a0f20d0acff
|
||||
@@ -157,16 +157,16 @@ F src/os.c 60178f518c4d6c0dcb59f7292232281d7bea2dcf
|
||||
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
|
||||
F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
|
||||
F src/os_os2.c 72d0b2e562952a2464308c4ce5f7913ac10bef3e
|
||||
F src/os_unix.c 11194cbcf6a57456e58022dc537ab8c3497d9bb9
|
||||
F src/os_unix.c 79cf726c9a0bcc4691a01389031513c10bf15bed
|
||||
F src/os_win.c 51cb62f76262d961ea4249489383d714501315a7
|
||||
F src/pager.c a5f5d9787b11dfb0b6082e6f5846d00b459a8e19
|
||||
F src/pager.c b9809c31985b77437d89649b5dc351b45e01551b
|
||||
F src/pager.h ef8c8f71ab022cc2fff768a1175dd32355be9dcd
|
||||
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
|
||||
F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07
|
||||
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
|
||||
F src/pcache1.c e921e8a1d52c93abde63cb6dad1fa39770410c52
|
||||
F src/pragma.c 8b24ce00a93de345b6c3bd1e1e2cfba9f63d2325
|
||||
F src/prepare.c ce4c35a2b1d5fe916e4a46b70d24a6e997d7c4c6
|
||||
F src/pragma.c 6a641dec2c137092ef2b7489e4943b878cf2cbfd
|
||||
F src/prepare.c 23b5da0608820c9f76aa61d4955ebdbd23ffda36
|
||||
F src/printf.c 8ae5082dd38a1b5456030c3755ec3a392cd51506
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
|
||||
@@ -174,13 +174,14 @@ F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c 8add6cab889fc02e1492eda8dba462ccf11f51dd
|
||||
F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056
|
||||
F src/sqlite.h.in 2d72a6242df41c517e38eec8791abcf5484a36f1
|
||||
F src/sqlite3_private.h 2a814d17913732831acf13e7e87860105a3416e4
|
||||
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
|
||||
F src/sqliteInt.h e33b15e8176442bf7484f0e716edfd1ce03b2979
|
||||
F src/sqliteInt.h a4231c81ff0d3767b61ca7a15268f91d778726b1
|
||||
F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
|
||||
F src/status.c 496913d4e8441195f6f2a75b1c95993a45b9b30b
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c cacee9482417b6fc6043f6bb831ff9496d46242d
|
||||
F src/test1.c 55005c9781b157b1d215ba145768783b9abae78c
|
||||
F src/test1.c 6abff878520c77f10891b06c36a57b3226ebc3d4
|
||||
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
|
||||
F src/test3.c 4c21700c73a890a47fc685c1097bfb661346ac94
|
||||
F src/test4.c 0528360b5025688002a5feb6be906ddce52eaaee
|
||||
@@ -191,9 +192,9 @@ F src/test8.c 6b1d12912a04fe6fca8c45bb9c3ea022f4352228
|
||||
F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
|
||||
F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad
|
||||
F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e
|
||||
F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de
|
||||
F src/test_backup.c 64fd6173ad99daade1227aa17c3ca0d18fa5e5fa
|
||||
F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2
|
||||
F src/test_config.c 5a11c51af2156e2d07186930b36f2b8239a4393f
|
||||
F src/test_config.c 91e758b037c7c58a6e3b3ce6babae883666174e9
|
||||
F src/test_demovfs.c 0aed671636735116fc872c5b03706fd5612488b5
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_func.c 13b582345fb1185a93e46c53310fae8547dcce20
|
||||
@@ -221,10 +222,10 @@ F src/update.c 1521162d20c2994af1fdc8833e1a88dae09052c8
|
||||
F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
|
||||
F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b
|
||||
F src/vacuum.c 241a8386727c1497eba4955933356dfba6ff8c9f
|
||||
F src/vdbe.c 66c262a923915e596379b1d597178e04c5d719e4
|
||||
F src/vdbe.c 60ef76968e7ab2288ee1e39573a090e549fd8f3d
|
||||
F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2
|
||||
F src/vdbeInt.h ffd68c4d4229227a5089bec53a1c635146177abc
|
||||
F src/vdbeapi.c d0f4407e465f261780ad725c1caece7d66a6aa35
|
||||
F src/vdbeapi.c 232d20465aa606c12520840597361279c7a96236
|
||||
F src/vdbeaux.c c73bcefcebfd3d2cf91bf6a41ef0fb0d884814c6
|
||||
F src/vdbeblob.c 258a6010ba7a82b72b327fb24c55790655689256
|
||||
F src/vdbemem.c e5673f81a2381b35c60e73ef0a8502be2ab1041e
|
||||
@@ -250,7 +251,7 @@ F test/async2.test bf5e2ca2c96763b4cba3d016249ad7259a5603b6
|
||||
F test/async3.test 93edaa9122f498e56ea98c36c72abc407f4fb11e
|
||||
F test/async4.test 1787e3952128aa10238bf39945126de7ca23685a
|
||||
F test/async5.test f3592d79c84d6e83a5f50d3fd500445f7d97dfdf
|
||||
F test/attach.test ce9660e51768fab93cf129787be886c5d6c4fd81
|
||||
F test/attach.test ccdedd5496a0244f8e45366ba9253af30083ea84
|
||||
F test/attach2.test a295d2d7061adcee5884ef4a93c7c96a82765437
|
||||
F test/attach3.test bd9830bc3a0d22ed1310c9bff6896927937017dc
|
||||
F test/attachmalloc.test 38d2da5fdaf09ba0add57296967a3061e5842584
|
||||
@@ -271,7 +272,7 @@ F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f
|
||||
F test/between.test 16b1776c6323faadb097a52d673e8e3d8be7d070
|
||||
F test/bigfile.test a8ec8073a20207456dab01a29ad9cde42b0dd103
|
||||
F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747
|
||||
F test/bind.test 3c7b320969000c441a70952b0b15938fbb66237c
|
||||
F test/bind.test 30af0fc61bc3836034215cdbdeca46113ca1b4a1
|
||||
F test/bindxfer.test efecd12c580c14df5f4ad3b3e83c667744a4f7e0
|
||||
F test/bitvec.test 75894a880520164d73b1305c1c3f96882615e142
|
||||
F test/blob.test e7ac6c7d3a985cc4678c64f325292529a69ae252
|
||||
@@ -351,11 +352,11 @@ F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
|
||||
F test/enc2.test 6d91a5286f59add0cfcbb2d0da913b76f2242398
|
||||
F test/enc3.test 5c550d59ff31dccdba5d1a02ae11c7047d77c041
|
||||
F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
|
||||
F test/exclusive.test b1f9012cabc124af947165d15ffa62ad20f63db8
|
||||
F test/exclusive.test 9e62270fdf967870921053e2ec0f293b67c140a4
|
||||
F test/exclusive2.test fcbb1c9ca9739292a0a22a3763243ad6d868086b
|
||||
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
|
||||
F test/expr.test 9f521ae22f00e074959f72ce2e55d46b9ed23f68
|
||||
F test/fallocate.test 43dc34b8c24be6baffadc3b4401ee15710ce83c6
|
||||
F test/fallocate.test a9927b638567e2e776c112f54d701402a0e74023
|
||||
F test/filectrl.test 97003734290887566e01dded09dc9e99cb937e9e
|
||||
F test/filefmt.test f77c92141960b7933bc6691631d2ad62257ef40a
|
||||
F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
|
||||
@@ -474,7 +475,7 @@ F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe
|
||||
F test/join6.test bf82cf3f979e9eade83ad0d056a66c5ed71d1901
|
||||
F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19
|
||||
F test/journal2.test 50a3604768494d4a337f194f0a9480e7c57dcb72
|
||||
F test/journal3.test ff175219be1b02d2f7e54297ad7e491b7533edb6
|
||||
F test/journal3.test 7cfbd86429305c96c9d985665320db5364764d96
|
||||
F test/jrnlmode.test e3fe6c4a2c3213d285650dc8e33aab7eaaa5ce53
|
||||
F test/jrnlmode2.test a19e28de1a6ec898067e46a122f1b71c9323bf00
|
||||
F test/jrnlmode3.test cfcdb12b90e640a23b92785a002d96c0624c8710
|
||||
@@ -490,12 +491,13 @@ F test/lock.test 842e80b6be816c79525a20b098cca066989feed7
|
||||
F test/lock2.test 5242d8ac4e2d59c403aebff606af449b455aceff
|
||||
F test/lock3.test f271375930711ae044080f4fe6d6eda930870d00
|
||||
F test/lock4.test c82268c031d39345d05efa672f80b025481b3ae5
|
||||
F test/lock5.test b2abb5e711bc59b0eae00f6c97a36ec9f458fada
|
||||
F test/lock6.test 8df56060f396151777390982422c800d026e1722
|
||||
F test/lock5.test d0d313f059ae5661726d3f197ba6ed8f69257d8e
|
||||
F test/lock6.test 55bbfce7a6905be8282f125c2dbeb8688e2cfd8b
|
||||
F test/lock7.test 64006c84c1c616657e237c7ad6532b765611cf64
|
||||
F test/lock_common.tcl 18c637fc89e12f1ac0d27d2186f12c3d3f789e3e
|
||||
F test/lock_proxy.test 95be9c32d79be25cf643b4e41a0aa0e53aa21621
|
||||
F test/lookaside.test 382e7bc2fab23d902c8eafb1b9ed7ababfff75a6
|
||||
F test/main.test 9d7bbfcc1b52c88ba7b2ba6554068ecf9939f252
|
||||
F test/main.test 753e2b772c041bd8dbd17c7e4132b3981378eaab
|
||||
F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
|
||||
F test/malloc.test 927e6c8668a1d48c23aa6189bda02aff5a1b83de
|
||||
F test/malloc3.test 4bc57f850b212f706f3e1b37c4eced1d5a727cd1
|
||||
@@ -517,11 +519,11 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb
|
||||
F test/mallocI.test a88c2b9627c8506bf4703d8397420043a786cdb6
|
||||
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
|
||||
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
|
||||
F test/malloc_common.tcl f4a04b7a733eb114a3da16eb39035cde2c851220
|
||||
F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c
|
||||
F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498
|
||||
F test/malloc_common.tcl bd0b0916f03cb4f4c973bcb793f3057e84d5ecfb
|
||||
F test/manydb.test 7faa0df55bbab2b14c25f323801db336c4e7ce3a
|
||||
F test/memdb.test f773146f66ee2c635854a8264317f39a6cc3e18c
|
||||
F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
|
||||
F test/memsubsys1.test 8fb47b7e2523f94c100f5885c5697505524de4b9
|
||||
F test/memsubsys1.test 98d5ff4c9f534cc863c07b74043bd44921893f29
|
||||
F test/memsubsys2.test 72a731225997ad5e8df89fdbeae9224616b6aecc
|
||||
F test/minmax.test 722d80816f7e096bf2c04f4111f1a6c1ba65453d
|
||||
F test/minmax2.test 33504c01a03bd99226144e4b03f7631a274d66e0
|
||||
@@ -543,17 +545,17 @@ F test/notify3.test d60923e186e0900f4812a845fcdfd8eea096e33a
|
||||
F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
|
||||
F test/null.test a8b09b8ed87852742343b33441a9240022108993
|
||||
F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec
|
||||
F test/pager1.test 6922029d71a8090169c71a67a141b6b94ad17d50
|
||||
F test/pager1.test 4d3bf78c043af2054cfb63897ef3f990a420c6a5
|
||||
F test/pager2.test 0fbb6b6dc40ce1fecfe758c555a748ad2e9beaa3
|
||||
F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f
|
||||
F test/pagerfault.test 84c6a4fcfe1a9e450fc1cec86f5baebfb017e53e
|
||||
F test/pagerfault.test f168ec2c659faccffc083ec1847bf4295dd67d14
|
||||
F test/pagerfault2.test 1f79ea40d1133b2683a2f811b00f2399f7ec2401
|
||||
F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806
|
||||
F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb
|
||||
F test/pcache.test 4118a183908ecaed343a06fcef3ba82e87e0129d
|
||||
F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16
|
||||
F test/permutations.test 17498d1219f922d5a6da893a94c4dc7766fb2426
|
||||
F test/pragma.test ed78d200f65c6998df51196cb8c39d5300570f24
|
||||
F test/pragma.test 421476c181fe8ddb528dcaac8b043aa1544983df
|
||||
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
|
||||
F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
|
||||
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
|
||||
@@ -591,7 +593,7 @@ F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532
|
||||
F test/selectB.test f305cc6660804cb239aab4e2f26b0e288b59958b
|
||||
F test/selectC.test f9bf1bc4581b5b8158caa6e4e4f682acb379fb25
|
||||
F test/server1.test f5b790d4c0498179151ca8a7715a65a7802c859c
|
||||
F test/shared.test b9114eaea7e748a3a4c8ff7b9ca806c8f95cef3e
|
||||
F test/shared.test e5ed27551ba06b28e851101683f0caef1445f4ac
|
||||
F test/shared2.test d6ba4ca1827ea36a1ac23a99e3c36eeac9165450
|
||||
F test/shared3.test d69bdd5f156580876c5345652d21dc2092e85962
|
||||
F test/shared4.test d0fadacb50bb6981b2fb9dc6d1da30fa1edddf83
|
||||
@@ -613,8 +615,8 @@ F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/sqllimits1.test e90a0ed94452076f6a10209d378e06b5f75ef0a0
|
||||
F test/stat.test 70fe540ffb285947aead5533dfd0c8c12f17f14e
|
||||
F test/stmt.test 7915bd3e8380b956c095f40f41a775a30716e649
|
||||
F test/stat.test 8b7342007bdb49a9427d57a9bb94d02d6e54f2d0
|
||||
F test/stmt.test 8e39760750cdf8044d4ca441b2b95053817c9a5f
|
||||
F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796
|
||||
F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
|
||||
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
@@ -622,10 +624,10 @@ F test/sync.test ded6b39d8d8ca3c0c5518516c6371b3316d3e3a3
|
||||
F test/table.test 04ba066432430657712d167ebf28080fe878d305
|
||||
F test/tableapi.test 7262a8cbaa9965d429f1cbd2747edc185fa56516
|
||||
F test/tclsqlite.test 8c154101e704170c2be10f137a5499ac2c6da8d3
|
||||
F test/tempdb.test 800c36623d67a2ad1f58784b9c5644e0405af6e6
|
||||
F test/tempdb.test 285dda9fdf10730702549e8aa19c9258bbf753b8
|
||||
F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a
|
||||
F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05
|
||||
F test/tester.tcl 6135019fcfac363ea0e11aee670cc97080ab578e
|
||||
F test/tester.tcl e4bed769a9e7b55d569fe90e9548fc86d405acf8
|
||||
F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f
|
||||
F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db
|
||||
F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca
|
||||
@@ -705,7 +707,7 @@ F test/tkt3357.test 77c37c6482b526fe89941ce951c22d011f5922ed
|
||||
F test/tkt3419.test 1bbf36d7ea03b638c15804251287c2391f5c1f6b
|
||||
F test/tkt3424.test 61f831bd2b071bd128fa5d00fbda57e656ca5812
|
||||
F test/tkt3442.test 89d7b41a4ec4d9d9b40ab8575d648579fb13cb4f
|
||||
F test/tkt3457.test edbf54b05cbe5165f00192becbd621038f1615e4
|
||||
F test/tkt3457.test 8a8f29536bf65b994bef5dde881404530b61a62a
|
||||
F test/tkt3461.test 228ea328a5a21e8663f80ee3d212a6ad92549a19
|
||||
F test/tkt3493.test 1686cbde85f8721fc1bdc0ee72f2ef2f63139218
|
||||
F test/tkt3508.test d75704db9501625c7f7deec119fcaf1696aefb7d
|
||||
@@ -787,22 +789,22 @@ F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61
|
||||
F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
|
||||
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
||||
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
|
||||
F test/wal.test 70227190e713b3e7eb2a7d5ec3510b66db01f327
|
||||
F test/wal2.test 223f3e14d475730af772a7f5862d4bcfa7565c3a
|
||||
F test/wal3.test 695ea0f6c516423c611891df9a285aacd33344e3
|
||||
F test/wal4.test 3404b048fa5e10605facaf70384e6d2943412e30
|
||||
F test/wal.test d83c3d227e9e9bb5c7a0c1447ea4a3c6cd5fced4
|
||||
F test/wal2.test 03f5f0e14cf26120d2bc2daedb6952a93b981c8e
|
||||
F test/wal3.test 09278a6f54b3a847b502f426a63a0a3028c4e57e
|
||||
F test/wal4.test 6a68c45bc1ca24a3592ec449ddcb92b29d0e0e87
|
||||
F test/wal_common.tcl 895d76138043b86bdccf36494054bdabcf65837b
|
||||
F test/walbak.test 4df1c7369da0301caeb9a48fa45997fd592380e4
|
||||
F test/walbig.test e882bc1d014afffbfa2b6ba36e0f07d30a633ad0
|
||||
F test/walcksum.test a37b36375c595e61bdb7e1ec49b5f0979b6fc7ce
|
||||
F test/walcrash.test e763841551d6b23677ccb419797c1589dcbdbaf5
|
||||
F test/walcrash2.test 019d60b89d96c1937adb2b30b850ac7e86e5a142
|
||||
F test/walfault.test 05c470688d742688e455dd56816bd6bcffa298f8
|
||||
F test/walhook.test ed00a40ba7255da22d6b66433ab61fab16a63483
|
||||
F test/walmode.test 4ecd37284f245247f7935896ab66f6943f0432a0
|
||||
F test/walshared.test 985b4a3406b2b2dace1d52a42d26a11dd6900981
|
||||
F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
|
||||
F test/walthread.test a25a393c068a2b42b44333fa3fdaae9072f1617c
|
||||
F test/walbak.test 767e1c9e0ea0cfb907873b332883e66e187fa4bc
|
||||
F test/walbig.test 78ac493db2abdb65b9c6cace5b851cc32df1d449
|
||||
F test/walcksum.test cf6787f2ee1a6a3da6f0c2b20b9ede5153e4e03f
|
||||
F test/walcrash.test 80c1cc3173a0ef09d8303fa556cb0187a36d82ea
|
||||
F test/walcrash2.test 929c99d14ee2e3e3ef82585058968a8b12f72706
|
||||
F test/walfault.test 60527645638532a565a8e729db287ef0dba85ece
|
||||
F test/walhook.test c934ac5219fee2b4e7653d291db9107b8dc73bba
|
||||
F test/walmode.test 8746ec81f78597e0f988d8e31347dc1b9b22ebbd
|
||||
F test/walshared.test 51082db7d1edc720256c524e9b22e92c50f72149
|
||||
F test/walslow.test 989854bc5c214700a9f2d545bb158643813b8881
|
||||
F test/walthread.test e6e32e93ccebfa401dfc0dd930c79daa3472b0ae
|
||||
F test/where.test de337a3fe0a459ec7c93db16a519657a90552330
|
||||
F test/where2.test 43d4becaf5a5df854e6c21d624a1cb84c6904554
|
||||
F test/where3.test 3bf8006d441b66a57bee02bb420423f84eb8fde3
|
||||
@@ -826,7 +828,7 @@ F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc
|
||||
F tool/mkkeywordhash.c d2e6b4a5965e23afb80fbe74bb54648cd371f309
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c.tcl aff0d53f0e84cf919922c0d02e767bdf5eeafb90
|
||||
F tool/mksqlite3c.tcl be5206d081291aa4c0e1a328331171425bdbe77c
|
||||
F tool/mksqlite3h.tcl eb100dce83f24b501b325b340f8b5eb8e5106b3b
|
||||
F tool/mksqlite3internalh.tcl 7b43894e21bcb1bb39e11547ce7e38a063357e87
|
||||
F tool/omittest.tcl 27d6f6e3b1e95aeb26a1c140e6eb57771c6d794a
|
||||
@@ -849,14 +851,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P 42537b60566f288167f1b5864a5435986838e3a3
|
||||
R 2c180f83601b5fb3eca266f1d7990e7f
|
||||
U drh
|
||||
Z 10d60dee314996598be1db5d0c7786c6
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||
|
||||
iD8DBQFMcyU/oxKgR168RlERAix8AJ4mlLsRwIdCGZXuMMz9jxnrImU9JACffIYe
|
||||
yL2XIDq+iw10tkqZ3HaRjys=
|
||||
=n6uZ
|
||||
-----END PGP SIGNATURE-----
|
||||
P f59949fac1776ea2f58f41ee8aef8dd95b67725a
|
||||
R 10ec051ad734b09d2ce7d88de83d010e
|
||||
U dan
|
||||
Z 13849545f92827f8d5abaf3d106e2e3f
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
7f2f71cc9e3c39093f09231f448576cff6afb5fe
|
||||
756589ad6e286a898ca34ff1b14d5bb4843529e1
|
||||
@@ -207,6 +207,9 @@ static void substrFunc(
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef SQLITE_SUBSTR_COMPATIBILITY
|
||||
if( p1==0 ) p1 = 1; /* <rdar://problem/6778339> */
|
||||
#endif
|
||||
if( argc==3 ){
|
||||
p2 = sqlite3_value_int(argv[2]);
|
||||
if( p2<0 ){
|
||||
|
||||
+9
-1
@@ -16,6 +16,9 @@
|
||||
*/
|
||||
|
||||
#include "sqliteInt.h"
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
# include "sqlrr.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Execute SQL code. Return one of the SQLITE_ success/failure
|
||||
@@ -43,7 +46,9 @@ int sqlite3_exec(
|
||||
|
||||
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
|
||||
if( zSql==0 ) zSql = "";
|
||||
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecExec(db, zSql);
|
||||
#endif
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
sqlite3Error(db, SQLITE_OK, 0);
|
||||
while( (rc==SQLITE_OK || (rc==SQLITE_SCHEMA && (++nRetry)<2)) && zSql[0] ){
|
||||
@@ -124,6 +129,9 @@ int sqlite3_exec(
|
||||
exec_out:
|
||||
if( pStmt ) sqlite3VdbeFinalize((Vdbe *)pStmt);
|
||||
sqlite3DbFree(db, azCols);
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecExecEnd(db);
|
||||
#endif
|
||||
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
if( rc!=SQLITE_OK && ALWAYS(rc==sqlite3_errcode(db)) && pzErrMsg ){
|
||||
|
||||
+25
@@ -16,6 +16,9 @@
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
# include "sqlrr.h"
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_FTS3
|
||||
# include "fts3.h"
|
||||
#endif
|
||||
@@ -717,6 +720,10 @@ int sqlite3_close(sqlite3 *db){
|
||||
if( db->lookaside.bMalloced ){
|
||||
sqlite3_free(db->lookaside.pStart);
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecClose(db);
|
||||
#endif
|
||||
|
||||
sqlite3_free(db);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -1658,6 +1665,12 @@ int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
|
||||
}
|
||||
return oldLimit;
|
||||
}
|
||||
#if defined(SQLITE_ENABLE_AUTO_PROFILE)
|
||||
static void profile_sql(void *aux, const char *sql, u64 ns) {
|
||||
#pragma unused(aux)
|
||||
fprintf(stderr, "Query: %s\n Execution Time: %llu ms\n", sql, ns / 1000000);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This routine does the work of opening a database on behalf of
|
||||
@@ -1890,7 +1903,19 @@ opendb_out:
|
||||
}else if( rc!=SQLITE_OK ){
|
||||
db->magic = SQLITE_MAGIC_SICK;
|
||||
}
|
||||
#if defined(SQLITE_ENABLE_AUTO_PROFILE)
|
||||
if( db && !rc ){
|
||||
char *envprofile = getenv("SQLITE_AUTO_PROFILE");
|
||||
|
||||
if( envprofile!=NULL ){
|
||||
sqlite3_profile(db, profile_sql, NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
*ppDb = db;
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecOpen(db, zFilename, flags);
|
||||
#endif
|
||||
return sqlite3ApiExit(0, rc);
|
||||
}
|
||||
|
||||
|
||||
+71
-3
@@ -26,6 +26,28 @@
|
||||
*/
|
||||
#ifdef SQLITE_SYSTEM_MALLOC
|
||||
|
||||
#if (!defined(__APPLE__))
|
||||
|
||||
#define SQLITE_MALLOC(x) malloc(x)
|
||||
#define SQLITE_FREE(x) free(x)
|
||||
#define SQLITE_REALLOC(x,y) realloc((x),(y))
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
#include <malloc/malloc.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
|
||||
static malloc_zone_t* _sqliteZone_;
|
||||
|
||||
#define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x))
|
||||
#define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x));
|
||||
#define SQLITE_REALLOC(x,y) malloc_zone_realloc(_sqliteZone_, (x), (y))
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Like malloc(), but remember the size of the allocation
|
||||
** so that we can find it later using sqlite3MemSize().
|
||||
@@ -38,7 +60,7 @@ static void *sqlite3MemMalloc(int nByte){
|
||||
sqlite3_int64 *p;
|
||||
assert( nByte>0 );
|
||||
nByte = ROUND8(nByte);
|
||||
p = malloc( nByte+8 );
|
||||
p = SQLITE_MALLOC( nByte+8 );
|
||||
if( p ){
|
||||
p[0] = nByte;
|
||||
p++;
|
||||
@@ -61,7 +83,7 @@ static void sqlite3MemFree(void *pPrior){
|
||||
sqlite3_int64 *p = (sqlite3_int64*)pPrior;
|
||||
assert( pPrior!=0 );
|
||||
p--;
|
||||
free(p);
|
||||
SQLITE_FREE(p);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -91,7 +113,7 @@ static void *sqlite3MemRealloc(void *pPrior, int nByte){
|
||||
assert( pPrior!=0 && nByte>0 );
|
||||
nByte = ROUND8(nByte);
|
||||
p--;
|
||||
p = realloc(p, nByte+8 );
|
||||
p = SQLITE_REALLOC(p, nByte+8 );
|
||||
if( p ){
|
||||
p[0] = nByte;
|
||||
p++;
|
||||
@@ -115,6 +137,37 @@ static int sqlite3MemRoundup(int n){
|
||||
** Initialize this module.
|
||||
*/
|
||||
static int sqlite3MemInit(void *NotUsed){
|
||||
#if defined(__APPLE__)
|
||||
if (_sqliteZone_) {
|
||||
return SQLITE_OK;
|
||||
}
|
||||
int cpuCount;
|
||||
size_t len;
|
||||
|
||||
len = sizeof(cpuCount);
|
||||
sysctlbyname("hw.ncpu", &cpuCount, &len, NULL, 0); // one almost always wants to use "hw.activecpu" for MT decisions, but not here.
|
||||
|
||||
if (cpuCount > 1) {
|
||||
// defer MT decisions to system malloc
|
||||
_sqliteZone_ = malloc_default_zone();
|
||||
} else {
|
||||
// only 1 core, use our own zone to contention over global locks,
|
||||
// e.g. we have our own dedicated locks
|
||||
malloc_zone_t* newzone = malloc_create_zone(4096, 0);
|
||||
malloc_set_zone_name(newzone, "Sqlite_Heap");
|
||||
|
||||
bool success;
|
||||
do {
|
||||
success = OSAtomicCompareAndSwapPtrBarrier(NULL, newzone, (void * volatile *)&_sqliteZone_);
|
||||
} while (!_sqliteZone_);
|
||||
|
||||
if (!success) {
|
||||
// somebody registered a zone first
|
||||
malloc_destroy_zone(newzone);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -123,6 +176,17 @@ static int sqlite3MemInit(void *NotUsed){
|
||||
** Deinitialize this module.
|
||||
*/
|
||||
static void sqlite3MemShutdown(void *NotUsed){
|
||||
#if (0 && defined(__APPLE__))
|
||||
if (_sqliteZone_ && (_sqliteZone_ != malloc_default_zone())) {
|
||||
malloc_zone_t* oldzone = _sqliteZone_;
|
||||
|
||||
bool success = OSAtomicCompareAndSwapPtrBarrier(oldzone, NULL, (void * volatile *)&_sqliteZone_);
|
||||
if (success) {
|
||||
malloc_destroy_zone(oldzone);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
return;
|
||||
}
|
||||
@@ -147,4 +211,8 @@ void sqlite3MemSetDefault(void){
|
||||
sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
|
||||
}
|
||||
|
||||
#undef SQLITE_MALLOC
|
||||
#undef SQLITE_FREE
|
||||
#undef SQLITE_REALLOC
|
||||
|
||||
#endif /* SQLITE_SYSTEM_MALLOC */
|
||||
|
||||
+298
-26
@@ -2808,6 +2808,12 @@ int sqlite3_fullsync_count = 0;
|
||||
# define HAVE_FULLFSYNC 0
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_USE_REQUEST_FULLFSYNC
|
||||
#import <notify.h>
|
||||
#import <libkern/OSAtomic.h>
|
||||
static OSSpinLock notify_lock = 0;
|
||||
#define REQUEST_FULLSYNC_NOTIFICATION "com.apple.reqsync"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The fsync() system call does not work as advertised on many
|
||||
@@ -2867,7 +2873,16 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
|
||||
rc = SQLITE_OK;
|
||||
#elif HAVE_FULLFSYNC
|
||||
if( fullSync ){
|
||||
#ifdef SQLITE_USE_REQUEST_FULLFSYNC
|
||||
rc = fsync(fd);
|
||||
if (!rc) {
|
||||
OSSpinLockLock(¬ify_lock);
|
||||
rc = notify_post(REQUEST_FULLSYNC_NOTIFICATION);
|
||||
OSSpinLockUnlock(¬ify_lock);
|
||||
}
|
||||
#else
|
||||
rc = fcntl(fd, F_FULLFSYNC, 0);
|
||||
#endif
|
||||
}else{
|
||||
rc = 1;
|
||||
}
|
||||
@@ -3096,6 +3111,12 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
|
||||
#include "sqlite3_private.h"
|
||||
#include <copyfile.h>
|
||||
static int getDbPathForUnixFile(unixFile *pFile, char *dbPath);
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Information and control of an open file handle.
|
||||
*/
|
||||
@@ -3133,6 +3154,219 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
return proxyFileControl(id,op,pArg);
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
|
||||
#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
|
||||
case SQLITE_TRUNCATE_DATABASE: {
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
int trc = SQLITE_OK;
|
||||
int eFileLock = pFile->eFileLock;
|
||||
int rc = SQLITE_OK;
|
||||
char jPath[MAXPATHLEN+9];
|
||||
size_t jLen;
|
||||
|
||||
if( eFileLock<SQLITE_LOCK_SHARED ){
|
||||
rc = pFile->pMethod->xLock(id, SQLITE_LOCK_SHARED);
|
||||
}
|
||||
if( !rc && eFileLock<SQLITE_LOCK_EXCLUSIVE ){
|
||||
rc = pFile->pMethod->xLock(id, SQLITE_LOCK_EXCLUSIVE);
|
||||
}
|
||||
if( rc ){
|
||||
if( pFile->eFileLock > eFileLock ){
|
||||
pFile->pMethod->xUnlock(id, eFileLock);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
rc = pFile->pMethod->xTruncate(id, ((pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS) != 0) ? 1L : 0L);
|
||||
if( !rc && (SQLITE_OK==getDbPathForUnixFile(pFile, jPath)) ){
|
||||
jLen = strlcat(jPath, "-journal", MAXPATHLEN+9);
|
||||
if( jLen < MAXPATHLEN+9 ){
|
||||
int jfd = open(jPath, O_TRUNC);
|
||||
if( (jfd == -1) ){
|
||||
if ( errno!=ENOENT ){
|
||||
perror(jPath);
|
||||
}
|
||||
} else {
|
||||
fsync(jfd);
|
||||
close(jfd);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
trc=rc;
|
||||
}
|
||||
if( !trc ){
|
||||
trc = pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);
|
||||
}
|
||||
if( pFile->eFileLock > eFileLock ){
|
||||
int unlockRC = pFile->pMethod->xUnlock(id, SQLITE_LOCK_SHARED);
|
||||
if (!rc) rc = unlockRC;
|
||||
}
|
||||
if( pFile->eFileLock > eFileLock ){
|
||||
int unlockRC = pFile->pMethod->xUnlock(id, SQLITE_LOCK_NONE);
|
||||
if (!rc) rc = unlockRC;
|
||||
}
|
||||
if( trc ){
|
||||
return trc;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
case SQLITE_REPLACE_DATABASE: {
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
int trc = SQLITE_OK;
|
||||
int eFileLock = pFile->eFileLock;
|
||||
int rc = SQLITE_OK;
|
||||
char jPath[MAXPATHLEN+9];
|
||||
size_t jLen;
|
||||
sqlite3 *srcdb = (sqlite3 *)pArg;
|
||||
Btree *pSrcBtree = NULL;
|
||||
int eSrcFileLock = SQLITE_LOCK_NONE;
|
||||
int srcLockRC = -1;
|
||||
sqlite3_file *src_file = NULL;
|
||||
unixFile *pSrcFile = NULL;
|
||||
|
||||
if( !sqlite3SafetyCheckOk(srcdb) ){
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
if( eFileLock<SQLITE_LOCK_SHARED ){
|
||||
rc = pFile->pMethod->xLock(id, SQLITE_LOCK_SHARED);
|
||||
}
|
||||
if( !rc && eFileLock<SQLITE_LOCK_EXCLUSIVE ){
|
||||
rc = pFile->pMethod->xLock(id, SQLITE_LOCK_EXCLUSIVE);
|
||||
}
|
||||
if( !rc ){
|
||||
/* get the src file descriptor adhering to the db struct access rules
|
||||
** this code is modeled after sqlite3_file_control() in main.c
|
||||
*/
|
||||
sqlite3_mutex_enter(srcdb->mutex);
|
||||
if( srcdb->nDb>0 ){
|
||||
pSrcBtree = srcdb->aDb[0].pBt;
|
||||
}
|
||||
if( pSrcBtree ){
|
||||
Pager *pSrcPager;
|
||||
sqlite3BtreeEnter(pSrcBtree);
|
||||
pSrcPager = sqlite3BtreePager(pSrcBtree);
|
||||
assert( pSrcPager!=0 );
|
||||
src_file = sqlite3PagerFile(pSrcPager);
|
||||
assert( src_file!=0 );
|
||||
if( src_file->pMethods ){
|
||||
pSrcFile = (unixFile *)src_file;
|
||||
eSrcFileLock = pSrcFile->eFileLock;
|
||||
if( eSrcFileLock<SQLITE_LOCK_SHARED ){
|
||||
rc = pSrcFile->pMethod->xLock(src_file, SQLITE_LOCK_SHARED);
|
||||
srcLockRC = rc; /* SQLITE_OK means we need to unlock later */
|
||||
} else if( eSrcFileLock==SQLITE_LOCK_EXCLUSIVE ){
|
||||
/* if the src database has an exclusive lock, verify that the
|
||||
** it doesn't have a journal file with open transactions
|
||||
*/
|
||||
if( getDbPathForUnixFile(pSrcFile, jPath) ){
|
||||
rc = SQLITE_INTERNAL;
|
||||
}else{
|
||||
jLen = strlcat(jPath, "-journal", MAXPATHLEN+9);
|
||||
if( jLen < MAXPATHLEN+9 ){
|
||||
int jfd = open(jPath, O_RDONLY);
|
||||
if( jfd==-1 ){
|
||||
if( errno!=ENOENT ){
|
||||
pFile->lastErrno = errno;
|
||||
rc = SQLITE_IOERR;
|
||||
}
|
||||
}else{
|
||||
/* if the journal exists ensure there's no pending
|
||||
** transaction by checking the journal header */
|
||||
char magic[8];
|
||||
ssize_t rlen = pread(jfd, magic, 8, 0);
|
||||
if( rlen<0 ){
|
||||
pFile->lastErrno = errno;
|
||||
rc = SQLITE_IOERR;
|
||||
}else if( rlen==8 ){
|
||||
char test[8] = {'\0','\0','\0','\0','\0','\0','\0','\0'};
|
||||
if( memcmp(magic,test,8) ){
|
||||
rc = SQLITE_LOCKED;
|
||||
}
|
||||
}else if( rlen!=0 ){
|
||||
rc = SQLITE_INTERNAL;
|
||||
}
|
||||
close(jfd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
rc = SQLITE_MISUSE;
|
||||
}
|
||||
if( rc ){
|
||||
if( srcLockRC==SQLITE_OK ){
|
||||
pSrcFile->pMethod->xUnlock(src_file, eSrcFileLock);
|
||||
}
|
||||
sqlite3BtreeLeave(pSrcBtree);
|
||||
}
|
||||
}
|
||||
if( pSrcFile==NULL || (pSrcFile->h<0) ){
|
||||
rc = SQLITE_INTERNAL;
|
||||
sqlite3_mutex_leave(srcdb->mutex);
|
||||
}
|
||||
}
|
||||
if( rc ){
|
||||
/* unroll state changes and return error code */
|
||||
if( pFile->eFileLock > eFileLock ){
|
||||
pFile->pMethod->xUnlock(id, eFileLock);
|
||||
}
|
||||
return rc;
|
||||
}else{
|
||||
/* both databases are locked appropriately, copy file data
|
||||
** and then unroll the locks we added.
|
||||
*/
|
||||
copyfile_state_t s;
|
||||
|
||||
s = copyfile_state_alloc();
|
||||
if( fcopyfile(pSrcFile->h, pFile->h, s, COPYFILE_ALL) ){
|
||||
switch(errno) {
|
||||
case ENOMEM:
|
||||
rc = SQLITE_NOMEM;
|
||||
break;
|
||||
default:
|
||||
rc = SQLITE_INTERNAL;
|
||||
}
|
||||
}
|
||||
copyfile_state_free(s);
|
||||
if( srcLockRC==SQLITE_OK ){
|
||||
pSrcFile->pMethod->xUnlock(src_file, eSrcFileLock);
|
||||
}
|
||||
sqlite3BtreeLeave(pSrcBtree);
|
||||
sqlite3_mutex_leave(srcdb->mutex);
|
||||
}
|
||||
|
||||
if( !rc && (SQLITE_OK==getDbPathForUnixFile(pFile, jPath)) ){
|
||||
jLen = strlcat(jPath, "-journal", MAXPATHLEN+9);
|
||||
if( jLen < MAXPATHLEN+9 ){
|
||||
int jfd = open(jPath, O_TRUNC);
|
||||
if( (jfd == -1) ){
|
||||
if ( errno!=ENOENT ){
|
||||
perror(jPath);
|
||||
}
|
||||
} else {
|
||||
fsync(jfd);
|
||||
close(jfd);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
trc=rc;
|
||||
}
|
||||
if( !trc ){
|
||||
trc = pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);
|
||||
}
|
||||
if( pFile->eFileLock > eFileLock ){
|
||||
int unlockRC = pFile->pMethod->xUnlock(id, SQLITE_LOCK_SHARED);
|
||||
if (!rc) rc = unlockRC;
|
||||
}
|
||||
if( pFile->eFileLock > eFileLock ){
|
||||
int unlockRC = pFile->pMethod->xUnlock(id, SQLITE_LOCK_NONE);
|
||||
if (!rc) rc = unlockRC;
|
||||
}
|
||||
if( trc ){
|
||||
return trc;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
@@ -3335,6 +3569,9 @@ static void unixShmPurge(unixFile *pFd){
|
||||
}
|
||||
}
|
||||
|
||||
static int isProxyLockingMode(unixFile *);
|
||||
static const char *proxySharedMemoryBasePath(unixFile *);
|
||||
|
||||
/*
|
||||
** Open a shared-memory area associated with open database file pDbFd.
|
||||
** This particular implementation uses mmapped files.
|
||||
@@ -3397,10 +3634,24 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
||||
goto shm_open_err;
|
||||
}
|
||||
|
||||
const char *zBasePath = pDbFd->zPath;
|
||||
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
|
||||
/* If pDbFd is configured with proxy locking mode, use the local
|
||||
** lock file path to determine the -shm file path
|
||||
*/
|
||||
if( isProxyLockingMode(pDbFd) ){
|
||||
zBasePath = proxySharedMemoryBasePath(pDbFd);
|
||||
if( !zBasePath ){
|
||||
rc = SQLITE_CANTOPEN_BKPT;
|
||||
goto shm_open_err;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_SHM_DIRECTORY
|
||||
nShmFilename = sizeof(SQLITE_SHM_DIRECTORY) + 30;
|
||||
#else
|
||||
nShmFilename = 5 + (int)strlen(pDbFd->zPath);
|
||||
nShmFilename = 5 + (int)strlen(zBasePath);
|
||||
#endif
|
||||
pShmNode = sqlite3_malloc( sizeof(*pShmNode) + nShmFilename );
|
||||
if( pShmNode==0 ){
|
||||
@@ -3414,7 +3665,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
||||
SQLITE_SHM_DIRECTORY "/sqlite-shm-%x-%x",
|
||||
(u32)sStat.st_ino, (u32)sStat.st_dev);
|
||||
#else
|
||||
sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", pDbFd->zPath);
|
||||
sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", zBasePath);
|
||||
#endif
|
||||
pShmNode->h = -1;
|
||||
pDbFd->pInode->pShmNode = pShmNode;
|
||||
@@ -3916,7 +4167,7 @@ static int proxyCheckReservedLock(sqlite3_file*, int*);
|
||||
IOMETHODS(
|
||||
proxyIoFinder, /* Finder function name */
|
||||
proxyIoMethods, /* sqlite3_io_methods object name */
|
||||
1, /* shared memory is disabled */
|
||||
2, /* shared memory is enabled */
|
||||
proxyClose, /* xClose method */
|
||||
proxyLock, /* xLock method */
|
||||
proxyUnlock, /* xUnlock method */
|
||||
@@ -4636,6 +4887,9 @@ static int unixOpen(
|
||||
if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) {
|
||||
((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
|
||||
}
|
||||
if (0 == strncmp("exfat", fsInfo.f_fstypename, 5)) {
|
||||
((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SQLITE_ENABLE_LOCKING_STYLE
|
||||
@@ -4651,35 +4905,24 @@ static int unixOpen(
|
||||
if( envforce!=NULL ){
|
||||
useProxy = atoi(envforce)>0;
|
||||
}else{
|
||||
struct statfs fsInfo;
|
||||
if( statfs(zPath, &fsInfo) == -1 ){
|
||||
/* In theory, the close(fd) call is sub-optimal. If the file opened
|
||||
** with fd is a database file, and there are other connections open
|
||||
** on that file that are currently holding advisory locks on it,
|
||||
** then the call to close() will cancel those locks. In practice,
|
||||
** we're assuming that statfs() doesn't fail very often. At least
|
||||
** not while other file descriptors opened by the same process on
|
||||
** the same file are working. */
|
||||
p->lastErrno = errno;
|
||||
if( dirfd>=0 ){
|
||||
close(dirfd); /* silently leak if fail, in error */
|
||||
}
|
||||
close(fd); /* silently leak if fail, in error */
|
||||
rc = SQLITE_IOERR_ACCESS;
|
||||
goto open_finished;
|
||||
}
|
||||
useProxy = !(fsInfo.f_flags&MNT_LOCAL);
|
||||
}
|
||||
if( useProxy ){
|
||||
rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete);
|
||||
if( rc==SQLITE_OK ){
|
||||
/* cache the pMethod in case the transform fails */
|
||||
const struct sqlite3_io_methods *pMethod = pFile->pMethods;
|
||||
rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:");
|
||||
if( rc!=SQLITE_OK ){
|
||||
/* Use unixClose to clean up the resources added in fillInUnixFile
|
||||
** and clear all the structure's references. Specifically,
|
||||
** pFile->pMethods will be NULL so sqlite3OsClose will be a no-op
|
||||
*/
|
||||
unixClose(pFile);
|
||||
if( pMethod!=NULL ){
|
||||
pMethod->xClose(pFile);
|
||||
}else{
|
||||
unixClose(pFile);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
@@ -5276,6 +5519,28 @@ static int proxyCreateLockPath(const char *lockPath){
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isProxyLockingMode(unixFile *pFile) {
|
||||
return (pFile->pMethod == &proxyIoMethods) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the shared memory base path based on the lock proxy file if the
|
||||
** lock proxy file is hosted on a shared memory compatible FS
|
||||
*/
|
||||
static const char *proxySharedMemoryBasePath(unixFile *pFile) {
|
||||
proxyLockingContext *pCtx;
|
||||
unixFile *pLockFile;
|
||||
|
||||
assert(pFile!=NULL && pFile->lockingContext!=NULL);
|
||||
assert(pFile->pMethod == &proxyIoMethods);
|
||||
pCtx = ((proxyLockingContext *)(pFile->lockingContext));
|
||||
pLockFile = pCtx->lockProxy;
|
||||
if( pLockFile->pMethod->iVersion>=2 && pLockFile->pMethod->xShmMap!=0 ){
|
||||
return pCtx->lockProxyPath;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new VFS file descriptor (stored in memory obtained from
|
||||
** sqlite3_malloc) and open the file named "path" in the file descriptor.
|
||||
@@ -5327,6 +5592,7 @@ static int proxyCreateUnixFile(
|
||||
terrno = errno;
|
||||
}
|
||||
if( fd<0 ){
|
||||
sqlite3_free(pUnused);
|
||||
if( islockfile ){
|
||||
return SQLITE_BUSY;
|
||||
}
|
||||
@@ -5876,7 +6142,7 @@ static int switchLockProxyPath(unixFile *pFile, const char *path) {
|
||||
** This routine find the filename associated with pFile and writes it
|
||||
** int dbPath.
|
||||
*/
|
||||
static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){
|
||||
static int getDbPathForUnixFile(unixFile *pFile, char *dbPath){
|
||||
#if defined(__APPLE__)
|
||||
if( pFile->pMethod == &afpIoMethods ){
|
||||
/* afp style keeps a reference to the db path in the filePath field
|
||||
@@ -5915,7 +6181,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
|
||||
if( pFile->eFileLock!=NO_LOCK ){
|
||||
return SQLITE_BUSY;
|
||||
}
|
||||
proxyGetDbPathForUnixFile(pFile, dbPath);
|
||||
getDbPathForUnixFile(pFile, dbPath);
|
||||
if( !path || path[0]=='\0' || !strcmp(path, ":auto:") ){
|
||||
lockPath=NULL;
|
||||
}else{
|
||||
@@ -5958,6 +6224,9 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
|
||||
}
|
||||
if( rc==SQLITE_OK && lockPath ){
|
||||
pCtx->lockProxyPath = sqlite3DbStrDup(0, lockPath);
|
||||
if( pCtx->lockProxyPath==NULL ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -5997,7 +6266,7 @@ static int proxyFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
switch( op ){
|
||||
case SQLITE_GET_LOCKPROXYFILE: {
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
if( pFile->pMethod == &proxyIoMethods ){
|
||||
if( isProxyLockingMode(pFile) ){
|
||||
proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext;
|
||||
proxyTakeConch(pFile);
|
||||
if( pCtx->lockProxyPath ){
|
||||
@@ -6013,10 +6282,13 @@ static int proxyFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
case SQLITE_SET_LOCKPROXYFILE: {
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
int rc = SQLITE_OK;
|
||||
int isProxyStyle = (pFile->pMethod == &proxyIoMethods);
|
||||
int isProxyStyle = isProxyLockingMode(pFile);
|
||||
if( pArg==NULL || (const char *)pArg==0 ){
|
||||
if( isProxyStyle ){
|
||||
/* turn off proxy locking - not supported */
|
||||
/* turn off proxy locking - not supported. If support is added for
|
||||
** switching proxy locking mode off then it will need to fail if
|
||||
** the journal mode is WAL mode.
|
||||
*/
|
||||
rc = SQLITE_ERROR /*SQLITE_PROTOCOL? SQLITE_MISUSE?*/;
|
||||
}else{
|
||||
/* turn off proxy locking - already off - NOOP */
|
||||
|
||||
+27
-11
@@ -619,6 +619,7 @@ struct Pager {
|
||||
u8 tempFile; /* zFilename is a temporary file */
|
||||
u8 readOnly; /* True for a read-only database */
|
||||
u8 memDb; /* True to inhibit all file I/O */
|
||||
u8 ckptFullSync; /* True to pass SYNC_FULL to WalCheckpoint() */
|
||||
|
||||
/**************************************************************************
|
||||
** The following block contains those class members that change during
|
||||
@@ -3082,6 +3083,19 @@ static int pagerOpenWalIfPresent(Pager *pPager){
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the value of the flags parameter that should be passed to
|
||||
** sqlite3OsSync() when checkpointing a WAL file.
|
||||
*/
|
||||
static int walCkptSyncFlags(Pager *pPager){
|
||||
int flags = 0;
|
||||
if( pPager->noSync==0 ){
|
||||
flags = pPager->sync_flags | (pPager->ckptFullSync?SQLITE_SYNC_FULL:0);
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -3262,10 +3276,16 @@ void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){
|
||||
** and FULL=3.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
void sqlite3PagerSetSafetyLevel(Pager *pPager, int level, int bFullFsync){
|
||||
void sqlite3PagerSetSafetyLevel(Pager *pPager, int level, int fullFsync){
|
||||
assert( 0==(fullFsync & ~(SQLITE_FullFSync|SQLITE_CkptFullFSync)) );
|
||||
pPager->noSync = (level==1 || pPager->tempFile) ?1:0;
|
||||
pPager->fullSync = (level==3 && !pPager->tempFile) ?1:0;
|
||||
pPager->sync_flags = (bFullFsync?SQLITE_SYNC_FULL:SQLITE_SYNC_NORMAL);
|
||||
if( fullFsync & SQLITE_FullFSync ){
|
||||
pPager->sync_flags = SQLITE_SYNC_FULL;
|
||||
}else{
|
||||
pPager->sync_flags = SQLITE_SYNC_NORMAL;
|
||||
}
|
||||
pPager->ckptFullSync = (fullFsync & SQLITE_CkptFullFSync)!=0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3651,8 +3671,7 @@ int sqlite3PagerClose(Pager *pPager){
|
||||
/* pPager->errCode = 0; */
|
||||
pPager->exclusiveMode = 0;
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
sqlite3WalClose(pPager->pWal,
|
||||
(pPager->noSync ? 0 : pPager->sync_flags),
|
||||
sqlite3WalClose(pPager->pWal, walCkptSyncFlags(pPager),
|
||||
pPager->pageSize, pTmp
|
||||
);
|
||||
pPager->pWal = 0;
|
||||
@@ -6521,10 +6540,8 @@ int sqlite3PagerCheckpoint(Pager *pPager){
|
||||
int rc = SQLITE_OK;
|
||||
if( pPager->pWal ){
|
||||
u8 *zBuf = (u8 *)pPager->pTmpSpace;
|
||||
rc = sqlite3WalCheckpoint(pPager->pWal,
|
||||
(pPager->noSync ? 0 : pPager->sync_flags),
|
||||
pPager->pageSize, zBuf
|
||||
);
|
||||
int flags = walCkptSyncFlags(pPager);
|
||||
rc = sqlite3WalCheckpoint(pPager->pWal, flags, pPager->pageSize, zBuf);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -6629,9 +6646,8 @@ int sqlite3PagerCloseWal(Pager *pPager){
|
||||
if( rc==SQLITE_OK && pPager->pWal ){
|
||||
rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3WalClose(pPager->pWal,
|
||||
(pPager->noSync ? 0 : pPager->sync_flags),
|
||||
pPager->pageSize, (u8*)pPager->pTmpSpace
|
||||
rc = sqlite3WalClose(pPager->pWal, walCkptSyncFlags(pPager),
|
||||
pPager->pageSize, (u8*)pPager->pTmpSpace
|
||||
);
|
||||
pPager->pWal = 0;
|
||||
}else{
|
||||
|
||||
+28
-21
@@ -142,12 +142,12 @@ static int changeTempStorage(Parse *pParse, const char *zStorageType){
|
||||
/*
|
||||
** Generate code to return a single integer value.
|
||||
*/
|
||||
static void returnSingleInt(Parse *pParse, const char *zLabel, i64 value){
|
||||
static void returnSingleInt(Parse *pParse, const char *zLabel, i64 *pValue){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
int mem = ++pParse->nMem;
|
||||
i64 *pI64 = sqlite3DbMallocRaw(pParse->db, sizeof(value));
|
||||
i64 *pI64 = sqlite3DbMallocRaw(pParse->db, sizeof(*pValue));
|
||||
if( pI64 ){
|
||||
memcpy(pI64, &value, sizeof(value));
|
||||
memcpy(pI64, pValue, sizeof(*pValue));
|
||||
}
|
||||
sqlite3VdbeAddOp4(v, OP_Int64, 0, mem, 0, (char*)pI64, P4_INT64);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
@@ -172,6 +172,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
|
||||
{ "empty_result_callbacks", SQLITE_NullCallback },
|
||||
{ "legacy_file_format", SQLITE_LegacyFileFmt },
|
||||
{ "fullfsync", SQLITE_FullFSync },
|
||||
{ "checkpoint_fullfsync", SQLITE_CkptFullFSync },
|
||||
{ "reverse_unordered_selects", SQLITE_ReverseOrder },
|
||||
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
||||
{ "automatic_index", SQLITE_AutoIndex },
|
||||
@@ -209,7 +210,8 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
|
||||
assert( v!=0 ); /* Already allocated by sqlite3Pragma() */
|
||||
if( ALWAYS(v) ){
|
||||
if( zRight==0 ){
|
||||
returnSingleInt(pParse, p->zName, (db->flags & p->mask)!=0 );
|
||||
i64 value = ((db->flags & p->mask)!=0 ? 1 : 0);
|
||||
returnSingleInt(pParse, p->zName, &value);
|
||||
}else{
|
||||
int mask = p->mask; /* Mask of bits to set or clear. */
|
||||
if( db->autoCommit==0 ){
|
||||
@@ -406,8 +408,8 @@ void sqlite3Pragma(
|
||||
Btree *pBt = pDb->pBt;
|
||||
assert( pBt!=0 );
|
||||
if( !zRight ){
|
||||
int size = ALWAYS(pBt) ? sqlite3BtreeGetPageSize(pBt) : 0;
|
||||
returnSingleInt(pParse, "page_size", size);
|
||||
i64 size = ALWAYS(pBt) ? sqlite3BtreeGetPageSize(pBt) : 0;
|
||||
returnSingleInt(pParse, "page_size", &size);
|
||||
}else{
|
||||
/* Malloc may fail when setting the page-size, as there is an internal
|
||||
** buffer that the pager module resizes using sqlite3_realloc().
|
||||
@@ -430,15 +432,15 @@ void sqlite3Pragma(
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft,"max_page_count")==0 ){
|
||||
Btree *pBt = pDb->pBt;
|
||||
int newMax = 0;
|
||||
i64 newMax = 0;
|
||||
assert( pBt!=0 );
|
||||
if( zRight ){
|
||||
newMax = atoi(zRight);
|
||||
}
|
||||
if( ALWAYS(pBt) ){
|
||||
newMax = sqlite3BtreeMaxPageCount(pBt, newMax);
|
||||
newMax = sqlite3BtreeMaxPageCount(pBt, (int)newMax);
|
||||
}
|
||||
returnSingleInt(pParse, "max_page_count", newMax);
|
||||
returnSingleInt(pParse, "max_page_count", &newMax);
|
||||
}else
|
||||
|
||||
/*
|
||||
@@ -451,7 +453,7 @@ void sqlite3Pragma(
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft,"secure_delete")==0 ){
|
||||
Btree *pBt = pDb->pBt;
|
||||
int b = -1;
|
||||
sqlite3_int64 b = -1;
|
||||
assert( pBt!=0 );
|
||||
if( zRight ){
|
||||
b = getBoolean(zRight);
|
||||
@@ -463,7 +465,7 @@ void sqlite3Pragma(
|
||||
}
|
||||
}
|
||||
b = sqlite3BtreeSecureDelete(pBt, b);
|
||||
returnSingleInt(pParse, "secure_delete", b);
|
||||
returnSingleInt(pParse, "secure_delete", &b);
|
||||
}else
|
||||
|
||||
/*
|
||||
@@ -591,7 +593,7 @@ void sqlite3Pragma(
|
||||
if( iLimit<-1 ) iLimit = -1;
|
||||
}
|
||||
iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
|
||||
returnSingleInt(pParse, "journal_size_limit", iLimit);
|
||||
returnSingleInt(pParse, "journal_size_limit", &iLimit);
|
||||
}else
|
||||
|
||||
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
|
||||
@@ -611,13 +613,13 @@ void sqlite3Pragma(
|
||||
goto pragma_out;
|
||||
}
|
||||
if( !zRight ){
|
||||
int auto_vacuum;
|
||||
i64 auto_vacuum;
|
||||
if( ALWAYS(pBt) ){
|
||||
auto_vacuum = sqlite3BtreeGetAutoVacuum(pBt);
|
||||
}else{
|
||||
auto_vacuum = SQLITE_DEFAULT_AUTOVACUUM;
|
||||
}
|
||||
returnSingleInt(pParse, "auto_vacuum", auto_vacuum);
|
||||
returnSingleInt(pParse, "auto_vacuum", &auto_vacuum);
|
||||
}else{
|
||||
int eAuto = getAutoVacuum(zRight);
|
||||
assert( eAuto>=0 && eAuto<=2 );
|
||||
@@ -699,7 +701,8 @@ void sqlite3Pragma(
|
||||
if( sqlite3StrICmp(zLeft,"cache_size")==0 ){
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
if( !zRight ){
|
||||
returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
|
||||
i64 cacheSize = pDb->pSchema->cache_size;
|
||||
returnSingleInt(pParse, "cache_size", &cacheSize);
|
||||
}else{
|
||||
int size = atoi(zRight);
|
||||
if( size<0 ) size = -size;
|
||||
@@ -721,7 +724,8 @@ void sqlite3Pragma(
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft, "temp_store")==0 ){
|
||||
if( !zRight ){
|
||||
returnSingleInt(pParse, "temp_store", db->temp_store);
|
||||
i64 tempStore = db->temp_store;
|
||||
returnSingleInt(pParse, "temp_store", &tempStore);
|
||||
}else{
|
||||
changeTempStorage(pParse, zRight);
|
||||
}
|
||||
@@ -835,7 +839,8 @@ void sqlite3Pragma(
|
||||
if( sqlite3StrICmp(zLeft,"synchronous")==0 ){
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
if( !zRight ){
|
||||
returnSingleInt(pParse, "synchronous", pDb->safety_level-1);
|
||||
i64 safetyLevel = pDb->safety_level-1;
|
||||
returnSingleInt(pParse, "synchronous", &safetyLevel);
|
||||
}else{
|
||||
if( !db->autoCommit ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
@@ -1411,13 +1416,15 @@ void sqlite3Pragma(
|
||||
** of N.
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft, "wal_autocheckpoint")==0 ){
|
||||
i64 walArg = 0;
|
||||
if( zRight ){
|
||||
int nAuto = atoi(zRight);
|
||||
sqlite3_wal_autocheckpoint(db, nAuto);
|
||||
}
|
||||
returnSingleInt(pParse, "wal_autocheckpoint",
|
||||
db->xWalCallback==sqlite3WalDefaultHook ?
|
||||
SQLITE_PTR_TO_INT(db->pWalArg) : 0);
|
||||
if( db->xWalCallback==sqlite3WalDefaultHook ){
|
||||
walArg = SQLITE_PTR_TO_INT(db->pWalArg);
|
||||
}
|
||||
returnSingleInt(pParse, "wal_autocheckpoint", &walArg);
|
||||
}else
|
||||
#endif
|
||||
|
||||
@@ -1503,7 +1510,7 @@ void sqlite3Pragma(
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
if( db->autoCommit ){
|
||||
sqlite3BtreeSetSafetyLevel(pDb->pBt, pDb->safety_level,
|
||||
(db->flags&SQLITE_FullFSync)!=0);
|
||||
db->flags&(SQLITE_FullFSync|SQLITE_CkptFullFSync));
|
||||
}
|
||||
#endif
|
||||
pragma_out:
|
||||
|
||||
+12
-1
@@ -14,6 +14,9 @@
|
||||
** from disk.
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
# include "sqlrr.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Fill the InitData structure with an error message that indicates
|
||||
@@ -761,6 +764,9 @@ int sqlite3_prepare(
|
||||
){
|
||||
int rc;
|
||||
rc = sqlite3LockAndPrepare(db,zSql,nBytes,0,0,ppStmt,pzTail);
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecPrepare(db, zSql, nBytes, 0, *ppStmt);
|
||||
#endif
|
||||
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
|
||||
return rc;
|
||||
}
|
||||
@@ -773,6 +779,9 @@ int sqlite3_prepare_v2(
|
||||
){
|
||||
int rc;
|
||||
rc = sqlite3LockAndPrepare(db,zSql,nBytes,1,0,ppStmt,pzTail);
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecPrepare(db, zSql, nBytes, 1, *ppStmt);
|
||||
#endif
|
||||
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
|
||||
return rc;
|
||||
}
|
||||
@@ -808,7 +817,9 @@ static int sqlite3Prepare16(
|
||||
if( zSql8 ){
|
||||
rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, 0, ppStmt, &zTail8);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecPrepare(db, zSql8, -1, 1, *ppStmt);
|
||||
#endif
|
||||
if( zTail8 && pzTail ){
|
||||
/* If sqlite3_prepare returns a tail pointer, we calculate the
|
||||
** equivalent pointer into the UTF-16 string by counting the unicode
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* sqlite3_private.h
|
||||
*/
|
||||
|
||||
#ifndef _SQLITE3_PRIVATE_H
|
||||
#define _SQLITE3_PRIVATE_H
|
||||
|
||||
/*
|
||||
** Pass the SQLITE_TRUNCATE_DATABASE operation code to sqlite3_file_control()
|
||||
** to truncate a database and its associated journal file to zero length.
|
||||
*/
|
||||
#define SQLITE_TRUNCATE_DATABASE 101
|
||||
|
||||
/*
|
||||
** Pass the SQLITE_REPLACE_DATABASE operation code to sqlite3_file_control()
|
||||
** and a sqlite3 pointer to another open database file to safely copy the
|
||||
** contents of that database file into the receiving database.
|
||||
*/
|
||||
#define SQLITE_REPLACE_DATABASE 102
|
||||
|
||||
#endif
|
||||
@@ -914,6 +914,7 @@ struct sqlite3 {
|
||||
#define SQLITE_ForeignKeys 0x04000000 /* Enforce foreign key constraints */
|
||||
#define SQLITE_AutoIndex 0x08000000 /* Enable automatic indexes */
|
||||
#define SQLITE_PreferBuiltin 0x10000000 /* Preference to built-in funcs */
|
||||
#define SQLITE_CkptFullFSync 0x20000000 /* Use full fsync on checkpoint */
|
||||
|
||||
/*
|
||||
** Bits of the sqlite3.flags field that are used by the
|
||||
|
||||
+112
@@ -3138,6 +3138,24 @@ static int test_clear_bindings(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_clear_bindings STMT
|
||||
**
|
||||
*/
|
||||
static int test_clear_bindings_null(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
if( objc!=1 ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
/* test for handling NULL <rdar://problem/6646331> */
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_clear_bindings(0)));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_sleep MILLISECONDS
|
||||
*/
|
||||
@@ -4721,6 +4739,97 @@ static int file_control_lockproxy_test(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/errno.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
** tclcmd: path_is_local PWD
|
||||
*/
|
||||
static int path_is_local(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3 *db;
|
||||
const char *zPath;
|
||||
int nPath;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
||||
Tcl_GetStringFromObj(objv[0], 0), " PATH", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zPath = Tcl_GetStringFromObj(objv[1], &nPath);
|
||||
|
||||
#ifdef __APPLE__
|
||||
{
|
||||
struct statfs fsInfo;
|
||||
if( statfs(zPath, &fsInfo) == -1 ){
|
||||
int err = errno;
|
||||
Tcl_AppendResult(interp, "Error calling statfs on path",
|
||||
Tcl_NewIntObj(err), 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( fsInfo.f_flags&MNT_LOCAL ){
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(1));
|
||||
} else {
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
|
||||
}
|
||||
}
|
||||
#else
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(1));
|
||||
#endif
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: path_is_dos PWD
|
||||
*/
|
||||
static int path_is_dos(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3 *db;
|
||||
const char *zPath;
|
||||
int nPath;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
||||
Tcl_GetStringFromObj(objv[0], 0), " PATH", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zPath = Tcl_GetStringFromObj(objv[1], &nPath);
|
||||
|
||||
#ifdef __APPLE__
|
||||
{
|
||||
struct statfs fsInfo;
|
||||
if( statfs(zPath, &fsInfo) == -1 ){
|
||||
int err = errno;
|
||||
Tcl_AppendResult(interp, "Error calling statfs on path",
|
||||
Tcl_NewIntObj(err), 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) {
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(1));
|
||||
} else if (0 == strncmp("exfat", fsInfo.f_fstypename, 5)) {
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(1));
|
||||
} else {
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
|
||||
}
|
||||
}
|
||||
#else
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
|
||||
#endif
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_vfs_list
|
||||
@@ -5101,6 +5210,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_bind_parameter_name", test_bind_parameter_name, 0},
|
||||
{ "sqlite3_bind_parameter_index", test_bind_parameter_index, 0},
|
||||
{ "sqlite3_clear_bindings", test_clear_bindings, 0},
|
||||
{ "sqlite3_clear_bindings_null", test_clear_bindings_null, 0},
|
||||
{ "sqlite3_sleep", test_sleep, 0},
|
||||
{ "sqlite3_errcode", test_errcode ,0 },
|
||||
{ "sqlite3_extended_errcode", test_ex_errcode ,0 },
|
||||
@@ -5187,6 +5297,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "file_control_lockproxy_test", file_control_lockproxy_test, 0 },
|
||||
{ "file_control_chunksize_test", file_control_chunksize_test, 0 },
|
||||
{ "sqlite3_vfs_list", vfs_list, 0 },
|
||||
{ "path_is_local", path_is_local, 0 },
|
||||
{ "path_is_dos", path_is_dos, 0 },
|
||||
|
||||
/* Functions from os.h */
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "tcl.h"
|
||||
#include <sqlite3.h>
|
||||
#include "sqlite3.h"
|
||||
#include <assert.h>
|
||||
|
||||
/* These functions are implemented in test1.c. */
|
||||
|
||||
+17
-1
@@ -528,7 +528,23 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "yytrackmaxstackdepth", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
# if defined(__ppc__)
|
||||
Tcl_SetVar2(interp, "os_options", "arch", "ppc", TCL_GLOBAL_ONLY);
|
||||
# elif defined(__i386__)
|
||||
Tcl_SetVar2(interp, "os_options", "arch", "i386", TCL_GLOBAL_ONLY);
|
||||
# elif defined(__x86_64__)
|
||||
Tcl_SetVar2(interp, "os_options", "arch", "x86_64", TCL_GLOBAL_ONLY);
|
||||
# elif defined(__arm__)
|
||||
Tcl_SetVar2(interp, "os_options", "arch", "arm", TCL_GLOBAL_ONLY);
|
||||
# else
|
||||
# error Unrecognized architecture for exec_options
|
||||
# endif
|
||||
#else
|
||||
Tcl_SetVar2(interp, "os_options", "arch", "unknown", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#define LINKVAR(x) { \
|
||||
static const int cv_ ## x = SQLITE_ ## x; \
|
||||
Tcl_LinkVar(interp, "SQLITE_" #x, (char *)&(cv_ ## x), \
|
||||
|
||||
+1
-1
@@ -580,7 +580,7 @@ int sqlite3VdbeExec(
|
||||
** sqlite3_column_text16() failed. */
|
||||
goto no_mem;
|
||||
}
|
||||
assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY );
|
||||
assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY || ((p->rc&0xFF) == SQLITE_LOCKED));
|
||||
p->rc = SQLITE_OK;
|
||||
assert( p->explain==0 );
|
||||
p->pResultSet = 0;
|
||||
|
||||
+46
-2
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
# include "sqlrr.h"
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
/*
|
||||
@@ -37,7 +40,8 @@ int sqlite3_expired(sqlite3_stmt *pStmt){
|
||||
** invalid). Return false if it is ok.
|
||||
*/
|
||||
static int vdbeSafety(Vdbe *p){
|
||||
if( p->db==0 ){
|
||||
sqlite3* db = p->db;
|
||||
if((db==0) || (db->magic != SQLITE_MAGIC_OPEN) || ((p->magic != VDBE_MAGIC_RUN) && (p->magic != VDBE_MAGIC_HALT))){
|
||||
sqlite3_log(SQLITE_MISUSE, "API called with finalized prepared statement");
|
||||
return 1;
|
||||
}else{
|
||||
@@ -68,6 +72,9 @@ int sqlite3_finalize(sqlite3_stmt *pStmt){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
Vdbe *v = (Vdbe*)pStmt;
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecFinalize(pStmt);
|
||||
#endif
|
||||
sqlite3 *db = v->db;
|
||||
#if SQLITE_THREADSAFE
|
||||
sqlite3_mutex *mutex;
|
||||
@@ -98,6 +105,9 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
Vdbe *v = (Vdbe*)pStmt;
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecReset(pStmt);
|
||||
#endif
|
||||
sqlite3_mutex_enter(v->db->mutex);
|
||||
rc = sqlite3VdbeReset(v);
|
||||
sqlite3VdbeMakeReady(v, -1, 0, 0, 0, 0, 0);
|
||||
@@ -116,7 +126,14 @@ int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
|
||||
int rc = SQLITE_OK;
|
||||
Vdbe *p = (Vdbe*)pStmt;
|
||||
#if SQLITE_THREADSAFE
|
||||
sqlite3_mutex *mutex = ((Vdbe*)pStmt)->db->mutex;
|
||||
sqlite3_mutex *mutex=NULL;
|
||||
#endif
|
||||
if( NULL==pStmt ){ return SQLITE_OK; } /* <rdar://problem/6646331> */
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecClearBindings(pStmt);
|
||||
#endif
|
||||
#if SQLITE_THREADSAFE
|
||||
mutex = ((Vdbe*)pStmt)->db->mutex;
|
||||
#endif
|
||||
sqlite3_mutex_enter(mutex);
|
||||
for(i=0; i<p->nVar; i++){
|
||||
@@ -1024,11 +1041,17 @@ int sqlite3_bind_blob(
|
||||
int nData,
|
||||
void (*xDel)(void*)
|
||||
){
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecBindBlob(pStmt, i, zData, nData);
|
||||
#endif
|
||||
return bindText(pStmt, i, zData, nData, xDel, 0);
|
||||
}
|
||||
int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
|
||||
int rc;
|
||||
Vdbe *p = (Vdbe *)pStmt;
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecBindDouble(pStmt, i, rValue);
|
||||
#endif
|
||||
rc = vdbeUnbind(p, i);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue);
|
||||
@@ -1037,11 +1060,17 @@ int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
|
||||
return rc;
|
||||
}
|
||||
int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecBindInt64(p, i, (i64)iValue);
|
||||
#endif
|
||||
return sqlite3_bind_int64(p, i, (i64)iValue);
|
||||
}
|
||||
int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
|
||||
int rc;
|
||||
Vdbe *p = (Vdbe *)pStmt;
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecBindInt64(pStmt, i, iValue);
|
||||
#endif
|
||||
rc = vdbeUnbind(p, i);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue);
|
||||
@@ -1052,6 +1081,9 @@ int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
|
||||
int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
|
||||
int rc;
|
||||
Vdbe *p = (Vdbe*)pStmt;
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecBindNull(pStmt, i);
|
||||
#endif
|
||||
rc = vdbeUnbind(p, i);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_mutex_leave(p->db->mutex);
|
||||
@@ -1065,6 +1097,9 @@ int sqlite3_bind_text(
|
||||
int nData,
|
||||
void (*xDel)(void*)
|
||||
){
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecBindText(pStmt, i, zData, nData);
|
||||
#endif
|
||||
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
@@ -1075,6 +1110,9 @@ int sqlite3_bind_text16(
|
||||
int nData,
|
||||
void (*xDel)(void*)
|
||||
){
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecBindText(pStmt, i, zData, nData);
|
||||
#endif
|
||||
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
@@ -1098,6 +1136,9 @@ int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecBindText(pStmt, i, pValue->z, pValue->n);
|
||||
#endif
|
||||
rc = bindText(pStmt,i, pValue->z, pValue->n, SQLITE_TRANSIENT,
|
||||
pValue->enc);
|
||||
break;
|
||||
@@ -1112,6 +1153,9 @@ int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
|
||||
int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
|
||||
int rc;
|
||||
Vdbe *p = (Vdbe *)pStmt;
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
SRRecBindBlob(pStmt, i, NULL, n);
|
||||
#endif
|
||||
rc = vdbeUnbind(p, i);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
|
||||
|
||||
+18
-17
@@ -714,23 +714,24 @@ do_test attach-6.1 {
|
||||
}
|
||||
} {0 {}}
|
||||
if {$tcl_platform(platform)=="unix"} {
|
||||
do_test attach-6.2 {
|
||||
sqlite3 dbx cannot-read
|
||||
dbx eval {CREATE TABLE t1(a,b,c)}
|
||||
dbx close
|
||||
file attributes cannot-read -permission 0000
|
||||
if {[file writable cannot-read]} {
|
||||
puts "\n**** Tests do not work when run as root ****"
|
||||
file delete -force cannot-read
|
||||
exit 1
|
||||
}
|
||||
catchsql {
|
||||
ATTACH DATABASE 'cannot-read' AS noread;
|
||||
}
|
||||
} {1 {unable to open database: cannot-read}}
|
||||
do_test attach-6.2.2 {
|
||||
db errorcode
|
||||
} {14}
|
||||
sqlite3 dbx cannot-read
|
||||
dbx eval {CREATE TABLE t1(a,b,c)}
|
||||
dbx close
|
||||
file attributes cannot-read -permission 0000
|
||||
if {[file writable cannot-read]} {
|
||||
#puts "\n**** Tests do not work when run as root ****"
|
||||
file delete -force cannot-read
|
||||
#exit 1
|
||||
} else {
|
||||
do_test attach-6.2 {
|
||||
catchsql {
|
||||
ATTACH DATABASE 'cannot-read' AS noread;
|
||||
}
|
||||
} {1 {unable to open database: cannot-read}}
|
||||
do_test attach-6.2.2 {
|
||||
db errorcode
|
||||
} {14}
|
||||
}
|
||||
file delete -force cannot-read
|
||||
}
|
||||
|
||||
|
||||
@@ -656,6 +656,9 @@ do_test bind-13.4 {
|
||||
[sqlite3_column_type $VM 2]
|
||||
} {NULL NULL NULL}
|
||||
sqlite3_finalize $VM
|
||||
do_test bind-13.5 {
|
||||
sqlite3_clear_bindings_null
|
||||
} {0}
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# These tests attempt to reproduce bug #3463.
|
||||
|
||||
+1
-5
@@ -401,12 +401,8 @@ sqlite db test.db
|
||||
# if we're using proxy locks, we use 3 filedescriptors for a db
|
||||
# that is open but NOT writing changes, normally
|
||||
# sqlite uses 1 (proxy locking adds the conch and the local lock)
|
||||
set using_proxy 0
|
||||
foreach {name value} [array get env SQLITE_FORCE_PROXY_LOCKING] {
|
||||
set using_proxy $value
|
||||
}
|
||||
set extrafds 0
|
||||
if {$using_proxy!=0} {
|
||||
if {[forced_proxy_locking]} {
|
||||
set extrafds 2
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ set skipwaltests [expr {
|
||||
[permutation]=="journaltest" || [permutation]=="inmemory_journal"
|
||||
}]
|
||||
ifcapable !wal { set skipwaltests 1 }
|
||||
if {![wal_is_ok]} { set skipwaltests 1 }
|
||||
|
||||
if {!$skipwaltests} {
|
||||
db close
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ source $testdir/malloc_common.tcl
|
||||
# If a connection is required to create a journal file, it creates it with
|
||||
# the same file-system permissions as the database file itself. Test this.
|
||||
#
|
||||
if {$::tcl_platform(platform) == "unix"} {
|
||||
if {$::tcl_platform(platform) == "unix" && ![path_is_dos "."]} {
|
||||
|
||||
set umask [exec /bin/sh -c umask]
|
||||
faultsim_delete_and_reopen
|
||||
|
||||
+73
-69
@@ -106,87 +106,91 @@ if {[catch {sqlite3 db test.db -vfs unix-flock} msg]} {
|
||||
return
|
||||
}
|
||||
|
||||
do_test lock5-flock.1 {
|
||||
sqlite3 db test.db -vfs unix-flock
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b);
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
}
|
||||
} {}
|
||||
# Only run the flock tests on a local file system
|
||||
if { [path_is_local "."] } {
|
||||
|
||||
# Make sure we are not accidentally using the dotfile locking scheme.
|
||||
do_test lock5-flock.2 {
|
||||
file exists test.db.lock
|
||||
} {0}
|
||||
do_test lock5-flock.1 {
|
||||
sqlite3 db test.db -vfs unix-flock
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b);
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test lock5-flock.3 {
|
||||
catch { sqlite3 db2 test.db -vfs unix-flock }
|
||||
catchsql { SELECT * FROM t1 } db2
|
||||
} {1 {database is locked}}
|
||||
# Make sure we are not accidentally using the dotfile locking scheme.
|
||||
do_test lock5-flock.2 {
|
||||
file exists test.db.lock
|
||||
} {0}
|
||||
|
||||
do_test lock5-flock.4 {
|
||||
execsql COMMIT
|
||||
catchsql { SELECT * FROM t1 } db2
|
||||
} {0 {1 2}}
|
||||
do_test lock5-flock.3 {
|
||||
catch { sqlite3 db2 test.db -vfs unix-flock }
|
||||
catchsql { SELECT * FROM t1 } db2
|
||||
} {1 {database is locked}}
|
||||
|
||||
do_test lock5-flock.5 {
|
||||
execsql BEGIN
|
||||
catchsql { SELECT * FROM t1 } db2
|
||||
} {0 {1 2}}
|
||||
do_test lock5-flock.4 {
|
||||
execsql COMMIT
|
||||
catchsql { SELECT * FROM t1 } db2
|
||||
} {0 {1 2}}
|
||||
|
||||
do_test lock5-flock.6 {
|
||||
execsql {SELECT * FROM t1}
|
||||
catchsql { SELECT * FROM t1 } db2
|
||||
} {1 {database is locked}}
|
||||
do_test lock5-flock.5 {
|
||||
execsql BEGIN
|
||||
catchsql { SELECT * FROM t1 } db2
|
||||
} {0 {1 2}}
|
||||
|
||||
do_test lock5-flock.7 {
|
||||
db close
|
||||
catchsql { SELECT * FROM t1 } db2
|
||||
} {0 {1 2}}
|
||||
do_test lock5-flock.6 {
|
||||
execsql {SELECT * FROM t1}
|
||||
catchsql { SELECT * FROM t1 } db2
|
||||
} {1 {database is locked}}
|
||||
|
||||
do_test lock5-flock.8 {
|
||||
db2 close
|
||||
} {}
|
||||
do_test lock5-flock.7 {
|
||||
db close
|
||||
catchsql { SELECT * FROM t1 } db2
|
||||
} {0 {1 2}}
|
||||
|
||||
#####################################################################
|
||||
do_test lock5-flock.8 {
|
||||
db2 close
|
||||
} {}
|
||||
|
||||
do_test lock5-none.1 {
|
||||
sqlite3 db test.db -vfs unix-none
|
||||
sqlite3 db2 test.db -vfs unix-none
|
||||
execsql {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(3, 4);
|
||||
}
|
||||
} {}
|
||||
do_test lock5-none.2 {
|
||||
execsql { SELECT * FROM t1 }
|
||||
} {1 2 3 4}
|
||||
do_test lock5-flock.3 {
|
||||
execsql { SELECT * FROM t1 } db2
|
||||
} {1 2}
|
||||
do_test lock5-none.4 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
SELECT * FROM t1;
|
||||
} db2
|
||||
} {1 2}
|
||||
do_test lock5-none.5 {
|
||||
execsql COMMIT
|
||||
execsql {SELECT * FROM t1} db2
|
||||
} {1 2}
|
||||
#####################################################################
|
||||
|
||||
ifcapable memorymanage {
|
||||
do_test lock5-none.6 {
|
||||
sqlite3_release_memory 1000000
|
||||
execsql {SELECT * FROM t1} db2
|
||||
do_test lock5-none.1 {
|
||||
sqlite3 db test.db -vfs unix-none
|
||||
sqlite3 db2 test.db -vfs unix-none
|
||||
execsql {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(3, 4);
|
||||
}
|
||||
} {}
|
||||
do_test lock5-none.2 {
|
||||
execsql { SELECT * FROM t1 }
|
||||
} {1 2 3 4}
|
||||
}
|
||||
do_test lock5-flock.3 {
|
||||
execsql { SELECT * FROM t1 } db2
|
||||
} {1 2}
|
||||
do_test lock5-none.4 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
SELECT * FROM t1;
|
||||
} db2
|
||||
} {1 2}
|
||||
do_test lock5-none.5 {
|
||||
execsql COMMIT
|
||||
execsql {SELECT * FROM t1} db2
|
||||
} {1 2}
|
||||
|
||||
do_test lock5-flock.X {
|
||||
db close
|
||||
db2 close
|
||||
} {}
|
||||
ifcapable memorymanage {
|
||||
do_test lock5-none.6 {
|
||||
sqlite3_release_memory 1000000
|
||||
execsql {SELECT * FROM t1} db2
|
||||
} {1 2 3 4}
|
||||
}
|
||||
|
||||
do_test lock5-flock.X {
|
||||
db close
|
||||
db2 close
|
||||
} {}
|
||||
}
|
||||
|
||||
ifcapable lock_proxy_pragmas {
|
||||
set env(SQLITE_FORCE_PROXY_LOCKING) $::using_proxy
|
||||
|
||||
+5
-3
@@ -126,9 +126,10 @@ ifcapable lock_proxy_pragmas&&prefer_proxy_locking {
|
||||
set lockpath
|
||||
} {{:auto: (not held)}}
|
||||
|
||||
set lpp [exec mktemp -t fail]
|
||||
do_test lock6-1.4.1 {
|
||||
execsql "PRAGMA lock_proxy_file='$lpp'"
|
||||
catchsql {
|
||||
PRAGMA lock_proxy_file="notmine";
|
||||
select * from sqlite_master;
|
||||
} db
|
||||
} {1 {database is locked}}
|
||||
@@ -137,7 +138,7 @@ ifcapable lock_proxy_pragmas&&prefer_proxy_locking {
|
||||
execsql {
|
||||
PRAGMA lock_proxy_file;
|
||||
} db
|
||||
} {notmine}
|
||||
} $lpp
|
||||
|
||||
do_test lock6-1.5 {
|
||||
testfixture $::tf1 {
|
||||
@@ -150,9 +151,10 @@ ifcapable lock_proxy_pragmas&&prefer_proxy_locking {
|
||||
|
||||
catch {testfixture $::tf1 {db close}}
|
||||
|
||||
set lpp [exec mktemp -t ok]
|
||||
do_test lock6-1.6 {
|
||||
execsql "PRAGMA lock_proxy_file='$lpp'"
|
||||
execsql {
|
||||
PRAGMA lock_proxy_file="mine";
|
||||
select * from sqlite_master;
|
||||
} db
|
||||
} {}
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
# 2008 June 28
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is database proxy locks.
|
||||
#
|
||||
# $Id$
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# This file is only run if using the unix backend compiled with the
|
||||
# SQLITE_ENABLE_LOCKING_STYLE macro.
|
||||
db close
|
||||
if {[catch {sqlite3 db test.db -vfs unix-none} msg]} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
db close
|
||||
file delete -force test.db.lock
|
||||
|
||||
#####################################################################
|
||||
ifcapable lock_proxy_pragmas&&prefer_proxy_locking {
|
||||
set ::using_proxy 0
|
||||
foreach {name value} [array get env SQLITE_FORCE_PROXY_LOCKING] {
|
||||
set ::using_proxy $value
|
||||
}
|
||||
|
||||
# enable the proxy locking for these tests
|
||||
set env(SQLITE_FORCE_PROXY_LOCKING) "1"
|
||||
|
||||
# test conch file creation
|
||||
#
|
||||
|
||||
catch { file delete lock_proxy_test.db }
|
||||
catch { file delete .lock_proxy_test.db-conch }
|
||||
# test that proxy locking mode creates conch files
|
||||
do_test lock_proxy1.0 {
|
||||
sqlite3 db2 lock_proxy_test.db
|
||||
catchsql {
|
||||
create table x(y);
|
||||
} db2
|
||||
file exists .lock_proxy_test.db-conch
|
||||
} {1}
|
||||
catch { db2 close }
|
||||
|
||||
|
||||
# test proxy locking readonly file system handling
|
||||
#
|
||||
|
||||
if {[file exists /usr/bin/hdiutil]} {
|
||||
|
||||
puts "Creating readonly file system for proxy locking tests..."
|
||||
if {[file exists /Volumes/readonly]} {
|
||||
exec hdiutil detach /Volumes/readonly
|
||||
}
|
||||
if {[file exists readonly.dmg]} {
|
||||
file delete readonly.dmg
|
||||
}
|
||||
exec hdiutil create -megabytes 1 -fs HFS+ readonly.dmg -volname readonly
|
||||
exec hdiutil attach readonly.dmg
|
||||
|
||||
# create test1.db and a .test1.db-conch for host4
|
||||
set sqlite_hostid_num 4
|
||||
sqlite3 db2 /Volumes/readonly/test1.db
|
||||
execsql {
|
||||
create table x(y);
|
||||
} db2
|
||||
db2 close
|
||||
|
||||
# create test2.db and a .test2.db-conch for host5
|
||||
set sqlite_hostid_num 5
|
||||
sqlite3 db2 /Volumes/readonly/test2.db
|
||||
execsql {
|
||||
create table x(y);
|
||||
} db2
|
||||
db2 close
|
||||
|
||||
# create test3.db without a conch file
|
||||
set env(SQLITE_FORCE_PROXY_LOCKING) "0"
|
||||
sqlite3 db2 /Volumes/readonly/test3.db
|
||||
execsql {
|
||||
create table x(y);
|
||||
} db2
|
||||
db2 close
|
||||
exec hdiutil detach /Volumes/readonly
|
||||
exec hdiutil attach -readonly readonly.dmg
|
||||
|
||||
# test that an unwritable, host-mismatched conch file prevents
|
||||
# read only proxy-locking mode database access
|
||||
set env(SQLITE_FORCE_PROXY_LOCKING) "1"
|
||||
do_test lock_proxy2.0 {
|
||||
sqlite3 db2 /Volumes/readonly/test1.db
|
||||
catchsql {
|
||||
select * from sqlite_master;
|
||||
} db2
|
||||
} {1 {database is locked}}
|
||||
catch { db2 close }
|
||||
|
||||
# test that an unwritable, host-matching conch file allows
|
||||
# read only proxy-locking mode database access
|
||||
do_test lock_proxy2.1 {
|
||||
sqlite3 db2 /Volumes/readonly/test2.db
|
||||
catchsql {
|
||||
select * from sqlite_master;
|
||||
} db2
|
||||
} {0 {table x x 2 {CREATE TABLE x(y)}}}
|
||||
catch { db2 close }
|
||||
|
||||
# test that an unwritable, nonexistant conch file allows
|
||||
# read only proxy-locking mode database access
|
||||
do_test lock_proxy2.2 {
|
||||
sqlite3 db2 /Volumes/readonly/test3.db
|
||||
catchsql {
|
||||
select * from sqlite_master;
|
||||
} db2
|
||||
} {0 {table x x 2 {CREATE TABLE x(y)}}}
|
||||
catch { db2 close }
|
||||
|
||||
exec hdiutil detach /Volumes/readonly
|
||||
file delete readonly.dmg
|
||||
}
|
||||
set env(SQLITE_FORCE_PROXY_LOCKING) "0"
|
||||
set sqlite_hostid_num 0
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
|
||||
file delete -force test.db
|
||||
|
||||
ifcapable lock_proxy_pragmas&&prefer_proxy_locking {
|
||||
set env(SQLITE_FORCE_PROXY_LOCKING) $::using_proxy
|
||||
}
|
||||
|
||||
finish_test
|
||||
+3
-3
@@ -314,7 +314,7 @@ if {[permutation] == ""} {
|
||||
#
|
||||
do_test main-3.1 {
|
||||
catch {db close}
|
||||
foreach f [glob -nocomplain testdb/*] {file delete -force $f}
|
||||
catch {foreach f [glob -nocomplain testdb/*] {file delete -force $f}}
|
||||
file delete -force testdb
|
||||
sqlite3 db testdb
|
||||
set v [catch {execsql {SELECT * from T1 where x!!5}} msg]
|
||||
@@ -322,7 +322,7 @@ do_test main-3.1 {
|
||||
} {1 {unrecognized token: "!!"}}
|
||||
do_test main-3.2 {
|
||||
catch {db close}
|
||||
foreach f [glob -nocomplain testdb/*] {file delete -force $f}
|
||||
catch {foreach f [glob -nocomplain testdb/*] {file delete -force $f}}
|
||||
file delete -force testdb
|
||||
sqlite3 db testdb
|
||||
set v [catch {execsql {SELECT * from T1 where ^x}} msg]
|
||||
@@ -442,7 +442,7 @@ do_test main-3.2.30 {
|
||||
|
||||
do_test main-3.3 {
|
||||
catch {db close}
|
||||
foreach f [glob -nocomplain testdb/*] {file delete -force $f}
|
||||
catch {foreach f [glob -nocomplain testdb/*] {file delete -force $f}}
|
||||
file delete -force testdb
|
||||
sqlite3 db testdb
|
||||
execsql {
|
||||
|
||||
@@ -412,7 +412,7 @@ proc do_malloc_test {tn args} {
|
||||
set zRepeat "transient"
|
||||
if {$::iRepeat} {set zRepeat "persistent"}
|
||||
restore_prng_state
|
||||
foreach file [glob -nocomplain test.db-mj*] {file delete -force $file}
|
||||
catch {foreach file [glob -nocomplain test.db-mj*] {file delete -force $file}}
|
||||
|
||||
do_test ${tn}.${zRepeat}.${::n} {
|
||||
|
||||
|
||||
+1
-5
@@ -22,12 +22,8 @@ set N 300
|
||||
# if we're using proxy locks, we use 5 filedescriptors for a db
|
||||
# that is open and in the middle of writing changes, normally
|
||||
# sqlite uses 3 (proxy locking adds the conch and the local lock)
|
||||
set using_proxy 0
|
||||
foreach {name value} [array get env SQLITE_FORCE_PROXY_LOCKING] {
|
||||
set using_proxy value
|
||||
}
|
||||
set num_fd_per_openwrite_db 3
|
||||
if {$using_proxy>0} {
|
||||
if {[forced_proxy_locking]} {
|
||||
set num_fd_per_openwrite_db 5
|
||||
}
|
||||
|
||||
|
||||
+21
-18
@@ -413,24 +413,27 @@ do_test memdb-8.2 {
|
||||
|
||||
# Test that auto-vacuum works with in-memory databases.
|
||||
#
|
||||
ifcapable autovacuum {
|
||||
do_test memdb-9.1 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
db cache size 0
|
||||
execsql {
|
||||
PRAGMA auto_vacuum = full;
|
||||
CREATE TABLE t1(a);
|
||||
INSERT INTO t1 VALUES(randstr(1000,1000));
|
||||
INSERT INTO t1 VALUES(randstr(1000,1000));
|
||||
INSERT INTO t1 VALUES(randstr(1000,1000));
|
||||
}
|
||||
set memused [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
|
||||
set pgovfl [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 1]
|
||||
execsql { DELETE FROM t1 }
|
||||
set memused2 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
|
||||
expr {($memused2 + 2048 < $memused) || $pgovfl==0}
|
||||
} {1}
|
||||
set msize [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0]
|
||||
if {[lindex $msize 2]!=0} {
|
||||
ifcapable autovacuum {
|
||||
do_test memdb-9.1 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
db cache size 0
|
||||
execsql {
|
||||
PRAGMA auto_vacuum = full;
|
||||
CREATE TABLE t1(a);
|
||||
INSERT INTO t1 VALUES(randstr(1000,1000));
|
||||
INSERT INTO t1 VALUES(randstr(1000,1000));
|
||||
INSERT INTO t1 VALUES(randstr(1000,1000));
|
||||
}
|
||||
set memused [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
|
||||
set pgovfl [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 1]
|
||||
execsql { DELETE FROM t1 }
|
||||
set memused2 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
|
||||
expr {($memused2 + 2048 < $memused) || $pgovfl==0}
|
||||
} {1}
|
||||
}
|
||||
}
|
||||
|
||||
} ;# ifcapable memorydb
|
||||
|
||||
+36
-28
@@ -191,17 +191,20 @@ build_test_db memsubsys1-5 {PRAGMA page_size=4096}
|
||||
do_test memsubsys1-5.3 {
|
||||
set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
|
||||
} 23
|
||||
do_test memsubsys1-5.4 {
|
||||
set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2]
|
||||
expr {$maxreq>4096}
|
||||
} 1
|
||||
do_test memsubsys1-5.5 {
|
||||
set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
|
||||
} 0
|
||||
do_test memsubsys1-5.6 {
|
||||
set s_ovfl [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0] 2]
|
||||
expr {$s_ovfl>6000}
|
||||
} 1
|
||||
set msize [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0]
|
||||
if {[lindex $msize 2]!=0} {
|
||||
do_test memsubsys1-5.4 {
|
||||
set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2]
|
||||
expr {$maxreq>4096}
|
||||
} 1
|
||||
do_test memsubsys1-5.5 {
|
||||
set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
|
||||
} 0
|
||||
do_test memsubsys1-5.6 {
|
||||
set s_ovfl [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0] 2]
|
||||
expr {$s_ovfl>6000}
|
||||
} 1
|
||||
}
|
||||
|
||||
# Test 6: Activate both PAGECACHE and SCRATCH with a 4k page size.
|
||||
# Make it so that SCRATCH is large enough
|
||||
@@ -217,10 +220,13 @@ build_test_db memsubsys1-6 {PRAGMA page_size=4096}
|
||||
do_test memsubsys1-6.3 {
|
||||
set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
|
||||
} 23
|
||||
do_test memsubsys1-6.4 {
|
||||
set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2]
|
||||
expr {$maxreq>4096 && $maxreq<=(4096+$xtra_size)}
|
||||
} 1
|
||||
set msize [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0]
|
||||
if {[lindex $msize 2]!=0} {
|
||||
do_test memsubsys1-6.4 {
|
||||
set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2]
|
||||
expr {$maxreq>4096 && $maxreq<=(4096+$xtra_size)}
|
||||
} 1
|
||||
}
|
||||
do_test memsubsys1-6.5 {
|
||||
set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
|
||||
} 1
|
||||
@@ -277,19 +283,21 @@ do_test memsubsys1-8.1 {
|
||||
do_test memsubsys1-8.2 {
|
||||
set s_ovfl [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0] 2]
|
||||
} 0
|
||||
do_test memsubsys1-8.3 {
|
||||
sqlite3 db :memory:
|
||||
db eval {
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES(zeroblob(400));
|
||||
INSERT INTO t1 VALUES(zeroblob(400));
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
}
|
||||
expr {[lindex [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0] 2]>0}
|
||||
} 1
|
||||
db close
|
||||
if {[lindex $msize 2]!=0} {
|
||||
do_test memsubsys1-8.3 {
|
||||
sqlite3 db :memory:
|
||||
db eval {
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES(zeroblob(400));
|
||||
INSERT INTO t1 VALUES(zeroblob(400));
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
}
|
||||
expr {[lindex [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0] 2]>0}
|
||||
} 1
|
||||
db close
|
||||
}
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_memstatus 0
|
||||
sqlite3_initialize
|
||||
|
||||
+130
-110
@@ -15,7 +15,7 @@ source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
source $testdir/wal_common.tcl
|
||||
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
#
|
||||
@@ -540,7 +540,11 @@ foreach {tn1 tcl} {
|
||||
# a valid page record (if the file page-size is 512 bytes). So as to
|
||||
# make sure SQLite doesn't get confused by this.
|
||||
#
|
||||
set nPadding [expr 511 - $::mj_filename_length]
|
||||
set target_length 511
|
||||
if { [forced_proxy_locking] } {
|
||||
set target_length 255
|
||||
}
|
||||
set nPadding [expr $target_length - $::mj_filename_length]
|
||||
if {$tcl_platform(platform)=="windows"} {
|
||||
# TBD need to figure out how to do this correctly for Windows!!!
|
||||
set nPadding [expr 255 - $::mj_filename_length]
|
||||
@@ -561,6 +565,7 @@ foreach {tn1 tcl} {
|
||||
|
||||
set padding [string repeat x [expr $nPadding %32]]
|
||||
set prefix "test.db${padding}"
|
||||
set prefix
|
||||
}
|
||||
} {
|
||||
eval $tcl
|
||||
@@ -1081,46 +1086,49 @@ do_execsql_test pager1-6.12 { PRAGMA max_page_count } {11}
|
||||
# $ws: The expected size of the WAL file, in bytes, after executing
|
||||
# the SQL script. Or -1 if the WAL is not expected to exist.
|
||||
#
|
||||
ifcapable wal {
|
||||
faultsim_delete_and_reopen
|
||||
foreach {tn sql res js ws} [subst {
|
||||
|
||||
1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
PRAGMA auto_vacuum=OFF;
|
||||
PRAGMA synchronous=NORMAL;
|
||||
PRAGMA page_size=1024;
|
||||
PRAGMA locking_mode=EXCLUSIVE;
|
||||
PRAGMA journal_mode=TRUNCATE;
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
} {exclusive truncate} 0 -1
|
||||
|
||||
2 {
|
||||
BEGIN IMMEDIATE;
|
||||
SELECT * FROM t1;
|
||||
COMMIT;
|
||||
} {1 2} 0 -1
|
||||
|
||||
3 {
|
||||
BEGIN;
|
||||
SELECT * FROM t1;
|
||||
COMMIT;
|
||||
} {1 2} 0 -1
|
||||
|
||||
4 { PRAGMA journal_mode = WAL } wal -1 -1
|
||||
5 { INSERT INTO t1 VALUES(3, 4) } {} -1 [wal_file_size 1 1024]
|
||||
6 { PRAGMA locking_mode = NORMAL } normal -1 [wal_file_size 1 1024]
|
||||
7 { INSERT INTO t1 VALUES(5, 6); } {} -1 [wal_file_size 2 1024]
|
||||
|
||||
8 { PRAGMA journal_mode = TRUNCATE } truncate 0 -1
|
||||
9 { INSERT INTO t1 VALUES(7, 8) } {} 0 -1
|
||||
10 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8} 0 -1
|
||||
|
||||
}] {
|
||||
do_execsql_test pager1-7.1.$tn.1 $sql $res
|
||||
catch { set J -1 ; set J [file size test.db-journal] }
|
||||
catch { set W -1 ; set W [file size test.db-wal] }
|
||||
do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws]
|
||||
set do_wal_tests [wal_is_ok]
|
||||
if { $do_wal_tests } {
|
||||
ifcapable wal {
|
||||
faultsim_delete_and_reopen
|
||||
foreach {tn sql res js ws} [subst {
|
||||
|
||||
1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
PRAGMA auto_vacuum=OFF;
|
||||
PRAGMA synchronous=NORMAL;
|
||||
PRAGMA page_size=1024;
|
||||
PRAGMA locking_mode=EXCLUSIVE;
|
||||
PRAGMA journal_mode=TRUNCATE;
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
} {exclusive truncate} 0 -1
|
||||
|
||||
2 {
|
||||
BEGIN IMMEDIATE;
|
||||
SELECT * FROM t1;
|
||||
COMMIT;
|
||||
} {1 2} 0 -1
|
||||
|
||||
3 {
|
||||
BEGIN;
|
||||
SELECT * FROM t1;
|
||||
COMMIT;
|
||||
} {1 2} 0 -1
|
||||
|
||||
4 { PRAGMA journal_mode = WAL } wal -1 -1
|
||||
5 { INSERT INTO t1 VALUES(3, 4) } {} -1 [wal_file_size 1 1024]
|
||||
6 { PRAGMA locking_mode = NORMAL } normal -1 [wal_file_size 1 1024]
|
||||
7 { INSERT INTO t1 VALUES(5, 6); } {} -1 [wal_file_size 2 1024]
|
||||
|
||||
8 { PRAGMA journal_mode = TRUNCATE } truncate 0 -1
|
||||
9 { INSERT INTO t1 VALUES(7, 8) } {} 0 -1
|
||||
10 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8} 0 -1
|
||||
|
||||
}] {
|
||||
do_execsql_test pager1-7.1.$tn.1 $sql $res
|
||||
catch { set J -1 ; set J [file size test.db-journal] }
|
||||
catch { set W -1 ; set W [file size test.db-wal] }
|
||||
do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1294,9 +1302,15 @@ do_test pager1-9.4.1 {
|
||||
sqlite3_backup B db2 main db main
|
||||
list [B step 10000] [B finish]
|
||||
} {SQLITE_DONE SQLITE_OK}
|
||||
do_test pager1-9.4.2 {
|
||||
list [file size test.db2] [file size test.db]
|
||||
} {0 0}
|
||||
if { [path_is_dos "."] } {
|
||||
do_test pager1-9.4.2_dos {
|
||||
list [file size test.db2] [file size test.db]
|
||||
} {0 1}
|
||||
} else {
|
||||
do_test pager1-9.4.2 {
|
||||
list [file size test.db2] [file size test.db]
|
||||
} {0 0}
|
||||
}
|
||||
db2 close
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
@@ -1919,32 +1933,34 @@ do_test pager1-20.2.2 {
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test pager1-20.3.1 {
|
||||
faultsim_delete_and_reopen
|
||||
db func a_string a_string
|
||||
execsql {
|
||||
PRAGMA cache_size = 10;
|
||||
PRAGMA journal_mode = wal;
|
||||
BEGIN;
|
||||
CREATE TABLE t1(x);
|
||||
CREATE TABLE t2(y);
|
||||
INSERT INTO t1 VALUES(a_string(800));
|
||||
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 2 */
|
||||
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 4 */
|
||||
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 8 */
|
||||
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 16 */
|
||||
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 32 */
|
||||
COMMIT;
|
||||
}
|
||||
} {wal}
|
||||
do_test pager1-20.3.2 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
INSERT INTO t2 VALUES('xxxx');
|
||||
}
|
||||
recursive_select 32 t1
|
||||
execsql COMMIT
|
||||
} {}
|
||||
if { $do_wal_tests } {
|
||||
do_test pager1-20.3.1 {
|
||||
faultsim_delete_and_reopen
|
||||
db func a_string a_string
|
||||
execsql {
|
||||
PRAGMA cache_size = 10;
|
||||
PRAGMA journal_mode = wal;
|
||||
BEGIN;
|
||||
CREATE TABLE t1(x);
|
||||
CREATE TABLE t2(y);
|
||||
INSERT INTO t1 VALUES(a_string(800));
|
||||
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 2 */
|
||||
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 4 */
|
||||
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 8 */
|
||||
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 16 */
|
||||
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 32 */
|
||||
COMMIT;
|
||||
}
|
||||
} {wal}
|
||||
do_test pager1-20.3.2 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
INSERT INTO t2 VALUES('xxxx');
|
||||
}
|
||||
recursive_select 32 t1
|
||||
execsql COMMIT
|
||||
} {}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that a WAL database may not be opened if:
|
||||
@@ -1952,28 +1968,30 @@ do_test pager1-20.3.2 {
|
||||
# pager1-21.1.*: The VFS has an iVersion less than 2, or
|
||||
# pager1-21.2.*: The VFS does not provide xShmXXX() methods.
|
||||
#
|
||||
do_test pager1-21.0 {
|
||||
faultsim_delete_and_reopen
|
||||
execsql {
|
||||
PRAGMA journal_mode = WAL;
|
||||
CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
|
||||
INSERT INTO ko DEFAULT VALUES;
|
||||
}
|
||||
} {wal}
|
||||
do_test pager1-21.1 {
|
||||
testvfs tv -noshm 1
|
||||
sqlite3 db2 test.db -vfs tv
|
||||
catchsql { SELECT * FROM ko } db2
|
||||
} {1 {unable to open database file}}
|
||||
db2 close
|
||||
tv delete
|
||||
do_test pager1-21.2 {
|
||||
testvfs tv -iversion 1
|
||||
sqlite3 db2 test.db -vfs tv
|
||||
catchsql { SELECT * FROM ko } db2
|
||||
} {1 {unable to open database file}}
|
||||
db2 close
|
||||
tv delete
|
||||
if { $do_wal_tests } {
|
||||
do_test pager1-21.0 {
|
||||
faultsim_delete_and_reopen
|
||||
execsql {
|
||||
PRAGMA journal_mode = WAL;
|
||||
CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
|
||||
INSERT INTO ko DEFAULT VALUES;
|
||||
}
|
||||
} {wal}
|
||||
do_test pager1-21.1 {
|
||||
testvfs tv -noshm 1
|
||||
sqlite3 db2 test.db -vfs tv
|
||||
catchsql { SELECT * FROM ko } db2
|
||||
} {1 {unable to open database file}}
|
||||
db2 close
|
||||
tv delete
|
||||
do_test pager1-21.2 {
|
||||
testvfs tv -iversion 1
|
||||
sqlite3 db2 test.db -vfs tv
|
||||
catchsql { SELECT * FROM ko } db2
|
||||
} {1 {unable to open database file}}
|
||||
db2 close
|
||||
tv delete
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that a "PRAGMA wal_checkpoint":
|
||||
@@ -2254,24 +2272,26 @@ do_test pager1.27.1 {
|
||||
# the same database.
|
||||
#
|
||||
catch { db close }
|
||||
do_multiclient_test tn {
|
||||
do_test pager1-28.$tn.1 {
|
||||
sql1 {
|
||||
PRAGMA journal_mode = WAL;
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES('a', 'b');
|
||||
}
|
||||
} {wal}
|
||||
do_test pager1-28.$tn.2 { sql2 { SELECT * FROM t1 } } {a b}
|
||||
if {[wal_is_ok]} {
|
||||
do_multiclient_test tn {
|
||||
do_test pager1-28.$tn.1 {
|
||||
sql1 {
|
||||
PRAGMA journal_mode = WAL;
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES('a', 'b');
|
||||
}
|
||||
} {wal}
|
||||
do_test pager1-28.$tn.2 { sql2 { SELECT * FROM t1 } } {a b}
|
||||
|
||||
do_test pager1-28.$tn.3 { sql1 { PRAGMA locking_mode=exclusive } } {exclusive}
|
||||
do_test pager1-28.$tn.4 {
|
||||
csql1 { BEGIN; INSERT INTO t1 VALUES('c', 'd'); }
|
||||
} {1 {database is locked}}
|
||||
code2 { db2 close ; sqlite3 db2 test.db }
|
||||
do_test pager1-28.$tn.4 {
|
||||
sql1 { INSERT INTO t1 VALUES('c', 'd'); COMMIT }
|
||||
} {}
|
||||
do_test pager1-28.$tn.3 { sql1 { PRAGMA locking_mode=exclusive } } {exclusive}
|
||||
do_test pager1-28.$tn.4 {
|
||||
csql1 { BEGIN; INSERT INTO t1 VALUES('c', 'd'); }
|
||||
} {1 {database is locked}}
|
||||
code2 { db2 close ; sqlite3 db2 test.db }
|
||||
do_test pager1-28.$tn.4 {
|
||||
sql1 { INSERT INTO t1 VALUES('c', 'd'); COMMIT }
|
||||
} {}
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@@ -1046,6 +1046,39 @@ ifcapable crashtest {
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# When a 3.7.0 client opens a write-transaction on a database file that
|
||||
# has been appended to or truncated by a pre-370 client, it updates
|
||||
# the db-size in the file header immediately. This test case provokes
|
||||
# errors during that operation.
|
||||
#
|
||||
do_test pagerfault-22-pre1 {
|
||||
faultsim_delete_and_reopen
|
||||
db func a_string a_string
|
||||
execsql {
|
||||
PRAGMA page_size = 1024;
|
||||
PRAGMA auto_vacuum = 0;
|
||||
CREATE TABLE t1(a);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
INSERT INTO t1 VALUES(a_string(3000));
|
||||
CREATE TABLE t2(a);
|
||||
INSERT INTO t2 VALUES(1);
|
||||
}
|
||||
db close
|
||||
sql36231 { INSERT INTO t1 VALUES(a_string(3000)) }
|
||||
faultsim_save_and_close
|
||||
} {}
|
||||
do_faultsim_test pagerfault-22 -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql { INSERT INTO t2 VALUES(2) }
|
||||
execsql { SELECT * FROM t2 }
|
||||
} -test {
|
||||
faultsim_test_result {0 {1 2}}
|
||||
faultsim_integrity_check
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# When a 3.7.0 client opens a write-transaction on a database file that
|
||||
# has been appended to or truncated by a pre-370 client, it updates
|
||||
|
||||
+137
-32
@@ -1292,7 +1292,12 @@ sqlite3 dbX :memory:
|
||||
dbX eval {PRAGMA temp_store_directory = ""}
|
||||
dbX close
|
||||
|
||||
ifcapable lock_proxy_pragmas&&prefer_proxy_locking {
|
||||
set skip_lock_proxy_tests [path_is_dos "."]
|
||||
ifcapable !lock_proxy_pragmas||prefer_proxy_locking {
|
||||
set skip_lock_proxy_tests 1
|
||||
}
|
||||
|
||||
if !$skip_lock_proxy_tests {
|
||||
set sqlite_hostid_num 1
|
||||
|
||||
set using_proxy 0
|
||||
@@ -1306,67 +1311,67 @@ ifcapable lock_proxy_pragmas&&prefer_proxy_locking {
|
||||
set env(SQLITE_FORCE_PROXY_LOCKING) "0"
|
||||
|
||||
sqlite3 db test.db
|
||||
# set lock proxy name and then query it via pragma interface
|
||||
set lpp [exec mktemp -t 'proxy1']
|
||||
do_test pragma-16.1 {
|
||||
execsql {
|
||||
PRAGMA lock_proxy_file="mylittleproxy";
|
||||
select * from sqlite_master;
|
||||
}
|
||||
execsql {
|
||||
PRAGMA lock_proxy_file;
|
||||
}
|
||||
} {mylittleproxy}
|
||||
execsql "PRAGMA lock_proxy_file='$lpp'"
|
||||
execsql "select * from sqlite_master"
|
||||
execsql "PRAGMA lock_proxy_file"
|
||||
} $lpp
|
||||
|
||||
# 2 database connections can share a lock proxy file
|
||||
do_test pragma-16.2 {
|
||||
sqlite3 db2 test.db
|
||||
execsql {
|
||||
PRAGMA lock_proxy_file="mylittleproxy";
|
||||
} db2
|
||||
execsql "PRAGMA lock_proxy_file='$lpp'" db2
|
||||
} {}
|
||||
|
||||
db2 close
|
||||
# 2nd database connection should auto-name an existing lock proxy file
|
||||
do_test pragma-16.2.1 {
|
||||
sqlite3 db2 test.db
|
||||
execsql {
|
||||
PRAGMA lock_proxy_file=":auto:";
|
||||
select * from sqlite_master;
|
||||
} db2
|
||||
execsql {
|
||||
PRAGMA lock_proxy_file;
|
||||
} db2
|
||||
} {mylittleproxy}
|
||||
execsql "PRAGMA lock_proxy_file" db2
|
||||
} $lpp
|
||||
|
||||
db2 close
|
||||
set lpp2 [exec mktemp -t 'proxy2']
|
||||
|
||||
# 2nd database connection cannot override the lock proxy file
|
||||
do_test pragma-16.3 {
|
||||
sqlite3 db2 test.db
|
||||
execsql {
|
||||
PRAGMA lock_proxy_file="myotherproxy";
|
||||
} db2
|
||||
execsql "PRAGMA lock_proxy_file='$lpp2'" db2
|
||||
catchsql {
|
||||
select * from sqlite_master;
|
||||
} db2
|
||||
} {1 {database is locked}}
|
||||
|
||||
set lpp3 [exec mktemp -t 'proxy3']
|
||||
|
||||
# lock proxy file can be renamed if no other connections are active
|
||||
do_test pragma-16.4 {
|
||||
db2 close
|
||||
db close
|
||||
sqlite3 db2 test.db
|
||||
execsql {
|
||||
PRAGMA lock_proxy_file="myoriginalproxy";
|
||||
PRAGMA lock_proxy_file="myotherproxy";
|
||||
PRAGMA lock_proxy_file;
|
||||
} db2
|
||||
} {myotherproxy}
|
||||
execsql "PRAGMA lock_proxy_file='$lpp3'" db2
|
||||
execsql "PRAGMA lock_proxy_file='$lpp2'" db2
|
||||
execsql "PRAGMA lock_proxy_file" db2
|
||||
} $lpp2
|
||||
|
||||
db2 close
|
||||
set env(SQLITE_FORCE_PROXY_LOCKING) "1"
|
||||
# auto-naming should reuse the last proxy name when available
|
||||
do_test pragma-16.5 {
|
||||
sqlite3 db2 test.db
|
||||
execsql {
|
||||
PRAGMA lock_proxy_file=":auto:";
|
||||
PRAGMA lock_proxy_file;
|
||||
} db2
|
||||
} {myotherproxy}
|
||||
} $lpp2
|
||||
|
||||
# auto-naming a new proxy should use a predictable & unique name
|
||||
do_test pragma-16.6 {
|
||||
db2 close
|
||||
sqlite3 db2 test2.db
|
||||
@@ -1378,6 +1383,7 @@ ifcapable lock_proxy_pragmas&&prefer_proxy_locking {
|
||||
} {1}
|
||||
|
||||
set sqlite_hostid_num 2
|
||||
# db access should be limited to one host at a time (simulate 2nd host id)
|
||||
do_test pragma-16.7 {
|
||||
sqlite3 db test2.db
|
||||
execsql {
|
||||
@@ -1389,6 +1395,7 @@ ifcapable lock_proxy_pragmas&&prefer_proxy_locking {
|
||||
} {1 {database is locked}}
|
||||
db close
|
||||
|
||||
# default to using proxy locking (simulate network file system detection)
|
||||
do_test pragma-16.8 {
|
||||
sqlite3 db test2.db
|
||||
catchsql {
|
||||
@@ -1397,19 +1404,25 @@ ifcapable lock_proxy_pragmas&&prefer_proxy_locking {
|
||||
} {1 {database is locked}}
|
||||
|
||||
db2 close
|
||||
set lpp4 [exec mktemp -t 'proxy4']
|
||||
|
||||
# check that db is unlocked after first host connection closes
|
||||
do_test pragma-16.8.1 {
|
||||
execsql {
|
||||
PRAGMA lock_proxy_file="yetanotherproxy";
|
||||
PRAGMA lock_proxy_file;
|
||||
}
|
||||
} {yetanotherproxy}
|
||||
execsql "PRAGMA lock_proxy_file='$lpp4'"
|
||||
execsql "select * from sqlite_master"
|
||||
execsql "PRAGMA lock_proxy_file"
|
||||
} $lpp4
|
||||
|
||||
do_test pragma-16.8.2 {
|
||||
execsql {
|
||||
create table mine(x);
|
||||
create table if not exists mine(x);
|
||||
insert into mine values (1);
|
||||
}
|
||||
} {}
|
||||
|
||||
db close
|
||||
file delete -force proxytest.db
|
||||
file delete -force .proxytest.db-conch
|
||||
do_test pragma-16.9 {
|
||||
sqlite3 db proxytest.db
|
||||
set lockpath2 [execsql {
|
||||
@@ -1419,6 +1432,98 @@ ifcapable lock_proxy_pragmas&&prefer_proxy_locking {
|
||||
string match "*proxytest.db:auto:" $lockpath2
|
||||
} {1}
|
||||
|
||||
# ensure creating directories for a lock proxy file works
|
||||
set lpp5 [exec mktemp -d -t "proxy5"]/sub/dir/lock
|
||||
db close
|
||||
file delete -force proxytest
|
||||
do_test pragma-16.10.1 {
|
||||
sqlite3 db proxytest.db
|
||||
execsql "PRAGMA lock_proxy_file='$lpp5'"
|
||||
set lockpath2 [execsql {
|
||||
PRAGMA lock_proxy_file;
|
||||
} db]
|
||||
string match "*sub/dir/lock" $lockpath2
|
||||
} {1}
|
||||
|
||||
# ensure that after deleting the path, setting ":auto:" works correctly
|
||||
db close
|
||||
file delete -force proxytest
|
||||
do_test pragma-16.10.2 {
|
||||
sqlite3 db proxytest.db
|
||||
set lockpath3 [execsql {
|
||||
PRAGMA lock_proxy_file=":auto:";
|
||||
create table if not exists pt(y);
|
||||
PRAGMA lock_proxy_file;
|
||||
} db]
|
||||
string match "*sub/dir/lock" $lockpath3
|
||||
} {1}
|
||||
|
||||
# ensure that if the path can not be created (file instead of dir)
|
||||
# setting :auto: deals with it by creating a new autonamed lock file
|
||||
db close
|
||||
file delete -force proxytest
|
||||
close [open "proxytest" a]
|
||||
do_test pragma-16.10.3 {
|
||||
sqlite3 db proxytest.db
|
||||
set lockpath2 [execsql {
|
||||
PRAGMA lock_proxy_file=":auto:";
|
||||
create table if not exists zz(y);
|
||||
PRAGMA lock_proxy_file;
|
||||
} db]
|
||||
string match "*proxytest.db:auto:" $lockpath2
|
||||
} {1}
|
||||
|
||||
# make sure we can deal with ugly file paths correctly
|
||||
set lpp6 [exec mktemp -d -t "proxy6"]/./././////./proxytest/../proxytest/sub/dir/lock
|
||||
db close
|
||||
file delete -force proxytest
|
||||
do_test pragma-16.10.4 {
|
||||
sqlite3 db proxytest.db
|
||||
execsql "PRAGMA lock_proxy_file='$lpp6'"
|
||||
set lockpath4 [execsql {
|
||||
create table if not exists aa(bb);
|
||||
PRAGMA lock_proxy_file;
|
||||
} db]
|
||||
string match "*proxytest/sub/dir/lock" $lockpath4
|
||||
} {1}
|
||||
|
||||
# ensure that if the path can not be created (perm), setting :auto: deals
|
||||
db close
|
||||
file delete -force proxytest
|
||||
do_test pragma-16.10.5 {
|
||||
sqlite3 db proxytest.db
|
||||
execsql "PRAGMA lock_proxy_file='$lpp5'"
|
||||
execsql {
|
||||
create table if not exists bb(bb);
|
||||
}
|
||||
db close
|
||||
file delete -force proxytest
|
||||
file mkdir proxytest
|
||||
file attributes proxytest -permission 0000
|
||||
sqlite3 db proxytest.db
|
||||
set lockpath5 [execsql {
|
||||
PRAGMA lock_proxy_file=":auto:";
|
||||
create table if not exists cc(bb);
|
||||
PRAGMA lock_proxy_file;
|
||||
} db]
|
||||
string match "*proxytest.db:auto:" $lockpath5
|
||||
} {1}
|
||||
|
||||
# ensure that if the path can not be created, locking fails
|
||||
db close
|
||||
do_test pragma-16.10.6 {
|
||||
sqlite3 db proxytest.db
|
||||
execsql "PRAGMA lock_proxy_file='$lpp5'"
|
||||
catchsql {
|
||||
create table if not exists faily(y);
|
||||
PRAGMA lock_proxy_file;
|
||||
} db
|
||||
} {1 {database is locked}}
|
||||
db close
|
||||
|
||||
file attributes proxytest -permission 0777
|
||||
file delete -force proxytest
|
||||
|
||||
set env(SQLITE_FORCE_PROXY_LOCKING) $using_proxy
|
||||
set sqlite_hostid_num 0
|
||||
}
|
||||
|
||||
+1
-5
@@ -45,13 +45,9 @@ ifcapable autovacuum {
|
||||
# if we're using proxy locks, we use 2 filedescriptors for a db
|
||||
# that is open but NOT yet locked, after a lock is taken we'll have 3,
|
||||
# normally sqlite uses 1 (proxy locking adds the conch and the local lock)
|
||||
set using_proxy 0
|
||||
foreach {name value} [array get env SQLITE_FORCE_PROXY_LOCKING] {
|
||||
set using_proxy $value
|
||||
}
|
||||
set extrafds_prelock 0
|
||||
set extrafds_postlock 0
|
||||
if {$using_proxy>0} {
|
||||
if {[forced_proxy_locking]} {
|
||||
set extrafds_prelock 1
|
||||
set extrafds_postlock 2
|
||||
}
|
||||
|
||||
+7
-6
@@ -30,12 +30,13 @@ do_execsql_test stat-0.0 {
|
||||
CREATE VIRTUAL TABLE temp.stat USING dbstat;
|
||||
SELECT * FROM stat;
|
||||
} {}
|
||||
do_execsql_test stat-0.1 {
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA journal_mode = delete;
|
||||
SELECT * FROM stat;
|
||||
} {wal delete sqlite_master / 1 leaf 0 0 916 0}
|
||||
|
||||
if {[wal_is_ok]} {
|
||||
do_execsql_test stat-0.1 {
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA journal_mode = delete;
|
||||
SELECT * FROM stat;
|
||||
} {wal delete sqlite_master / 1 leaf 0 0 916 0}
|
||||
}
|
||||
do_test stat-1.0 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b);
|
||||
|
||||
+24
-7
@@ -30,8 +30,19 @@ if {$::TEMP_STORE==3} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# if we're using proxy locks, we use 3 filedescriptors for a db
|
||||
# that is open but NOT writing changes, normally
|
||||
# sqlite uses 1 (proxy locking adds the conch and the local lock)
|
||||
set extrafds 0
|
||||
if {[forced_proxy_locking]} {
|
||||
set extrafds 2
|
||||
}
|
||||
|
||||
|
||||
do_test stmt-1.2 {
|
||||
set sqlite_open_file_count
|
||||
expr $sqlite_open_file_count-$extrafds
|
||||
} {1}
|
||||
do_test stmt-1.3 {
|
||||
execsql {
|
||||
@@ -39,16 +50,19 @@ do_test stmt-1.3 {
|
||||
INSERT INTO t1 VALUES(1, 1);
|
||||
}
|
||||
set sqlite_open_file_count
|
||||
expr $sqlite_open_file_count-$extrafds
|
||||
} {2}
|
||||
do_test stmt-1.4 {
|
||||
execsql {
|
||||
INSERT INTO t1 SELECT a+1, b+1 FROM t1;
|
||||
}
|
||||
set sqlite_open_file_count
|
||||
expr $sqlite_open_file_count-$extrafds
|
||||
} {3}
|
||||
do_test stmt-1.5 {
|
||||
execsql COMMIT
|
||||
set sqlite_open_file_count
|
||||
expr $sqlite_open_file_count-$extrafds
|
||||
} {1}
|
||||
do_test stmt-1.6.1 {
|
||||
execsql {
|
||||
@@ -56,34 +70,37 @@ do_test stmt-1.6.1 {
|
||||
INSERT INTO t1 SELECT a+2, b+2 FROM t1;
|
||||
}
|
||||
set sqlite_open_file_count
|
||||
expr $sqlite_open_file_count-$extrafds
|
||||
} {2}
|
||||
do_test stmt-1.6.2 {
|
||||
execsql { INSERT INTO t1 SELECT a+4, b+4 FROM t1 }
|
||||
set sqlite_open_file_count
|
||||
expr $sqlite_open_file_count-$extrafds
|
||||
} {3}
|
||||
do_test stmt-1.7 {
|
||||
execsql COMMIT
|
||||
set sqlite_open_file_count
|
||||
expr $sqlite_open_file_count-$extrafds
|
||||
} {1}
|
||||
|
||||
|
||||
proc filecount {testname sql expected} {
|
||||
proc filecount {testname sql expected extrafds} {
|
||||
uplevel [list do_test $testname [subst -nocommand {
|
||||
execsql BEGIN
|
||||
execsql { $sql }
|
||||
set ret [set sqlite_open_file_count]
|
||||
execsql ROLLBACK
|
||||
set ret
|
||||
}] $expected]
|
||||
}] [ expr $expected+$extrafds ] ]
|
||||
}
|
||||
|
||||
filecount stmt-2.1 { INSERT INTO t1 VALUES(9, 9) } 2
|
||||
filecount stmt-2.2 { REPLACE INTO t1 VALUES(9, 9) } 2
|
||||
filecount stmt-2.3 { INSERT INTO t1 SELECT 9, 9 } 2
|
||||
filecount stmt-2.1 { INSERT INTO t1 VALUES(9, 9) } 2 $extrafds
|
||||
filecount stmt-2.2 { REPLACE INTO t1 VALUES(9, 9) } 2 $extrafds
|
||||
filecount stmt-2.3 { INSERT INTO t1 SELECT 9, 9 } 2 $extrafds
|
||||
filecount stmt-2.4 {
|
||||
INSERT INTO t1 SELECT 9, 9;
|
||||
INSERT INTO t1 SELECT 10, 10;
|
||||
} 3
|
||||
} 3 $extrafds
|
||||
|
||||
do_test stmt-2.5 {
|
||||
execsql { CREATE INDEX i1 ON t1(b) }
|
||||
@@ -91,6 +108,6 @@ do_test stmt-2.5 {
|
||||
filecount stmt-2.6 {
|
||||
REPLACE INTO t1 VALUES(5, 5);
|
||||
REPLACE INTO t1 VALUES(5, 5);
|
||||
} 3
|
||||
} 3 $extrafds
|
||||
|
||||
finish_test
|
||||
|
||||
+7
-2
@@ -52,6 +52,11 @@ do_test tempdb-1.2 {
|
||||
}
|
||||
} {}
|
||||
|
||||
set extrafds 0
|
||||
if {[forced_proxy_locking]} {
|
||||
set extrafds 2
|
||||
}
|
||||
|
||||
do_test tempdb-2.1 {
|
||||
# Set $::jrnl_in_memory if the journal file is expected to be in-memory.
|
||||
# Similarly, set $::subj_in_memory if the sub-journal file is expected
|
||||
@@ -76,7 +81,7 @@ do_test tempdb-2.2 {
|
||||
}
|
||||
catchsql { INSERT INTO t1 SELECT * FROM t2 }
|
||||
set sqlite_open_file_count
|
||||
} [expr 1 + (0==$jrnl_in_memory) + (0==$subj_in_memory)]
|
||||
} [expr 1 + $extrafds + (0==$jrnl_in_memory) + (0==$subj_in_memory)]
|
||||
do_test tempdb-2.3 {
|
||||
execsql {
|
||||
PRAGMA temp_store = 'memory';
|
||||
@@ -88,6 +93,6 @@ do_test tempdb-2.3 {
|
||||
}
|
||||
catchsql { INSERT INTO t1 SELECT * FROM t2 }
|
||||
set sqlite_open_file_count
|
||||
} [expr 1 + (0==$jrnl_in_memory)]
|
||||
} [expr 1 + $extrafds + (0==$jrnl_in_memory)]
|
||||
|
||||
finish_test
|
||||
|
||||
+41
-4
@@ -245,6 +245,10 @@ reset_db
|
||||
#
|
||||
if {[info exists TC(count)]} return
|
||||
|
||||
# Make sure memory statistics are enabled.
|
||||
#
|
||||
sqlite3_config_memstatus 1
|
||||
|
||||
# Initialize the test counters and set up commands to access them.
|
||||
# Or, if this is a slave interpreter, set up aliases to write the
|
||||
# counters in the parent interpreter.
|
||||
@@ -475,11 +479,15 @@ proc finalize_testing {} {
|
||||
memdebug_log_sql leaks.sql
|
||||
}
|
||||
}
|
||||
foreach f [glob -nocomplain test.db-*-journal] {
|
||||
file delete -force $f
|
||||
catch {
|
||||
foreach f [glob -nocomplain test.db-*-journal] {
|
||||
file delete -force $f
|
||||
}
|
||||
}
|
||||
foreach f [glob -nocomplain test.db-mj*] {
|
||||
file delete -force $f
|
||||
catch {
|
||||
foreach f [glob -nocomplain test.db-mj*] {
|
||||
file delete -force $f
|
||||
}
|
||||
}
|
||||
exit [expr {$nErr>0}]
|
||||
}
|
||||
@@ -1157,6 +1165,35 @@ proc presql {} {
|
||||
set presql
|
||||
}
|
||||
|
||||
proc forced_proxy_locking {} {
|
||||
ifcapable lock_proxy_pragmas&&prefer_proxy_locking {
|
||||
set force_proxy_value 0
|
||||
set force_key "SQLITE_FORCE_PROXY_LOCKING="
|
||||
foreach {env_pair} [exec env] {
|
||||
if { [string first $force_key $env_pair] == 0} {
|
||||
set force_proxy_value [string range $env_pair [string length $force_key] end]
|
||||
}
|
||||
}
|
||||
if { "$force_proxy_value " == "1 " } {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
proc wal_is_ok {} {
|
||||
if { [forced_proxy_locking] } {
|
||||
return 1
|
||||
}
|
||||
if { ![path_is_local "."] } {
|
||||
return 0
|
||||
}
|
||||
if { [path_is_dos "."] } {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
proc slave_test_script {script} {
|
||||
|
||||
+22
-20
@@ -62,26 +62,28 @@ do_test tkt3457-1.1 {
|
||||
execsql COMMIT
|
||||
} {}
|
||||
|
||||
do_test tkt3457-1.2 {
|
||||
file copy -force bak.db-journal test.db-journal
|
||||
file attributes test.db-journal -permissions ---------
|
||||
catchsql { SELECT * FROM t1 }
|
||||
} {1 {unable to open database file}}
|
||||
do_test tkt3457-1.3 {
|
||||
file copy -force bak.db-journal test.db-journal
|
||||
file attributes test.db-journal -permissions -w--w--w-
|
||||
catchsql { SELECT * FROM t1 }
|
||||
} {1 {unable to open database file}}
|
||||
do_test tkt3457-1.4 {
|
||||
file copy -force bak.db-journal test.db-journal
|
||||
file attributes test.db-journal -permissions r--r--r--
|
||||
catchsql { SELECT * FROM t1 }
|
||||
} {1 {unable to open database file}}
|
||||
if { ![path_is_dos "."] } {
|
||||
do_test tkt3457-1.2 {
|
||||
file copy -force bak.db-journal test.db-journal
|
||||
file attributes test.db-journal -permissions ---------
|
||||
catchsql { SELECT * FROM t1 }
|
||||
} {1 {unable to open database file}}
|
||||
do_test tkt3457-1.3 {
|
||||
file copy -force bak.db-journal test.db-journal
|
||||
file attributes test.db-journal -permissions -w--w--w-
|
||||
catchsql { SELECT * FROM t1 }
|
||||
} {1 {unable to open database file}}
|
||||
do_test tkt3457-1.4 {
|
||||
file copy -force bak.db-journal test.db-journal
|
||||
file attributes test.db-journal -permissions r--r--r--
|
||||
catchsql { SELECT * FROM t1 }
|
||||
} {1 {unable to open database file}}
|
||||
|
||||
do_test tkt3457-1.5 {
|
||||
file copy -force bak.db-journal test.db-journal
|
||||
file attributes test.db-journal -permissions rw-rw-rw-
|
||||
catchsql { SELECT * FROM t1 }
|
||||
} {0 {1 2 3 4 5 6}}
|
||||
do_test tkt3457-1.5 {
|
||||
file copy -force bak.db-journal test.db-journal
|
||||
file attributes test.db-journal -permissions rw-rw-rw-
|
||||
catchsql { SELECT * FROM t1 }
|
||||
} {0 {1 2 3 4 5 6}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -20,6 +20,10 @@ source $testdir/malloc_common.tcl
|
||||
source $testdir/wal_common.tcl
|
||||
|
||||
ifcapable !wal {finish_test ; return }
|
||||
if { ![wal_is_ok] } {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
proc reopen_db {} {
|
||||
catch { db close }
|
||||
|
||||
@@ -20,6 +20,10 @@ source $testdir/malloc_common.tcl
|
||||
source $testdir/wal_common.tcl
|
||||
|
||||
ifcapable !wal {finish_test ; return }
|
||||
if { ![wal_is_ok] || [path_is_dos "."]} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
proc set_tvfs_hdr {file args} {
|
||||
|
||||
@@ -1149,4 +1153,59 @@ if {$::tcl_platform(platform) == "unix"} {
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that "PRAGMA checkpoint_fullsync" appears to be working.
|
||||
#
|
||||
foreach {tn sql reslist} {
|
||||
1 { } {8 0 3 0 5 0}
|
||||
2 { PRAGMA checkpoint_fullfsync = 1 } {8 4 3 2 5 2}
|
||||
3 { PRAGMA checkpoint_fullfsync = 0 } {8 0 3 0 5 0}
|
||||
} {
|
||||
faultsim_delete_and_reopen
|
||||
|
||||
execsql $sql
|
||||
do_execsql_test wal2-14.$tn.1 { PRAGMA journal_mode = WAL } {wal}
|
||||
|
||||
set sqlite_sync_count 0
|
||||
set sqlite_fullsync_count 0
|
||||
|
||||
do_execsql_test wal2-14.$tn.2 {
|
||||
PRAGMA wal_autocheckpoint = 10;
|
||||
CREATE TABLE t1(a, b); -- 2 wal syncs
|
||||
INSERT INTO t1 VALUES(1, 2); -- 1 wal sync
|
||||
PRAGMA wal_checkpoint; -- 1 wal sync, 1 db sync
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(3, 4);
|
||||
INSERT INTO t1 VALUES(5, 6);
|
||||
COMMIT; -- 1 wal sync
|
||||
PRAGMA wal_checkpoint; -- 1 wal sync, 1 db sync
|
||||
} {10}
|
||||
|
||||
do_test wal2-14.$tn.3 {
|
||||
list $sqlite_sync_count $sqlite_fullsync_count
|
||||
} [lrange $reslist 0 1]
|
||||
|
||||
set sqlite_sync_count 0
|
||||
set sqlite_fullsync_count 0
|
||||
|
||||
do_test wal2-14.$tn.4 {
|
||||
execsql { INSERT INTO t1 VALUES(7, zeroblob(12*4096)) }
|
||||
list $sqlite_sync_count $sqlite_fullsync_count
|
||||
} [lrange $reslist 2 3]
|
||||
|
||||
set sqlite_sync_count 0
|
||||
set sqlite_fullsync_count 0
|
||||
|
||||
do_test wal2-14.$tn.5 {
|
||||
execsql { PRAGMA wal_autocheckpoint = 1000 }
|
||||
execsql { INSERT INTO t1 VALUES(9, 10) }
|
||||
execsql { INSERT INTO t1 VALUES(11, 12) }
|
||||
execsql { INSERT INTO t1 VALUES(13, 14) }
|
||||
db close
|
||||
list $sqlite_sync_count $sqlite_fullsync_count
|
||||
} [lrange $reslist 4 5]
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+5
-1
@@ -19,6 +19,10 @@ source $testdir/lock_common.tcl
|
||||
source $testdir/wal_common.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
ifcapable !wal {finish_test ; return }
|
||||
if { ![wal_is_ok] } {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set a_string_counter 1
|
||||
proc a_string {n} {
|
||||
@@ -613,7 +617,7 @@ T delete
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_test wal3-8.1 {
|
||||
file delete -force test.db test.db-journal test.db wal
|
||||
file delete -force test.db test.db-journal test.db wal .test.db-conch
|
||||
sqlite3 db test.db
|
||||
sqlite3 db2 test.db
|
||||
execsql {
|
||||
|
||||
@@ -16,6 +16,10 @@ set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
ifcapable !wal {finish_test ; return }
|
||||
if { ![wal_is_ok] || [path_is_dos "."]} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_test wal4-1.1 {
|
||||
execsql {
|
||||
|
||||
@@ -21,6 +21,10 @@ source $testdir/malloc_common.tcl
|
||||
do_not_use_codec
|
||||
|
||||
ifcapable !wal {finish_test ; return }
|
||||
if { ![wal_is_ok] } {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
# Test organization:
|
||||
|
||||
@@ -27,6 +27,10 @@ ifcapable !lfs {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
if { ![wal_is_ok] } {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set a_string_counter 1
|
||||
proc a_string {n} {
|
||||
|
||||
@@ -16,6 +16,10 @@ source $testdir/lock_common.tcl
|
||||
source $testdir/wal_common.tcl
|
||||
|
||||
ifcapable !wal {finish_test ; return }
|
||||
if { ![wal_is_ok] } {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# Read and return the contents of file $filename. Treat the content as
|
||||
# binary data.
|
||||
|
||||
@@ -28,6 +28,10 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !wal {finish_test ; return }
|
||||
if { ![wal_is_ok] } {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
db close
|
||||
|
||||
|
||||
@@ -16,6 +16,10 @@ source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
source $testdir/wal_common.tcl
|
||||
ifcapable !wal {finish_test ; return }
|
||||
if { ![wal_is_ok] } {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@@ -19,6 +19,10 @@ source $testdir/malloc_common.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
|
||||
ifcapable !wal {finish_test ; return }
|
||||
if { ![wal_is_ok] } {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# This test case, walfault-1-*, simulates faults while executing a
|
||||
|
||||
@@ -22,6 +22,10 @@ source $testdir/tester.tcl
|
||||
source $testdir/wal_common.tcl
|
||||
|
||||
ifcapable !wal {finish_test ; return }
|
||||
if { ![wal_is_ok] } {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set ::wal_hook [list]
|
||||
proc wal_hook {zDb nEntry} {
|
||||
|
||||
@@ -35,6 +35,20 @@ ifcapable !wal {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
if { ![wal_is_ok] && ![path_is_dos "."]} {
|
||||
do_test walmode-0.1 {
|
||||
execsql { PRAGMA journal_mode = wal }
|
||||
} {delete}
|
||||
do_test walmode-0.2 {
|
||||
execsql { PRAGMA main.journal_mode = wal }
|
||||
} {delete}
|
||||
do_test walmode-0.3 {
|
||||
execsql { PRAGMA main.journal_mode }
|
||||
} {delete}
|
||||
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_test walmode-1.1 {
|
||||
set sqlite_sync_count 0
|
||||
|
||||
@@ -15,6 +15,13 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !wal {finish_test ; return }
|
||||
if { ![wal_is_ok] } {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
db close
|
||||
set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
|
||||
|
||||
|
||||
@@ -18,6 +18,10 @@ set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !wal {finish_test ; return }
|
||||
if { ![wal_is_ok] } {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
proc reopen_db {} {
|
||||
catch { db close }
|
||||
|
||||
@@ -19,6 +19,10 @@ source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
if {[run_thread_tests]==0} { finish_test ; return }
|
||||
ifcapable !wal { finish_test ; return }
|
||||
if { ![wal_is_ok] } {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set sqlite_walsummary_mmap_incr 64
|
||||
|
||||
|
||||
@@ -107,6 +107,7 @@ foreach hdr {
|
||||
sqliteicu.h
|
||||
sqliteInt.h
|
||||
sqliteLimit.h
|
||||
sqlrr.h
|
||||
vdbe.h
|
||||
vdbeInt.h
|
||||
wal.h
|
||||
@@ -305,6 +306,7 @@ foreach file {
|
||||
rtree.c
|
||||
icu.c
|
||||
fts3_icu.c
|
||||
sqlrr.c
|
||||
} {
|
||||
copy_file tsrc/$file
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user