Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d23cae475d | |||
| d736884f3d | |||
| 7ae193a5cd | |||
| a96a399ec9 | |||
| 3640db58d0 | |||
| b6d2f9c5ef | |||
| 4edc6bf3ee | |||
| 283f9e7ee6 | |||
| fa64665a49 | |||
| e127a2ea9f | |||
| 5be1b1f262 | |||
| 25d2380356 | |||
| 69d67f5412 | |||
| 6f7fe3ef3e | |||
| e3a4e11bcc | |||
| 67d225da53 | |||
| 5a5ced7da9 | |||
| 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
@@ -323,6 +323,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
|
||||
@@ -470,6 +473,17 @@ EXTHDR += \
|
||||
$(TOP)/ext/icu/sqliteicu.h
|
||||
EXTHDR += \
|
||||
$(TOP)/ext/rtree/sqlite3rtree.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.
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
#include "sqlite3rtree.h"
|
||||
|
||||
@@ -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_ */
|
||||
@@ -204,6 +204,8 @@ SRC += \
|
||||
SRC += \
|
||||
$(TOP)/ext/rtree/rtree.h \
|
||||
$(TOP)/ext/rtree/rtree.c
|
||||
SRC += \
|
||||
$(TOP)/ext/sqlrr/sqlrr.c
|
||||
|
||||
|
||||
# Generated source code files
|
||||
@@ -345,6 +347,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.
|
||||
@@ -366,10 +370,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,7 +1,7 @@
|
||||
C When\scommitting\sa\sWAL\stransaction,\smake\ssure\sat\sleast\sone\spage\sis\nwritten\sto\sthe\sWAL\sfile\sso\sthat\sthe\sWAL\ssubsystem\swill\shave\sa\spage\non\swhich\sto\sset\sthe\scommit\sflag.\nTicket\s[2d1a5c67dfc236].
|
||||
D 2011-05-19T01:21:42.431
|
||||
C Bring\sthe\sapple-wal-readonly\sbranch\sup\sto\sdate\swith\sthe\slatest\schanges\nin\sapple-osx,\sand\sespecially\sthe\sfix\sfor\sdisappearing\sWAL\stransactions.
|
||||
D 2011-05-19T02:34:30.938
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 11dcc00a8d0e5202def00e81732784fb0cc4fe1d
|
||||
F Makefile.in a38f09acc876beec6b103a6e12a33795c6b1df9c
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.vxworks c85ec1d8597fe2f7bc225af12ac1666e21379151
|
||||
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
|
||||
@@ -82,7 +82,7 @@ F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
|
||||
F ext/icu/icu.c eb9ae1d79046bd7871aa97ee6da51eb770134b5a
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c 2445bec932f58f8f4fe9de49a63bd6bf24db82d6
|
||||
F ext/rtree/rtree.c d3741cde910b659fd66ca4289eed430e90bdbbb0
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
F ext/rtree/rtree1.test 28e1b8da4da98093ce3210187434dd760a8d89d8
|
||||
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
|
||||
@@ -100,9 +100,12 @@ F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
|
||||
F ext/rtree/sqlite3rtree.h 1af0899c63a688e272d69d8e746f24e76f10a3f0
|
||||
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F ext/sqlrr/README.txt 4239030e73023e72a2e727808cd433577d5bf730
|
||||
F ext/sqlrr/sqlrr.c 8d1e6571cd6a6beabdb5bcdfe3a0e723b914db41
|
||||
F ext/sqlrr/sqlrr.h 09e4f8929ad9bc2638732c0cc0db5eef8c417824
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F main.mk 6111163d4e9720e4212ef288e967b4aa2c2ce379
|
||||
F main.mk 3c7e0f21e531b58cfe398964a464411543462eec
|
||||
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
|
||||
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
|
||||
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
|
||||
@@ -117,13 +120,13 @@ F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
||||
F src/alter.c 280f5c04b11b492703a342222b3de0a999445280
|
||||
F src/analyze.c a425d62e8fa9ebcb4359ab84ff0c62c6563d2e2a
|
||||
F src/attach.c 12c6957996908edc31c96d7c68d4942c2474405f
|
||||
F src/attach.c a87bfb77a720f7aa02791434aacfd9bc8feb50cc
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c 986c15232757f2873dff35ee3b35cbf935fc573c
|
||||
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
|
||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c 975ad691a57eb1fb60f1ec76ad0b6571eace62f9
|
||||
F src/btree.h f5d775cd6cfc7ac32a2535b70e8d2af48ef5f2ce
|
||||
F src/btree.h d796dc4030b3cce7f5a0cc4f2f986d2befa6b8ac
|
||||
F src/btreeInt.h 67978c014fa4f7cc874032dd3aacadd8db656bc3
|
||||
F src/build.c 0132bc6631fa617a1d28ef805921f6dbac18a514
|
||||
F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a
|
||||
@@ -134,20 +137,20 @@ F src/delete.c 7a24fcc9a31664d145acb97ce56b6d9f249a25e4
|
||||
F src/expr.c e3cf0957c6b8faaaf7386a3bc69e53c0dc9705be
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c a43ba8a005fb5efd1deeee06853e3a6120d46a91
|
||||
F src/func.c b9117e40975245b8504cf3625d7e321d8d4b63dc
|
||||
F src/func.c c02fda657f2366c493198c3e480695fc69972c5f
|
||||
F src/global.c 29bfb85611dd816b04f10fba0ca910366e128d38
|
||||
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
|
||||
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c 3eea5a53d2644116fb865afaa4699fabe62b441c
|
||||
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/legacy.c 015826a958f690302d27e096a68d50b3657e4201
|
||||
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
|
||||
F src/loadext.c 3ae0d52da013a6326310655be6473fd472347b85
|
||||
F src/main.c 059daeed5876b3604f0192f838faf5f4db138901
|
||||
F src/main.c 6dc61e8bf59098d1ec49b20760e91539997acaaf
|
||||
F src/malloc.c 591aedb20ae40813f1045f2ef253438a334775d9
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206
|
||||
F src/mem1.c 46095d62b241466ef51970e592aa3a7a87e443e1
|
||||
F src/mem2.c e307323e86b5da1853d7111b68fd6b84ad6f09cf
|
||||
F src/mem3.c 9b237d911ba9904142a804be727cc6664873f8a3
|
||||
F src/mem5.c c2c63b7067570b00bf33d751c39af24182316f7f
|
||||
@@ -163,30 +166,31 @@ F src/os.c 22ac61d06e72a0dac900400147333b07b13d8e1d
|
||||
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
|
||||
F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
|
||||
F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440
|
||||
F src/os_unix.c 6d4a58d81ad4b782406519f3790202f330e89bb7
|
||||
F src/os_unix.c d5feb6cbdbbeb1f2d3d8c816dc93da7c408468a8
|
||||
F src/os_win.c 218b899469e570d46eb8147c2383075f7c026230
|
||||
F src/pager.c 4b2358556c88660a94a4560de95dd728911e00fd
|
||||
F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1
|
||||
F src/pager.c 928d50d35d0167799ac77357e6c4966b3be93f9d
|
||||
F src/pager.h 34c6b029446f06f40847746d22faac0d354dd909
|
||||
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
|
||||
F src/pcache.c 09d38c44ab275db581f7a2f6ff8b9bc7f8c0faaa
|
||||
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
|
||||
F src/pcache1.c d548e31beafa792d1994b663a29a5303569efc4e
|
||||
F src/pragma.c 9e778decc3ee9bcaf88904b4a3b0a4360aaf0eab
|
||||
F src/prepare.c e64261559a3187698a3e7e6c8b001a4f4f98dab4
|
||||
F src/pragma.c 8756649386a4eb7192915fb44e177d30e19f723c
|
||||
F src/prepare.c 9d7403fe75fefa134351b41400d09ba1b189134b
|
||||
F src/printf.c 585a36b6a963df832cfb69505afa3a34ed5ef8a1
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
|
||||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c d9d440809025a58547e39f4f268c2a296bfb56ff
|
||||
F src/shell.c decd04236a7ef26be5ef46d4ea963044bfad9a48
|
||||
F src/sqlite.h.in 8bbf8d9bc5f1a9474a633a2de7014506f1f06b90
|
||||
F src/sqlite.h.in 1c5172169121b89b2b08757acc57ec7a846f9c92
|
||||
F src/sqlite3_private.h 2a814d17913732831acf13e7e87860105a3416e4
|
||||
F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754
|
||||
F src/sqliteInt.h 771087591052966d36ac1fcd3c8bb7a8c6cf9a38
|
||||
F src/sqliteInt.h 52b58043e97367686042345d2e581604e44a1cbf
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c 501c9a200fd998a268be475be5858febc90b725b
|
||||
F src/test1.c 4a1171af201be90c21d64a872e686b1333d9a2cf
|
||||
F src/test1.c acdf3394565b1669657ea175013f418adb8fae44
|
||||
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
|
||||
F src/test3.c 124ff9735fb6bb7d41de180d6bac90e7b1509432
|
||||
F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7
|
||||
@@ -197,9 +201,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 9a6aa8301a56906612b5e70f5b38e80cfb8af8e7
|
||||
F src/test_config.c 308a99163bd821efa84f0ada99bc61fbbf44b613
|
||||
F src/test_demovfs.c 938d0f595f8bd310076e1c06cf7885a01ce7ce01
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_func.c cbdec5cededa0761daedde5baf06004a9bf416b5
|
||||
@@ -236,17 +240,17 @@ F src/update.c 5bcb56e5c7380a2eecb0e71891dbd4ad7437748f
|
||||
F src/utf.c d83650c3ea08f7407bd9d0839d9885241c209c60
|
||||
F src/util.c 0f33bbbdfcc4a2d8cf20c3b2a16ffc3b57c58a70
|
||||
F src/vacuum.c 05513dca036a1e7848fe18d5ed1265ac0b32365e
|
||||
F src/vdbe.c 343a068e8daeb8475e66776feb9f2974046e95c5
|
||||
F src/vdbe.c f997c49fa6745bce83e23ae7863a328f8cb9d448
|
||||
F src/vdbe.h 8a675fefdf7119441fe817c800a9a52440c2e797
|
||||
F src/vdbeInt.h fe8f58d305e629fff02f61f655aca1d299f1f6ae
|
||||
F src/vdbeapi.c e0e2672e0a96ae3f8575c8ecd02912a3e8a554a1
|
||||
F src/vdbeapi.c 34b6686d9079264bc715f63e41bc2f0d9b98de89
|
||||
F src/vdbeaux.c 535851211df61d83213c83d5ffd3c6ce9ecbdc18
|
||||
F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562
|
||||
F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b
|
||||
F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114
|
||||
F src/vtab.c 48dcef8bc757c2e7b488f68b5ddebb1650da2450
|
||||
F src/wal.c de27c34c8016c00be348fc6bed588816557ceb66
|
||||
F src/wal.h 66b40bd91bc29a5be1c88ddd1f5ade8f3f48728a
|
||||
F src/wal.c 11c17da2060683c9c0f3538f57e89643b0e2eb7e
|
||||
F src/wal.h 0835021ae243c2f1119e997e8af5d8cc3b991de1
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c 55403ce19c506be6a321c7f129aff693d6103db5
|
||||
F test/8_3_names.test b93687beebd17f6ebf812405a6833bae5d1f4199
|
||||
@@ -270,7 +274,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 2bb09073d7d5499127db00f50780766dcea913e1
|
||||
F test/attach.test e26b6c050d5b2ba0064288137bdd325370c11e65
|
||||
F test/attach2.test a295d2d7061adcee5884ef4a93c7c96a82765437
|
||||
F test/attach3.test bd9830bc3a0d22ed1310c9bff6896927937017dc
|
||||
F test/attach4.test 31f9eb0ca7bdbc393cc4657b877903a226a83d4b
|
||||
@@ -293,7 +297,7 @@ F test/badutf2.test f5bc7f2d280670ecd79b9cf4f0f1760c607fe51f
|
||||
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
|
||||
@@ -388,12 +392,12 @@ F test/enc3.test 5c550d59ff31dccdba5d1a02ae11c7047d77c041
|
||||
F test/enc4.test 4b575ef09e0eff896e73bd24076f96c2aa6a42de
|
||||
F test/eqp.test f14fadd76da53405e9885e2431cacf7191d83cdb
|
||||
F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
|
||||
F test/exclusive.test 53e1841b422e554cecf0160f937c473d6d0e3062
|
||||
F test/exclusive.test 897074dc6706b0c4f3b1dc4580ffddffe2a79206
|
||||
F test/exclusive2.test 343d55130c12c67b8bf10407acec043a6c26c86b
|
||||
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
|
||||
F test/exists.test 5e2d64b4eb5a9d08876599bdae2e1213d2d12e2a
|
||||
F test/expr.test 67c9fd6f8f829e239dc8b0f4a08a73c08b09196d
|
||||
F test/fallocate.test 43dc34b8c24be6baffadc3b4401ee15710ce83c6
|
||||
F test/fallocate.test a9927b638567e2e776c112f54d701402a0e74023
|
||||
F test/filectrl.test 97003734290887566e01dded09dc9e99cb937e9e
|
||||
F test/filefmt.test f178cfc29501a14565954c961b226e61877dd32c
|
||||
F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
|
||||
@@ -529,7 +533,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 c6522b276ba315fd1416198de6fc1da9e72409fb
|
||||
@@ -545,12 +549,13 @@ F test/lock.test db74fdf5a73bad29ab3d862ea78bf1068972cc1d
|
||||
F test/lock2.test 5242d8ac4e2d59c403aebff606af449b455aceff
|
||||
F test/lock3.test f271375930711ae044080f4fe6d6eda930870d00
|
||||
F test/lock4.test c82268c031d39345d05efa672f80b025481b3ae5
|
||||
F test/lock5.test b2abb5e711bc59b0eae00f6c97a36ec9f458fada
|
||||
F test/lock6.test ad5b387a3a8096afd3c68a55b9535056431b0cf5
|
||||
F test/lock5.test d0d313f059ae5661726d3f197ba6ed8f69257d8e
|
||||
F test/lock6.test 83434ae8ca1d1c5e2eaf74d4e44aa24ab62b291c
|
||||
F test/lock7.test 64006c84c1c616657e237c7ad6532b765611cf64
|
||||
F test/lock_common.tcl d279887a0ab16cdb6d935c1203e64113c5a000e9
|
||||
F test/lock_common.tcl 0c270b121d40959fa2f3add382200c27045b3d95
|
||||
F test/lock_proxy.test 95be9c32d79be25cf643b4e41a0aa0e53aa21621
|
||||
F test/lookaside.test 93f07bac140c5bb1d49f3892d2684decafdc7af2
|
||||
F test/main.test 9d7bbfcc1b52c88ba7b2ba6554068ecf9939f252
|
||||
F test/main.test 753e2b772c041bd8dbd17c7e4132b3981378eaab
|
||||
F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
|
||||
F test/malloc.test e56c9c3358da2c18385aea15a42dc970913986c2
|
||||
F test/malloc3.test 4128b1e6ffa506103b278ad97af89174f310c7ca
|
||||
@@ -572,12 +577,12 @@ 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 50d0ed21eed0ae9548b58935bd29ac89a05a54fa
|
||||
F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c
|
||||
F test/malloc_common.tcl 228af61862dd3f61f09dab4251ce3c1660b8b878
|
||||
F test/manydb.test 7faa0df55bbab2b14c25f323801db336c4e7ce3a
|
||||
F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
|
||||
F test/memdb.test 708a028d6d373e5b3842e4bdc8ba80998c9a4da6
|
||||
F test/memdb.test 4aa287fc0c18229086e7c286285d60773f0169c4
|
||||
F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
|
||||
F test/memsubsys1.test 679db68394a5692791737b150852173b3e2fea10
|
||||
F test/memsubsys1.test 7abc5c90b20e25040e2c800e3d95703d59d843a2
|
||||
F test/memsubsys2.test 72a731225997ad5e8df89fdbeae9224616b6aecc
|
||||
F test/minmax.test 722d80816f7e096bf2c04f4111f1a6c1ba65453d
|
||||
F test/minmax2.test 33504c01a03bd99226144e4b03f7631a274d66e0
|
||||
@@ -604,7 +609,7 @@ F test/oserror.test 498d8337e9d15543eb7b004fef8594bf204ff43c
|
||||
F test/pager1.test 8baf4470b29511503abcaf1f17d16b16462e4d54
|
||||
F test/pager2.test 745b911dde3d1f24ae0870bd433dfa83d7c658c1
|
||||
F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f
|
||||
F test/pagerfault.test 9de4d3e0c59970b4c6cb8dac511fa242f335d8a7
|
||||
F test/pagerfault.test bea066b9162e1ab6843c2c1524ebb0965715e956
|
||||
F test/pagerfault2.test 1f79ea40d1133b2683a2f811b00f2399f7ec2401
|
||||
F test/pagerfault3.test f16e2efcb5fc9996d1356f7cbc44c998318ae1d7
|
||||
F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806
|
||||
@@ -612,7 +617,7 @@ F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb
|
||||
F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16
|
||||
F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16
|
||||
F test/permutations.test 5b2a4cb756ffb2407cb4743163668d1d769febb6
|
||||
F test/pragma.test fdfc09067ea104a0c247a1a79d8093b56656f850
|
||||
F test/pragma.test 88048136eed6baa2097dd7ab5145d3288128ca70
|
||||
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
|
||||
F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
|
||||
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
|
||||
@@ -654,7 +659,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 7f6ad2d857d0f4e5d6a0b9a897b5e56a6b6ea18c
|
||||
F test/shared3.test d69bdd5f156580876c5345652d21dc2092e85962
|
||||
F test/shared4.test d0fadacb50bb6981b2fb9dc6d1da30fa1edddf83
|
||||
@@ -677,7 +682,7 @@ F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/sqllimits1.test e90a0ed94452076f6a10209d378e06b5f75ef0a0
|
||||
F test/stat.test c7b20ea43003dc2dc33335e231c27be8284c4a2a
|
||||
F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9
|
||||
F test/stmt.test 78a6764439cfa5abdcbf98d4d084739e81eeec4f
|
||||
F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796
|
||||
F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
|
||||
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
@@ -688,10 +693,10 @@ F test/sysfault.test c79441d88d23696fbec7b147dba98d42a04f523f
|
||||
F test/table.test 04ba066432430657712d167ebf28080fe878d305
|
||||
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
|
||||
F test/tclsqlite.test 8c154101e704170c2be10f137a5499ac2c6da8d3
|
||||
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
|
||||
F test/tempdb.test 3263e5c3f0604e54d307481e8587327c54544d18
|
||||
F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a
|
||||
F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05
|
||||
F test/tester.tcl a791ee74cb6b8f8613079ccc018bf2c8b952a26c
|
||||
F test/tester.tcl 51d761878d9934e19fc0eda3c9c5dbc39d02522d
|
||||
F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f
|
||||
F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db
|
||||
F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca
|
||||
@@ -782,7 +787,7 @@ F test/tkt3357.test 77c37c6482b526fe89941ce951c22d011f5922ed
|
||||
F test/tkt3419.test 1bbf36d7ea03b638c15804251287c2391f5c1f6b
|
||||
F test/tkt3424.test 61f831bd2b071bd128fa5d00fbda57e656ca5812
|
||||
F test/tkt3442.test 0adb70e9fe9cb750a702065a68ad647409dbc158
|
||||
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
|
||||
@@ -869,26 +874,27 @@ 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 5617ad308bfdb8a8885220d8a261a6096a8d7e57
|
||||
F test/wal2.test aa0fb2314b3235be4503c06873e41ebfc0757782
|
||||
F test/wal3.test 5c396cc22497244d627306f4c1d360167353f8dd
|
||||
F test/wal4.test 3404b048fa5e10605facaf70384e6d2943412e30
|
||||
F test/wal.test 3ff610479cd005117f54a8c003a8d86432e6f2ac
|
||||
F test/wal2.test 24239bb8cd8ca5e47c9ab4ac705f7343d2f9b5a2
|
||||
F test/wal3.test 34c65b1cb78e1da5d24c9ab74534c376784f96ea
|
||||
F test/wal4.test 6a68c45bc1ca24a3592ec449ddcb92b29d0e0e87
|
||||
F test/wal5.test 1bbfaa316dc2a1d0d1fac3f4500c38a90055a41b
|
||||
F test/wal6.test 07aa31ca8892d0527f2c5c5a9a2a87aa421dfaa8
|
||||
F test/wal7.test 09bc8de3d11949571d6f7a4188b308059cec27e5
|
||||
F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe
|
||||
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 58fce626359c9376fe35101b5c0f2df8040aa839
|
||||
F test/walhook.test ed00a40ba7255da22d6b66433ab61fab16a63483
|
||||
F test/walmode.test 22ddccd073c817ac9ead62b88ac446e8dedc7d2c
|
||||
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 7db81f3dac64ce8897196f199c2909078bcabf8d
|
||||
F test/walhook.test c934ac5219fee2b4e7653d291db9107b8dc73bba
|
||||
F test/walmode.test feb39956ec6f415fbb9dcb12d91243391c2c4715
|
||||
F test/walnoshm.test a074428046408f4eb5c6a00e09df8cc97ff93317
|
||||
F test/walshared.test 6dda2293880c300baf5d791c307f653094585761
|
||||
F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
|
||||
F test/walthread.test a25a393c068a2b42b44333fa3fdaae9072f1617c
|
||||
F test/walro.test 1f15853383a976ff8bbec78dd44bc15c4e237392
|
||||
F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
|
||||
F test/walslow.test 989854bc5c214700a9f2d545bb158643813b8881
|
||||
F test/walthread.test e6e32e93ccebfa401dfc0dd930c79daa3472b0ae
|
||||
F test/where.test de337a3fe0a459ec7c93db16a519657a90552330
|
||||
F test/where2.test 43d4becaf5a5df854e6c21d624a1cb84c6904554
|
||||
F test/where3.test 8e1175c7ef710c70502858fc4fb08d784b3620b9
|
||||
@@ -913,7 +919,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 623e26cc8c83322e4151d3ad85ac69d41221bae8
|
||||
F tool/mksqlite3c.tcl 98afd75c54489dd27b505fca45e3cc6943cb2409
|
||||
F tool/mksqlite3h.tcl d76c226a5e8e1f3b5f6593bcabe5e98b3b1ec9ff
|
||||
F tool/mksqlite3internalh.tcl 7b43894e21bcb1bb39e11547ce7e38a063357e87
|
||||
F tool/omittest.tcl b1dd290c1596e0f31fd335160a74ec5dfea3df4a
|
||||
@@ -938,7 +944,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P de58cb28387f44c35b1a81bdab853cafd938c1a6
|
||||
R e623b89a5e0b9474dd0884ecf24382fc
|
||||
P 97b980107676b2ea45a07c9c1a7de2e1ca74881f 8d1a6bb002a7817fa7df932f7cab7220c1d62c0e
|
||||
R 55067a82132bcf8831d179c443db5e2f
|
||||
U drh
|
||||
Z 83669a82fd950b01af57955dbca1c918
|
||||
Z 198f0d0d11e8401dbdcd4eff7ec30af8
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
67bf1c9a888b0d84d252d6c4c754c2c51994d208
|
||||
5791232778c825ec487a06c72b638dcb247cdd58
|
||||
+4
-2
@@ -76,6 +76,8 @@ static void attachFunc(
|
||||
Db *aNew;
|
||||
char *zErrDyn = 0;
|
||||
sqlite3_vfs *pVfs;
|
||||
const char *zVfs = db->pVfs->zName; /* Name of default (main) VFS */
|
||||
int btflags = 0;
|
||||
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
|
||||
@@ -129,7 +131,7 @@ static void attachFunc(
|
||||
** or may not be initialised.
|
||||
*/
|
||||
flags = db->openFlags;
|
||||
rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr);
|
||||
rc = sqlite3ParseUri(zVfs, zFile, &flags, &btflags, &pVfs, &zPath, &zErr);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
|
||||
sqlite3_result_error(context, zErr, -1);
|
||||
@@ -138,7 +140,7 @@ static void attachFunc(
|
||||
}
|
||||
assert( pVfs );
|
||||
flags |= SQLITE_OPEN_MAIN_DB;
|
||||
rc = sqlite3BtreeOpen(pVfs, zPath, db, &aNew->pBt, 0, flags);
|
||||
rc = sqlite3BtreeOpen(pVfs, zPath, db, &aNew->pBt, btflags, flags);
|
||||
sqlite3_free( zPath );
|
||||
db->nDb++;
|
||||
if( rc==SQLITE_CONSTRAINT ){
|
||||
|
||||
@@ -61,6 +61,7 @@ int sqlite3BtreeOpen(
|
||||
#define BTREE_MEMORY 4 /* This is an in-memory DB */
|
||||
#define BTREE_SINGLE 8 /* The file contains at most 1 b-tree */
|
||||
#define BTREE_UNORDERED 16 /* Use of a hash implementation is OK */
|
||||
#define BTREE_READONLYSHM 32 /* Read-only SHM access is acceptable */
|
||||
|
||||
int sqlite3BtreeClose(Btree*);
|
||||
int sqlite3BtreeSetCacheSize(Btree*,int);
|
||||
|
||||
@@ -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 ){
|
||||
|
||||
+41
-2
@@ -16,6 +16,9 @@
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
#ifdef SQLITE_ENABLE_SQLRR
|
||||
# include "sqlrr.h"
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_FTS3
|
||||
# include "fts3.h"
|
||||
#endif
|
||||
@@ -801,6 +804,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;
|
||||
}
|
||||
@@ -1789,6 +1796,12 @@ int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
|
||||
}
|
||||
return oldLimit; /* IMP: R-53341-35419 */
|
||||
}
|
||||
#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 function is used to parse both URIs and non-URI filenames passed by the
|
||||
@@ -1803,6 +1816,11 @@ int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
|
||||
** *pFlags may be updated before returning if the URI filename contains
|
||||
** "cache=xxx" or "mode=xxx" query parameters.
|
||||
**
|
||||
** The third argument, pBtflags, points to an integer containing the flags
|
||||
** that will be passed as the 5th argument to sqlite3BtreeOpen (BTREE_XXX
|
||||
** flags). This value will be edited if the URI filename contains a
|
||||
** "readonly_shm=1" or "readonly_shm=0" query parameter.
|
||||
**
|
||||
** If successful, SQLITE_OK is returned. In this case *ppVfs is set to point to
|
||||
** the VFS that should be used to open the database file. *pzFile is set to
|
||||
** point to a buffer containing the name of the file to open. It is the
|
||||
@@ -1818,6 +1836,7 @@ int sqlite3ParseUri(
|
||||
const char *zDefaultVfs, /* VFS to use if no "vfs=xxx" query option */
|
||||
const char *zUri, /* Nul-terminated URI to parse */
|
||||
unsigned int *pFlags, /* IN/OUT: SQLITE_OPEN_XXX flags */
|
||||
int *pBtflags, /* IN/OUT: BTREE_XXX flags */
|
||||
sqlite3_vfs **ppVfs, /* OUT: VFS to use */
|
||||
char **pzFile, /* OUT: Filename component of URI */
|
||||
char **pzErrMsg /* OUT: Error message (if rc!=SQLITE_OK) */
|
||||
@@ -1933,6 +1952,12 @@ int sqlite3ParseUri(
|
||||
|
||||
if( nOpt==3 && memcmp("vfs", zOpt, 3)==0 ){
|
||||
zVfs = zVal;
|
||||
}else if( nOpt==12 && memcmp("readonly_shm", zOpt, 12)==0 ){
|
||||
if( sqlite3Atoi(zVal) ){
|
||||
*pBtflags |= BTREE_READONLYSHM;
|
||||
}else{
|
||||
*pBtflags &= ~BTREE_READONLYSHM;
|
||||
}
|
||||
}else{
|
||||
struct OpenMode {
|
||||
const char *z;
|
||||
@@ -2036,6 +2061,7 @@ static int openDatabase(
|
||||
int isThreadsafe; /* True for threadsafe connections */
|
||||
char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */
|
||||
char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */
|
||||
int btflags = 0; /* Mask of BTREE_XXX flags */
|
||||
|
||||
*ppDb = 0;
|
||||
#ifndef SQLITE_OMIT_AUTOINIT
|
||||
@@ -2164,7 +2190,8 @@ static int openDatabase(
|
||||
|
||||
/* Parse the filename/URI argument. */
|
||||
db->openFlags = flags;
|
||||
rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
|
||||
rc = sqlite3ParseUri(
|
||||
zVfs, zFilename, &flags, &btflags, &db->pVfs, &zOpen, &zErrMsg);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
|
||||
sqlite3Error(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
|
||||
@@ -2173,7 +2200,7 @@ static int openDatabase(
|
||||
}
|
||||
|
||||
/* Open the backend database driver */
|
||||
rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0,
|
||||
rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, btflags,
|
||||
flags | SQLITE_OPEN_MAIN_DB);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc==SQLITE_IOERR_NOMEM ){
|
||||
@@ -2278,7 +2305,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 );
|
||||
assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */
|
||||
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 */
|
||||
|
||||
+336
-22
@@ -212,6 +212,7 @@ struct unixFile {
|
||||
UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
|
||||
const char *zPath; /* Name of the file */
|
||||
unixShm *pShm; /* Shared memory segment information */
|
||||
int readOnlyShm; /* True to open shared-memory read-only */
|
||||
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
|
||||
#if SQLITE_ENABLE_LOCKING_STYLE
|
||||
int openFlags; /* The flags specified at open() */
|
||||
@@ -3144,6 +3145,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
|
||||
@@ -3203,7 +3210,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 = osFsync(fd);
|
||||
if (!rc) {
|
||||
OSSpinLockLock(¬ify_lock);
|
||||
rc = notify_post(REQUEST_FULLSYNC_NOTIFICATION);
|
||||
OSSpinLockUnlock(¬ify_lock);
|
||||
}
|
||||
#else
|
||||
rc = osFcntl(fd, F_FULLFSYNC, 0);
|
||||
#endif
|
||||
}else{
|
||||
rc = 1;
|
||||
}
|
||||
@@ -3432,6 +3448,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.
|
||||
*/
|
||||
@@ -3452,6 +3474,10 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
case SQLITE_FCNTL_SIZE_HINT: {
|
||||
return fcntlSizeHint((unixFile *)id, *(i64 *)pArg);
|
||||
}
|
||||
case SQLITE_FCNTL_READONLY_SHM: {
|
||||
((unixFile*)id)->readOnlyShm = (pArg!=0);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
/* The pager calls this method to signal that it has done
|
||||
** a rollback and that the database is therefore unchanged and
|
||||
@@ -3469,6 +3495,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__) */
|
||||
case SQLITE_FCNTL_SYNC_OMITTED: {
|
||||
return SQLITE_OK; /* A no-op */
|
||||
}
|
||||
@@ -3541,6 +3780,7 @@ struct unixShmNode {
|
||||
char **apRegion; /* Array of mapped shared-memory regions */
|
||||
int nRef; /* Number of unixShm objects pointing to this */
|
||||
unixShm *pFirst; /* All unixShm objects pointing to this */
|
||||
u8 readOnly; /* True if this is a read-only mapping */
|
||||
#ifdef SQLITE_DEBUG
|
||||
u8 exclMask; /* Mask of exclusive locks held */
|
||||
u8 sharedMask; /* Mask of shared locks held */
|
||||
@@ -3683,6 +3923,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.
|
||||
@@ -3751,10 +3994,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 ){
|
||||
@@ -3768,7 +4025,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);
|
||||
sqlite3FileSuffix3(pDbFd->zPath, zShmFilename);
|
||||
#endif
|
||||
pShmNode->h = -1;
|
||||
@@ -3781,29 +4038,48 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
||||
}
|
||||
|
||||
if( pInode->bProcessLock==0 ){
|
||||
pShmNode->h = robust_open(zShmFilename, O_RDWR|O_CREAT,
|
||||
(sStat.st_mode & 0777));
|
||||
int flags = (pDbFd->readOnlyShm ? O_RDONLY : O_RDWR|O_CREAT);
|
||||
pShmNode->h = robust_open(zShmFilename, flags, (sStat.st_mode & 0777));
|
||||
if( pShmNode->h<0 ){
|
||||
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
|
||||
goto shm_open_err;
|
||||
}
|
||||
pShmNode->readOnly = pDbFd->readOnlyShm;
|
||||
|
||||
/* Check to see if another process is holding the dead-man switch.
|
||||
** If not, truncate the file to zero length.
|
||||
*/
|
||||
rc = SQLITE_OK;
|
||||
if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
|
||||
if( robust_ftruncate(pShmNode->h, 0) ){
|
||||
rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
|
||||
** If not, zero the first few bytes of the shared-memory file to make
|
||||
** sure it is not mistaken for valid by code in wal.c. Except, if this
|
||||
** is a read-only connection to the shared-memory then it is not possible
|
||||
** to check check if another process is holding a read-lock on the DMS
|
||||
** byte, as we cannot attempt a write-lock via a read-only file
|
||||
** descriptor. So in this case, we just assume the shared-memory
|
||||
** contents are Ok and proceed. */
|
||||
if( pShmNode->readOnly==0 ){
|
||||
rc = SQLITE_OK;
|
||||
if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
|
||||
if( pDbFd->readOnlyShm ){
|
||||
rc = SQLITE_IOERR_SHMOPEN;
|
||||
}else if( 4!=osWrite(pShmNode->h, "\00\00\00\00", 4) ){
|
||||
rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1);
|
||||
}
|
||||
if( rc ) goto shm_open_err;
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1);
|
||||
}
|
||||
if( rc ) goto shm_open_err;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the unixShmNode is read-only, but SQLITE_FCNTL_READONLY_SHM has not
|
||||
** been set for file-descriptor pDbFd, return an error. The wal.c module
|
||||
** will then call this function again with SQLITE_FCNTL_READONLY_SHM set.
|
||||
*/
|
||||
else if( pShmNode->readOnly && !pDbFd->readOnlyShm ){
|
||||
rc = SQLITE_IOERR_SHMOPEN;
|
||||
goto shm_open_err;
|
||||
}
|
||||
|
||||
/* Make the new connection a child of the unixShmNode */
|
||||
p->pShmNode = pShmNode;
|
||||
#ifdef SQLITE_DEBUG
|
||||
@@ -3924,7 +4200,7 @@ static int unixShmMap(
|
||||
while(pShmNode->nRegion<=iRegion){
|
||||
void *pMem;
|
||||
if( pShmNode->h>=0 ){
|
||||
pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE,
|
||||
pMem = mmap(0, szRegion, PROT_READ|(!pShmNode->readOnly?PROT_WRITE:0),
|
||||
MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion
|
||||
);
|
||||
if( pMem==MAP_FAILED ){
|
||||
@@ -4292,7 +4568,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 */
|
||||
@@ -5050,6 +5326,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
|
||||
@@ -5088,13 +5367,19 @@ static int unixOpen(
|
||||
rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock,
|
||||
isDelete, isReadonly);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -5690,6 +5975,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.
|
||||
@@ -5741,6 +6048,7 @@ static int proxyCreateUnixFile(
|
||||
terrno = errno;
|
||||
}
|
||||
if( fd<0 ){
|
||||
sqlite3_free(pUnused);
|
||||
if( islockfile ){
|
||||
return SQLITE_BUSY;
|
||||
}
|
||||
@@ -6293,7 +6601,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
|
||||
@@ -6332,7 +6640,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{
|
||||
@@ -6375,6 +6683,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 ){
|
||||
@@ -6414,7 +6725,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 ){
|
||||
@@ -6430,10 +6741,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 */
|
||||
|
||||
+5
-2
@@ -620,6 +620,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 readOnlyShm; /* True if read-only shm access is Ok */
|
||||
|
||||
/**************************************************************************
|
||||
** The following block contains those class members that change during
|
||||
@@ -3017,6 +3018,7 @@ static int pagerWalFrames(
|
||||
static int pagerBeginReadTransaction(Pager *pPager){
|
||||
int rc; /* Return code */
|
||||
int changed = 0; /* True if cache must be reset */
|
||||
Wal *pWal = pPager->pWal;
|
||||
|
||||
assert( pagerUseWal(pPager) );
|
||||
assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER );
|
||||
@@ -3026,9 +3028,9 @@ static int pagerBeginReadTransaction(Pager *pPager){
|
||||
** are in locking_mode=NORMAL and EndRead() was previously called,
|
||||
** the duplicate call is harmless.
|
||||
*/
|
||||
sqlite3WalEndReadTransaction(pPager->pWal);
|
||||
sqlite3WalEndReadTransaction(pWal);
|
||||
|
||||
rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed);
|
||||
rc = sqlite3WalBeginReadTransaction(pWal, pPager->readOnlyShm, &changed);
|
||||
if( rc!=SQLITE_OK || changed ){
|
||||
pager_reset(pPager);
|
||||
}
|
||||
@@ -4416,6 +4418,7 @@ int sqlite3PagerOpen(
|
||||
}
|
||||
pPager->pVfs = pVfs;
|
||||
pPager->vfsFlags = vfsFlags;
|
||||
pPager->readOnlyShm = (flags & PAGER_READONLYSHM)!=0;
|
||||
|
||||
/* Open the pager file.
|
||||
*/
|
||||
|
||||
@@ -60,6 +60,7 @@ typedef struct PgHdr DbPage;
|
||||
#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
|
||||
#define PAGER_NO_READLOCK 0x0002 /* Omit readlocks on readonly files */
|
||||
#define PAGER_MEMORY 0x0004 /* In-memory database */
|
||||
#define PAGER_READONLYSHM 0x0020 /* Read-only SHM access is acceptable */
|
||||
|
||||
/*
|
||||
** Valid values for the second argument to sqlite3PagerLockingMode().
|
||||
|
||||
+23
-17
@@ -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);
|
||||
@@ -210,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 ){
|
||||
@@ -407,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,7 +431,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 = sqlite3GetBoolean(zRight);
|
||||
@@ -442,7 +443,7 @@ void sqlite3Pragma(
|
||||
}
|
||||
}
|
||||
b = sqlite3BtreeSecureDelete(pBt, b);
|
||||
returnSingleInt(pParse, "secure_delete", b);
|
||||
returnSingleInt(pParse, "secure_delete", &b);
|
||||
}else
|
||||
|
||||
/*
|
||||
@@ -584,7 +585,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 */
|
||||
@@ -604,13 +605,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 );
|
||||
@@ -693,7 +694,8 @@ void sqlite3Pragma(
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
if( !zRight ){
|
||||
returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
|
||||
i64 cacheSize = pDb->pSchema->cache_size;
|
||||
returnSingleInt(pParse, "cache_size", &cacheSize);
|
||||
}else{
|
||||
int size = sqlite3AbsInt32(sqlite3Atoi(zRight));
|
||||
pDb->pSchema->cache_size = size;
|
||||
@@ -714,7 +716,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);
|
||||
}
|
||||
@@ -828,7 +831,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,
|
||||
@@ -1421,12 +1425,14 @@ void sqlite3Pragma(
|
||||
** of N.
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft, "wal_autocheckpoint")==0 ){
|
||||
i64 walArg = 0;
|
||||
if( zRight ){
|
||||
sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight));
|
||||
}
|
||||
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
|
||||
|
||||
|
||||
+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
|
||||
@@ -759,6 +762,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;
|
||||
}
|
||||
@@ -771,6 +777,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;
|
||||
}
|
||||
@@ -806,7 +815,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
|
||||
|
||||
+42
-1
@@ -455,6 +455,9 @@ int sqlite3_exec(
|
||||
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
|
||||
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
|
||||
|
||||
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
|
||||
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
|
||||
|
||||
/*
|
||||
** CAPI3REF: Flags For File Open Operations
|
||||
**
|
||||
@@ -734,6 +737,27 @@ struct sqlite3_io_methods {
|
||||
** Applications should not call [sqlite3_file_control()] with this
|
||||
** opcode as doing so may disrupt the operation of the specialized VFSes
|
||||
** that do require it.
|
||||
**
|
||||
** The [SQLITE_FCNTL_READONLY_SHM] may be generated internally by SQLite if
|
||||
** the "readonly_shm=1" URI option is specified when the database is opened.
|
||||
** The fourth argument passed to the VFS xFileControl methods is a pointer
|
||||
** to a variable of type "int" containing the value 1 or 0. If the variable
|
||||
** contains the value 1, then this indicates to the VFS that a read-only
|
||||
** mapping of the shared-memory region is acceptable. If it is set to 0, then
|
||||
** this indicates that a read-write mapping is required (as normal). If
|
||||
** a read-only mapping is returned, then the VFS may also return read-only
|
||||
** mappings for any subsequent requests via the same file-descriptor -
|
||||
** regardless of the value most recently configured using
|
||||
** SQLITE_FCNTL_READONLY_SHM.
|
||||
**
|
||||
** In practice, if "readonly_shm=1" is specified and the first attempt to
|
||||
** map a shared-memory region fails, then this file-control is invoked with
|
||||
** the argument variable set to 1 and a second attempt to map the shared-memory
|
||||
** region is made. If this mapping succeeds, then the connection continues
|
||||
** with the read-only mapping. Otherwise, if it fails, SQLITE_CANTOPEN is
|
||||
** returned to the caller. Whether or not the second (read-only) mapping
|
||||
** attempt succeeds, the file-control is invoked again with the argument
|
||||
** variable set to 0.
|
||||
*/
|
||||
#define SQLITE_FCNTL_LOCKSTATE 1
|
||||
#define SQLITE_GET_LOCKPROXYFILE 2
|
||||
@@ -743,6 +767,7 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_FCNTL_CHUNK_SIZE 6
|
||||
#define SQLITE_FCNTL_FILE_POINTER 7
|
||||
#define SQLITE_FCNTL_SYNC_OMITTED 8
|
||||
#define SQLITE_FCNTL_READONLY_SHM 9
|
||||
|
||||
|
||||
/*
|
||||
@@ -2456,7 +2481,7 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
||||
** [[core URI query parameters]]
|
||||
** The query component of a URI may contain parameters that are interpreted
|
||||
** either by SQLite itself, or by a [VFS | custom VFS implementation].
|
||||
** SQLite interprets the following three query parameters:
|
||||
** SQLite interprets the following four query parameters:
|
||||
**
|
||||
** <ul>
|
||||
** <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of
|
||||
@@ -2488,6 +2513,22 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
||||
** ^If sqlite3_open_v2() is used and the "cache" parameter is present in
|
||||
** a URI filename, its value overrides any behaviour requested by setting
|
||||
** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
|
||||
**
|
||||
** <li> <b>readonly_shm</b>: ^The readonly_shm parameter may be set to
|
||||
** either "1" or "0". Setting it to "1" indicates that if the database
|
||||
** is in WAL mode and read-write access to the associated shared
|
||||
** memory region cannot be obtained, then an attempt should be made to open
|
||||
** the shared-memory in read-only mode instead. If there exist one or
|
||||
** more other database clients that have read-write connections to the
|
||||
** database shared-memory, then a read-only shared-memory connection works
|
||||
** fine. However, if there exist no clients with read-write connections
|
||||
** to the shared-memory and the most recent such crashed or was interrupted
|
||||
** by a power failure, then it is possible for a database client using a
|
||||
** read-only connection to return incorrect data, incorrectly report
|
||||
** database corruption, or return an SQLITE_READONLY error. Or if the
|
||||
** most recent read-write connection shut down cleanly, it may not be
|
||||
** possible to open the shared-memory in read-only mode at all, and SQLite
|
||||
** will return SQLITE_CANTOPEN.
|
||||
** </ul>
|
||||
**
|
||||
** ^Specifying an unknown parameter in the query component of a URI is not an
|
||||
|
||||
@@ -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
|
||||
+1
-1
@@ -2673,7 +2673,7 @@ void sqlite3AddColumnType(Parse*,Token*);
|
||||
void sqlite3AddDefaultValue(Parse*,ExprSpan*);
|
||||
void sqlite3AddCollateType(Parse*, Token*);
|
||||
void sqlite3EndTable(Parse*,Token*,Token*,Select*);
|
||||
int sqlite3ParseUri(const char*,const char*,unsigned int*,
|
||||
int sqlite3ParseUri(const char*,const char*,unsigned int*,int*,
|
||||
sqlite3_vfs**,char**,char **);
|
||||
|
||||
Bitvec *sqlite3BitvecCreate(u32);
|
||||
|
||||
+114
-1
@@ -163,8 +163,9 @@ const char *sqlite3TestErrorName(int rc){
|
||||
case SQLITE_IOERR_CHECKRESERVEDLOCK:
|
||||
zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break;
|
||||
case SQLITE_IOERR_LOCK: zName = "SQLITE_IOERR_LOCK"; break;
|
||||
case SQLITE_READONLY_RECOVERY: zName = "SQLITE_READONLY_RECOVERY"; break;
|
||||
case SQLITE_READONLY_CANTLOCK: zName = "SQLITE_READONLY_CANTLOCK"; break;
|
||||
case SQLITE_CORRUPT_VTAB: zName = "SQLITE_CORRUPT_VTAB"; break;
|
||||
zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break;
|
||||
default: zName = "SQLITE_Unknown"; break;
|
||||
}
|
||||
return zName;
|
||||
@@ -3407,6 +3408,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
|
||||
*/
|
||||
@@ -5095,6 +5114,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
|
||||
@@ -5658,6 +5768,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 },
|
||||
@@ -5750,6 +5861,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "file_control_sizehint_test", file_control_sizehint_test, 0 },
|
||||
{ "sqlite3_vfs_list", vfs_list, 0 },
|
||||
{ "sqlite3_create_function_v2", test_create_function_v2, 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. */
|
||||
|
||||
@@ -552,6 +552,22 @@ 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; \
|
||||
|
||||
+1
-1
@@ -578,7 +578,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{
|
||||
@@ -70,6 +74,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;
|
||||
@@ -100,6 +107,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);
|
||||
@@ -118,7 +128,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++){
|
||||
@@ -1062,11 +1079,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);
|
||||
@@ -1075,11 +1098,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);
|
||||
@@ -1090,6 +1119,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);
|
||||
@@ -1103,6 +1135,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
|
||||
@@ -1113,6 +1148,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 */
|
||||
@@ -1136,6 +1174,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;
|
||||
@@ -1150,6 +1191,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);
|
||||
|
||||
@@ -406,6 +406,14 @@ struct WalCkptInfo {
|
||||
/*
|
||||
** An open write-ahead log file is represented by an instance of the
|
||||
** following object.
|
||||
**
|
||||
** The readOnlyShm variable is normally set to 0. If it is set to 1, then
|
||||
** the connection to shared-memory is read-only. This means it cannot
|
||||
** be written at all (even when read-locking the database). If it is set
|
||||
** to 2, then the shared-memory region is not yet open, but a read-only
|
||||
** connection is acceptable. In this case when the shared-memory is opened
|
||||
** (see function walIndexPage()), readOnlyShm is set to either 0 or 1 as
|
||||
** appropriate.
|
||||
*/
|
||||
struct Wal {
|
||||
sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */
|
||||
@@ -421,6 +429,7 @@ struct Wal {
|
||||
u8 writeLock; /* True if in a write transaction */
|
||||
u8 ckptLock; /* True if holding a checkpoint lock */
|
||||
u8 readOnly; /* True if the WAL file is open read-only */
|
||||
u8 readOnlyShm; /* True if the SHM file is open read-only */
|
||||
WalIndexHdr hdr; /* Wal-index header for current transaction */
|
||||
const char *zWalName; /* Name of WAL file */
|
||||
u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
|
||||
@@ -529,11 +538,23 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
|
||||
rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
|
||||
pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
|
||||
);
|
||||
if( rc==SQLITE_CANTOPEN && pWal->readOnlyShm>1 ){
|
||||
assert( iPage==0 );
|
||||
sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_READONLY_SHM, (void*)1);
|
||||
rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
|
||||
pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
pWal->readOnly = pWal->readOnlyShm = 1;
|
||||
}
|
||||
sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_READONLY_SHM, (void*)0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*ppPage = pWal->apWiData[iPage];
|
||||
|
||||
assert( iPage==0 || *ppPage || rc!=SQLITE_OK );
|
||||
if( pWal->readOnlyShm>1 ) pWal->readOnlyShm = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -773,6 +794,7 @@ static void walUnlockShared(Wal *pWal, int lockIdx){
|
||||
}
|
||||
static int walLockExclusive(Wal *pWal, int lockIdx, int n){
|
||||
int rc;
|
||||
assert( pWal->readOnlyShm==0 );
|
||||
if( pWal->exclusiveMode ) return SQLITE_OK;
|
||||
rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
|
||||
SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
|
||||
@@ -782,6 +804,7 @@ static int walLockExclusive(Wal *pWal, int lockIdx, int n){
|
||||
return rc;
|
||||
}
|
||||
static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
|
||||
assert( pWal->readOnlyShm==0 );
|
||||
if( pWal->exclusiveMode ) return;
|
||||
(void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
|
||||
SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE);
|
||||
@@ -1057,6 +1080,7 @@ static int walIndexRecover(Wal *pWal){
|
||||
assert( WAL_ALL_BUT_WRITE==WAL_WRITE_LOCK+1 );
|
||||
assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE );
|
||||
assert( pWal->writeLock );
|
||||
assert( pWal->readOnlyShm==0 );
|
||||
iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
|
||||
nLock = SQLITE_SHM_NLOCK - iLock;
|
||||
rc = walLockExclusive(pWal, iLock, nLock);
|
||||
@@ -1905,6 +1929,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
|
||||
return rc;
|
||||
};
|
||||
assert( page0 || pWal->writeLock==0 );
|
||||
assert( pWal->readOnlyShm==0 || pWal->readOnlyShm==1 );
|
||||
|
||||
/* If the first page of the wal-index has been mapped, try to read the
|
||||
** wal-index header immediately, without holding any lock. This usually
|
||||
@@ -1914,24 +1939,31 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
|
||||
badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
|
||||
|
||||
/* If the first attempt failed, it might have been due to a race
|
||||
** with a writer. So get a WRITE lock and try again.
|
||||
** with a writer. So lock the WAL_WRITE_LOCK byte and try again.
|
||||
*/
|
||||
assert( badHdr==0 || pWal->writeLock==0 );
|
||||
if( badHdr && SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
|
||||
pWal->writeLock = 1;
|
||||
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
|
||||
badHdr = walIndexTryHdr(pWal, pChanged);
|
||||
if( badHdr ){
|
||||
/* If the wal-index header is still malformed even while holding
|
||||
** a WRITE lock, it can only mean that the header is corrupted and
|
||||
** needs to be reconstructed. So run recovery to do exactly that.
|
||||
*/
|
||||
rc = walIndexRecover(pWal);
|
||||
*pChanged = 1;
|
||||
if( badHdr ){
|
||||
if( pWal->readOnlyShm ){
|
||||
if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
|
||||
walUnlockShared(pWal, WAL_WRITE_LOCK);
|
||||
rc = SQLITE_READONLY_RECOVERY;
|
||||
}
|
||||
}else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
|
||||
pWal->writeLock = 1;
|
||||
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
|
||||
badHdr = walIndexTryHdr(pWal, pChanged);
|
||||
if( badHdr ){
|
||||
/* If the wal-index header is still malformed even while holding
|
||||
** a WRITE lock, it can only mean that the header is corrupted and
|
||||
** needs to be reconstructed. So run recovery to do exactly that.
|
||||
*/
|
||||
rc = walIndexRecover(pWal);
|
||||
*pChanged = 1;
|
||||
}
|
||||
}
|
||||
pWal->writeLock = 0;
|
||||
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
||||
}
|
||||
pWal->writeLock = 0;
|
||||
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
||||
}
|
||||
|
||||
/* If the header is read successfully, check the version number to make
|
||||
@@ -2118,7 +2150,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
||||
}
|
||||
/* There was once an "if" here. The extra "{" is to preserve indentation. */
|
||||
{
|
||||
if( mxReadMark < pWal->hdr.mxFrame || mxI==0 ){
|
||||
if( pWal->readOnlyShm==0 && (mxReadMark < pWal->hdr.mxFrame || mxI==0) ){
|
||||
for(i=1; i<WAL_NREADER; i++){
|
||||
rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -2133,7 +2165,8 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
||||
}
|
||||
if( mxI==0 ){
|
||||
assert( rc==SQLITE_BUSY );
|
||||
return WAL_RETRY;
|
||||
assert( rc==SQLITE_BUSY || (pWal->readOnlyShm && rc==SQLITE_OK) );
|
||||
return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTLOCK;
|
||||
}
|
||||
|
||||
rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
|
||||
@@ -2188,13 +2221,18 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
||||
** Pager layer will use this to know that is cache is stale and
|
||||
** needs to be flushed.
|
||||
*/
|
||||
int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
|
||||
int sqlite3WalBeginReadTransaction(Wal *pWal, int readOnlyShm, int *pChanged){
|
||||
int rc; /* Return code */
|
||||
int cnt = 0; /* Number of TryBeginRead attempts */
|
||||
|
||||
if( pWal->nWiData==0 || pWal->apWiData[0]==0 ){
|
||||
assert( readOnlyShm==0 || readOnlyShm==1 );
|
||||
pWal->readOnlyShm = readOnlyShm*2;
|
||||
}
|
||||
do{
|
||||
rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
|
||||
}while( rc==WAL_RETRY );
|
||||
assert( rc || pWal->readOnlyShm==0 || (readOnlyShm && pWal->readOnlyShm==1) );
|
||||
testcase( (rc&0xff)==SQLITE_BUSY );
|
||||
testcase( (rc&0xff)==SQLITE_IOERR );
|
||||
testcase( rc==SQLITE_PROTOCOL );
|
||||
@@ -2369,6 +2407,7 @@ int sqlite3WalBeginWriteTransaction(Wal *pWal){
|
||||
if( pWal->readOnly ){
|
||||
return SQLITE_READONLY;
|
||||
}
|
||||
assert( pWal->readOnlyShm==0 );
|
||||
|
||||
/* Only one writer allowed at a time. Get the write lock. Return
|
||||
** SQLITE_BUSY if unable.
|
||||
@@ -2774,6 +2813,10 @@ int sqlite3WalCheckpoint(
|
||||
assert( pWal->writeLock==0 );
|
||||
|
||||
WALTRACE(("WAL%p: checkpoint begins\n", pWal));
|
||||
if( pWal->readOnlyShm ){
|
||||
return SQLITE_READONLY;
|
||||
}
|
||||
|
||||
rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
|
||||
if( rc ){
|
||||
/* Usually this is SQLITE_BUSY meaning that another thread or process
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
# define sqlite3WalOpen(x,y,z) 0
|
||||
# define sqlite3WalLimit(x,y)
|
||||
# define sqlite3WalClose(w,x,y,z) 0
|
||||
# define sqlite3WalBeginReadTransaction(y,z) 0
|
||||
# define sqlite3WalBeginReadTransaction(x,y,z) 0
|
||||
# define sqlite3WalEndReadTransaction(z)
|
||||
# define sqlite3WalRead(v,w,x,y,z) 0
|
||||
# define sqlite3WalDbsize(y) 0
|
||||
@@ -60,7 +60,7 @@ void sqlite3WalLimit(Wal*, i64);
|
||||
** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the
|
||||
** transaction and releases the lock.
|
||||
*/
|
||||
int sqlite3WalBeginReadTransaction(Wal *pWal, int *);
|
||||
int sqlite3WalBeginReadTransaction(Wal *pWal, int, int *);
|
||||
void sqlite3WalEndReadTransaction(Wal *pWal);
|
||||
|
||||
/* Read a page from the write-ahead log, if it is present. */
|
||||
|
||||
+18
-17
@@ -718,23 +718,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 @@ sqlite3 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
|
||||
} {}
|
||||
|
||||
@@ -55,8 +55,8 @@ proc do_multiclient_test {varname script} {
|
||||
uplevel set $varname $tn
|
||||
uplevel $script
|
||||
|
||||
code2 { db2 close }
|
||||
code3 { db3 close }
|
||||
catch { code2 { db2 close } }
|
||||
catch { code3 { db3 close } }
|
||||
catch { close $::code2_chan }
|
||||
catch { close $::code3_chan }
|
||||
catch { db close }
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -408,7 +408,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
@@ -407,24 +407,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
|
||||
|
||||
+29
-24
@@ -182,17 +182,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]
|
||||
} 24
|
||||
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
|
||||
@@ -268,19 +271,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
|
||||
|
||||
@@ -1055,6 +1055,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 {
|
||||
list [catch {
|
||||
sqlite3 db test2.db
|
||||
@@ -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 {
|
||||
list [catch {
|
||||
sqlite3 db test2.db
|
||||
@@ -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
|
||||
}
|
||||
|
||||
+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 {
|
||||
@@ -40,16 +51,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 {
|
||||
@@ -57,34 +71,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) }
|
||||
@@ -92,6 +109,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
|
||||
|
||||
+37
-4
@@ -605,11 +605,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}]
|
||||
}
|
||||
@@ -1314,6 +1318,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
|
||||
|
||||
@@ -22,6 +22,10 @@ source $testdir/wal_common.tcl
|
||||
set testprefix wal
|
||||
|
||||
ifcapable !wal {finish_test ; return }
|
||||
if { ![wal_is_ok] } {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
proc reopen_db {} {
|
||||
catch { db close }
|
||||
|
||||
@@ -22,6 +22,10 @@ source $testdir/wal_common.tcl
|
||||
set testprefix wal2
|
||||
|
||||
ifcapable !wal {finish_test ; return }
|
||||
if { ![wal_is_ok] || [path_is_dos "."]} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set sqlite_sync_count 0
|
||||
proc cond_incr_sync_count {adj} {
|
||||
|
||||
+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} {
|
||||
@@ -615,7 +619,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
|
||||
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
# 2011 May 09
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file contains tests for using WAL databases in read-only mode.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
set ::testprefix walro
|
||||
|
||||
|
||||
do_multiclient_test tn {
|
||||
# These tests are only going to work on unix.
|
||||
#
|
||||
if {$tcl_platform(platform) != "unix"} continue
|
||||
|
||||
# Do not run tests with the connections in the same process.
|
||||
#
|
||||
if {$tn==2} continue
|
||||
|
||||
# Close all connections and delete the database.
|
||||
#
|
||||
code1 { db close }
|
||||
code2 { db2 close }
|
||||
code3 { db3 close }
|
||||
forcedelete test.db
|
||||
forcedelete walro
|
||||
|
||||
foreach c {code1 code2 code3} {
|
||||
$c {
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_uri 1
|
||||
}
|
||||
}
|
||||
|
||||
file mkdir walro
|
||||
|
||||
do_test 1.1.1 {
|
||||
code2 { sqlite3 db2 test.db }
|
||||
sql2 {
|
||||
PRAGMA journal_mode = WAL;
|
||||
CREATE TABLE t1(x, y);
|
||||
INSERT INTO t1 VALUES('a', 'b');
|
||||
}
|
||||
file exists test.db-shm
|
||||
} {1}
|
||||
|
||||
do_test 1.1.2 {
|
||||
file attributes test.db-shm -permissions r--r--r--
|
||||
code1 { sqlite3 db file:test.db?readonly_shm=1 }
|
||||
} {}
|
||||
|
||||
do_test 1.1.3 { sql1 "SELECT * FROM t1" } {a b}
|
||||
do_test 1.1.4 { sql2 "INSERT INTO t1 VALUES('c', 'd')" } {}
|
||||
do_test 1.1.5 { sql1 "SELECT * FROM t1" } {a b c d}
|
||||
|
||||
# Check that the read-only connection cannot write or checkpoint the db.
|
||||
#
|
||||
do_test 1.1.6 {
|
||||
csql1 "INSERT INTO t1 VALUES('e', 'f')"
|
||||
} {1 {attempt to write a readonly database}}
|
||||
do_test 1.1.7 {
|
||||
csql1 "PRAGMA wal_checkpoint"
|
||||
} {1 {attempt to write a readonly database}}
|
||||
|
||||
do_test 1.1.9 { sql2 "INSERT INTO t1 VALUES('e', 'f')" } {}
|
||||
do_test 1.1.10 { sql1 "SELECT * FROM t1" } {a b c d e f}
|
||||
|
||||
do_test 1.1.11 {
|
||||
sql2 {
|
||||
INSERT INTO t1 VALUES('g', 'h');
|
||||
PRAGMA wal_checkpoint;
|
||||
}
|
||||
set {} {}
|
||||
} {}
|
||||
do_test 1.1.12 { sql1 "SELECT * FROM t1" } {a b c d e f g h}
|
||||
do_test 1.1.13 { sql2 "INSERT INTO t1 VALUES('i', 'j')" } {}
|
||||
|
||||
do_test 1.2.1 {
|
||||
code2 { db2 close }
|
||||
code1 { db close }
|
||||
list [file exists test.db-wal] [file exists test.db-shm]
|
||||
} {1 1}
|
||||
do_test 1.2.2 {
|
||||
code1 { sqlite3 db file:test.db?readonly_shm=1 }
|
||||
sql1 { SELECT * FROM t1 }
|
||||
} {a b c d e f g h i j}
|
||||
|
||||
do_test 1.2.3 {
|
||||
code1 { db close }
|
||||
file attributes test.db-shm -permissions rw-r--r--
|
||||
hexio_write test.db-shm 0 01020304
|
||||
file attributes test.db-shm -permissions r--r--r--
|
||||
code1 { sqlite3 db file:test.db?readonly_shm=1 }
|
||||
csql1 { SELECT * FROM t1 }
|
||||
} {1 {attempt to write a readonly database}}
|
||||
do_test 1.2.4 {
|
||||
code1 { sqlite3_extended_errcode db }
|
||||
} {SQLITE_READONLY_RECOVERY}
|
||||
|
||||
do_test 1.2.5 {
|
||||
file attributes test.db-shm -permissions rw-r--r--
|
||||
code2 { sqlite3 db2 test.db }
|
||||
sql2 "SELECT * FROM t1"
|
||||
} {a b c d e f g h i j}
|
||||
file attributes test.db-shm -permissions r--r--r--
|
||||
do_test 1.2.6 { sql1 "SELECT * FROM t1" } {a b c d e f g h i j}
|
||||
|
||||
do_test 1.2.7 {
|
||||
sql2 {
|
||||
PRAGMA wal_checkpoint;
|
||||
INSERT INTO t1 VALUES('k', 'l');
|
||||
}
|
||||
set {} {}
|
||||
} {}
|
||||
do_test 1.2.8 { sql1 "SELECT * FROM t1" } {a b c d e f g h i j k l}
|
||||
|
||||
# Now check that if the readonly_shm option is not supplied, or if it
|
||||
# is set to zero, it is not possible to connect to the database without
|
||||
# read-write access to the shm.
|
||||
do_test 1.3.1 {
|
||||
code1 { db close }
|
||||
code1 { sqlite3 db test.db }
|
||||
csql1 { SELECT * FROM t1 }
|
||||
} {1 {unable to open database file}}
|
||||
|
||||
# Also test that if the -shm file can be opened for read/write access,
|
||||
# it is, even if readonly_shm=1 is present in the URI.
|
||||
do_test 1.3.2.1 {
|
||||
code1 { db close }
|
||||
code2 { db2 close }
|
||||
file exists test.db-shm
|
||||
} {0}
|
||||
do_test 1.3.2.2 {
|
||||
code1 { sqlite3 db file:test.db?readonly_shm=1 }
|
||||
sql1 { SELECT * FROM t1 }
|
||||
} {a b c d e f g h i j k l}
|
||||
do_test 1.3.2.3 {
|
||||
code1 { db close }
|
||||
close [open test.db-shm w]
|
||||
file attributes test.db-shm -permissions r--r--r--
|
||||
code1 { sqlite3 db file:test.db?readonly_shm=1 }
|
||||
csql1 { SELECT * FROM t1 }
|
||||
} {1 {attempt to write a readonly database}}
|
||||
do_test 1.3.2.4 {
|
||||
code1 { sqlite3_extended_errcode db }
|
||||
} {SQLITE_READONLY_RECOVERY}
|
||||
}
|
||||
|
||||
finish_test
|
||||
@@ -60,4 +60,3 @@ do_test walshared-1.4 {
|
||||
|
||||
sqlite3_enable_shared_cache $::enable_shared_cache
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -306,6 +307,7 @@ foreach file {
|
||||
rtree.c
|
||||
icu.c
|
||||
fts3_icu.c
|
||||
sqlrr.c
|
||||
} {
|
||||
copy_file tsrc/$file
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user