mirror of
https://github.com/sqlite/sqlite.git
synced 2025-10-31 18:11:01 +03:00
Rename files using for testing only so that their name begins with "test". (CVS 3028)
FossilOrigin-Name: e4e6a205e4f7c14aae31f26f42a143fce143db1c
This commit is contained in:
@@ -191,7 +191,6 @@ TESTSRC = \
|
|||||||
$(TOP)/src/pager.c \
|
$(TOP)/src/pager.c \
|
||||||
$(TOP)/src/pragma.c \
|
$(TOP)/src/pragma.c \
|
||||||
$(TOP)/src/printf.c \
|
$(TOP)/src/printf.c \
|
||||||
$(TOP)/src/server.c \
|
|
||||||
$(TOP)/src/test1.c \
|
$(TOP)/src/test1.c \
|
||||||
$(TOP)/src/test2.c \
|
$(TOP)/src/test2.c \
|
||||||
$(TOP)/src/test3.c \
|
$(TOP)/src/test3.c \
|
||||||
@@ -200,10 +199,11 @@ TESTSRC = \
|
|||||||
$(TOP)/src/test6.c \
|
$(TOP)/src/test6.c \
|
||||||
$(TOP)/src/test7.c \
|
$(TOP)/src/test7.c \
|
||||||
$(TOP)/src/test_async.c \
|
$(TOP)/src/test_async.c \
|
||||||
|
$(TOP)/src/test_md5.c \
|
||||||
|
$(TOP)/src/test_server.c \
|
||||||
$(TOP)/src/utf.c \
|
$(TOP)/src/utf.c \
|
||||||
$(TOP)/src/util.c \
|
$(TOP)/src/util.c \
|
||||||
$(TOP)/src/vdbe.c \
|
$(TOP)/src/vdbe.c \
|
||||||
$(TOP)/src/md5.c \
|
|
||||||
$(TOP)/src/where.c
|
$(TOP)/src/where.c
|
||||||
|
|
||||||
# Header files used by all library source files.
|
# Header files used by all library source files.
|
||||||
|
|||||||
6
main.mk
6
main.mk
@@ -129,7 +129,6 @@ TESTSRC = \
|
|||||||
$(TOP)/src/pager.c \
|
$(TOP)/src/pager.c \
|
||||||
$(TOP)/src/pragma.c \
|
$(TOP)/src/pragma.c \
|
||||||
$(TOP)/src/printf.c \
|
$(TOP)/src/printf.c \
|
||||||
$(TOP)/src/server.c \
|
|
||||||
$(TOP)/src/test1.c \
|
$(TOP)/src/test1.c \
|
||||||
$(TOP)/src/test2.c \
|
$(TOP)/src/test2.c \
|
||||||
$(TOP)/src/test3.c \
|
$(TOP)/src/test3.c \
|
||||||
@@ -138,10 +137,11 @@ TESTSRC = \
|
|||||||
$(TOP)/src/test6.c \
|
$(TOP)/src/test6.c \
|
||||||
$(TOP)/src/test7.c \
|
$(TOP)/src/test7.c \
|
||||||
$(TOP)/src/test_async.c \
|
$(TOP)/src/test_async.c \
|
||||||
|
$(TOP)/src/test_md5.c \
|
||||||
|
$(TOP)/src/test_server.c \
|
||||||
$(TOP)/src/utf.c \
|
$(TOP)/src/utf.c \
|
||||||
$(TOP)/src/util.c \
|
$(TOP)/src/util.c \
|
||||||
$(TOP)/src/vdbe.c \
|
$(TOP)/src/vdbe.c \
|
||||||
$(TOP)/src/md5.c \
|
|
||||||
$(TOP)/src/where.c
|
$(TOP)/src/where.c
|
||||||
|
|
||||||
# Header files used by all library source files.
|
# Header files used by all library source files.
|
||||||
@@ -380,7 +380,7 @@ sqlite3_analyzer$(EXE): $(TOP)/src/tclsqlite.c libsqlite3.a $(TESTSRC) \
|
|||||||
-e 's,^,",' \
|
-e 's,^,",' \
|
||||||
-e 's,$$,\\n",' \
|
-e 's,$$,\\n",' \
|
||||||
$(TOP)/tool/spaceanal.tcl >spaceanal_tcl.h
|
$(TOP)/tool/spaceanal.tcl >spaceanal_tcl.h
|
||||||
$(TCCX) $(TCL_FLAGS) -DTCLSH=2 -DSQLITE_TEST=1 -o \
|
$(TCCX) $(TCL_FLAGS) -DTCLSH=2 -DSQLITE_TEST=1 -DSQLITE_DEBUG=1 -o \
|
||||||
sqlite3_analyzer$(EXE) $(TESTSRC) $(TOP)/src/tclsqlite.c \
|
sqlite3_analyzer$(EXE) $(TESTSRC) $(TOP)/src/tclsqlite.c \
|
||||||
libsqlite3.a $(LIBTCL) $(THREADLIB)
|
libsqlite3.a $(LIBTCL) $(THREADLIB)
|
||||||
|
|
||||||
|
|||||||
20
manifest
20
manifest
@@ -1,6 +1,6 @@
|
|||||||
C Handle\serrors\sin\ssaving\scursor\spositions\sduring\sa\srollback\sby\saborting\sall\sactive\sstatements.\s(CVS\s3027)
|
C Rename\sfiles\susing\sfor\stesting\sonly\sso\sthat\stheir\sname\sbegins\swith\s"test".\s(CVS\s3028)
|
||||||
D 2006-01-24T16:37:58
|
D 2006-01-25T15:55:37
|
||||||
F Makefile.in 53841eb72e9eeb6030a8ce28c2595a92f440fd10
|
F Makefile.in e936c6fc3134838318aa0335a85041e6da31f6ee
|
||||||
F Makefile.linux-gcc 74ba0eadf88748a9ce3fd03d2a3ede2e6715baec
|
F Makefile.linux-gcc 74ba0eadf88748a9ce3fd03d2a3ede2e6715baec
|
||||||
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
||||||
F VERSION dd67e1a7f1eae49ac8becb23f04d064c3cae6a5d
|
F VERSION dd67e1a7f1eae49ac8becb23f04d064c3cae6a5d
|
||||||
@@ -19,7 +19,7 @@ F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538
|
|||||||
F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac
|
F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac
|
||||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
||||||
F ltmain.sh f6b283068efa69f06eb8aa1fe4bddfdbdeb35826
|
F ltmain.sh f6b283068efa69f06eb8aa1fe4bddfdbdeb35826
|
||||||
F main.mk 8b8d1c8a21f9a898fbf524d7d5935b823d05a433
|
F main.mk 33144e8ccfa885a4b0c1c03e85131bd6c541f30c
|
||||||
F mkdll.sh 89b5390110c0b7fd93d6c456964c2b9adfcfc339
|
F mkdll.sh 89b5390110c0b7fd93d6c456964c2b9adfcfc339
|
||||||
F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d
|
F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d
|
||||||
F mkopcodeh.awk 071dbba4eaf56c8d643baf4604a043af35683316
|
F mkopcodeh.awk 071dbba4eaf56c8d643baf4604a043af35683316
|
||||||
@@ -68,7 +68,7 @@ F src/printf.c c7d6ad9efb71c466305297a448308f467b6e2b6e
|
|||||||
F src/random.c d40f8d356cecbd351ccfab6eaedd7ec1b54f5261
|
F src/random.c d40f8d356cecbd351ccfab6eaedd7ec1b54f5261
|
||||||
F src/select.c daee9b20702ba51cf3807fc1b130edd8846e3e48
|
F src/select.c daee9b20702ba51cf3807fc1b130edd8846e3e48
|
||||||
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
|
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
|
||||||
F src/shell.c 66b073375efbdee19045e7e0cd38b85f9aff71da
|
F src/shell.c ea0e46545442f9fbb8015afa821259816bfaeb96
|
||||||
F src/sqlite.h.in 492580f7e3ff71eb43193eb7bb98e2d549889ce3
|
F src/sqlite.h.in 492580f7e3ff71eb43193eb7bb98e2d549889ce3
|
||||||
F src/sqliteInt.h 0121298397ac14eb468ab1ba9d488ac7ed7d88a1
|
F src/sqliteInt.h 0121298397ac14eb468ab1ba9d488ac7ed7d88a1
|
||||||
F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316
|
F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316
|
||||||
@@ -81,6 +81,8 @@ F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f
|
|||||||
F src/test6.c 60a02961ceb7b3edc25f5dc5c1ac2556622a76de
|
F src/test6.c 60a02961ceb7b3edc25f5dc5c1ac2556622a76de
|
||||||
F src/test7.c d28d3e62f9594923648fc6a8fb030eba36564ba1
|
F src/test7.c d28d3e62f9594923648fc6a8fb030eba36564ba1
|
||||||
F src/test_async.c 6776f5027ca6378c116ff5ccc2fe41b908e33772
|
F src/test_async.c 6776f5027ca6378c116ff5ccc2fe41b908e33772
|
||||||
|
F src/test_md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217
|
||||||
|
F src/test_server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
|
||||||
F src/tokenize.c 9ae9a59238eb97fbc61baea280563b91100518fb
|
F src/tokenize.c 9ae9a59238eb97fbc61baea280563b91100518fb
|
||||||
F src/trigger.c 4d3644cbd16959b568c95ae73493402be8021b08
|
F src/trigger.c 4d3644cbd16959b568c95ae73493402be8021b08
|
||||||
F src/update.c 14be4ba2f438919b4217085c02feff569e6cf1f2
|
F src/update.c 14be4ba2f438919b4217085c02feff569e6cf1f2
|
||||||
@@ -344,7 +346,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
|
|||||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||||
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
|
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
|
||||||
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
|
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
|
||||||
P 32d45bcf746e7e926b8cc8bd038d66e7c2ec6562
|
P 5df9f022bfb22976f22b996bda169635354b825c
|
||||||
R bfc84cb6ae1c5988a33aa090aaeb35d5
|
R 19654534604b9d6e28fafed119189a39
|
||||||
U danielk1977
|
U drh
|
||||||
Z b319ec5ca674b878a1973ce33be953dd
|
Z cdb7895b465b1a2519023b8ebe746136
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
5df9f022bfb22976f22b996bda169635354b825c
|
e4e6a205e4f7c14aae31f26f42a143fce143db1c
|
||||||
27
src/shell.c
27
src/shell.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains code to implement the "sqlite" command line
|
** This file contains code to implement the "sqlite" command line
|
||||||
** utility for accessing SQLite databases.
|
** utility for accessing SQLite databases.
|
||||||
**
|
**
|
||||||
** $Id: shell.c,v 1.130 2005/12/29 12:53:10 drh Exp $
|
** $Id: shell.c,v 1.131 2006/01/25 15:55:38 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -774,9 +774,6 @@ static char zHelp[] =
|
|||||||
".prompt MAIN CONTINUE Replace the standard prompts\n"
|
".prompt MAIN CONTINUE Replace the standard prompts\n"
|
||||||
".quit Exit this program\n"
|
".quit Exit this program\n"
|
||||||
".read FILENAME Execute SQL in FILENAME\n"
|
".read FILENAME Execute SQL in FILENAME\n"
|
||||||
#ifdef SQLITE_HAS_CODEC
|
|
||||||
".rekey OLD NEW NEW Change the encryption key\n"
|
|
||||||
#endif
|
|
||||||
".schema ?TABLE? Show the CREATE statements\n"
|
".schema ?TABLE? Show the CREATE statements\n"
|
||||||
".separator STRING Change separator used by output mode and .import\n"
|
".separator STRING Change separator used by output mode and .import\n"
|
||||||
".show Show the current values for various settings\n"
|
".show Show the current values for various settings\n"
|
||||||
@@ -796,9 +793,6 @@ static void open_db(struct callback_data *p){
|
|||||||
if( p->db==0 ){
|
if( p->db==0 ){
|
||||||
sqlite3_open(p->zDbFilename, &p->db);
|
sqlite3_open(p->zDbFilename, &p->db);
|
||||||
db = p->db;
|
db = p->db;
|
||||||
#ifdef SQLITE_HAS_CODEC
|
|
||||||
sqlite3_key(p->db, p->zKey, p->zKey ? strlen(p->zKey) : 0);
|
|
||||||
#endif
|
|
||||||
sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0,
|
sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0,
|
||||||
shellstaticFunc, 0, 0);
|
shellstaticFunc, 0, 0);
|
||||||
if( SQLITE_OK!=sqlite3_errcode(db) ){
|
if( SQLITE_OK!=sqlite3_errcode(db) ){
|
||||||
@@ -1227,22 +1221,6 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||||||
}
|
}
|
||||||
}else
|
}else
|
||||||
|
|
||||||
#ifdef SQLITE_HAS_CODEC
|
|
||||||
if( c=='r' && strncmp(azArg[0],"rekey", n)==0 && nArg==4 ){
|
|
||||||
char *zOld = p->zKey;
|
|
||||||
if( zOld==0 ) zOld = "";
|
|
||||||
if( strcmp(azArg[1],zOld) ){
|
|
||||||
fprintf(stderr,"old key is incorrect\n");
|
|
||||||
}else if( strcmp(azArg[2], azArg[3]) ){
|
|
||||||
fprintf(stderr,"2nd copy of new key does not match the 1st\n");
|
|
||||||
}else{
|
|
||||||
sqlite3_free(p->zKey);
|
|
||||||
p->zKey = sqlite3_mprintf("%s", azArg[2]);
|
|
||||||
sqlite3_rekey(p->db, p->zKey, strlen(p->zKey));
|
|
||||||
}
|
|
||||||
}else
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
|
if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
|
||||||
struct callback_data data;
|
struct callback_data data;
|
||||||
char *zErrMsg = 0;
|
char *zErrMsg = 0;
|
||||||
@@ -1620,9 +1598,6 @@ static const char zOptions[] =
|
|||||||
" -[no]header turn headers on or off\n"
|
" -[no]header turn headers on or off\n"
|
||||||
" -column set output mode to 'column'\n"
|
" -column set output mode to 'column'\n"
|
||||||
" -html set output mode to HTML\n"
|
" -html set output mode to HTML\n"
|
||||||
#ifdef SQLITE_HAS_CODEC
|
|
||||||
" -key KEY encryption key\n"
|
|
||||||
#endif
|
|
||||||
" -line set output mode to 'line'\n"
|
" -line set output mode to 'line'\n"
|
||||||
" -list set output mode to 'list'\n"
|
" -list set output mode to 'list'\n"
|
||||||
" -separator 'x' set output field separator (|)\n"
|
" -separator 'x' set output field separator (|)\n"
|
||||||
|
|||||||
387
src/test_md5.c
Normal file
387
src/test_md5.c
Normal file
@@ -0,0 +1,387 @@
|
|||||||
|
/*
|
||||||
|
** SQLite uses this code for testing only. It is not a part of
|
||||||
|
** the SQLite library. This file implements two new TCL commands
|
||||||
|
** "md5" and "md5file" that compute md5 checksums on arbitrary text
|
||||||
|
** and on complete files. These commands are used by the "testfixture"
|
||||||
|
** program to help verify the correct operation of the SQLite library.
|
||||||
|
**
|
||||||
|
** The original use of these TCL commands was to test the ROLLBACK
|
||||||
|
** feature of SQLite. First compute the MD5-checksum of the database.
|
||||||
|
** Then make some changes but rollback the changes rather than commit
|
||||||
|
** them. Compute a second MD5-checksum of the file and verify that the
|
||||||
|
** two checksums are the same. Such is the original use of this code.
|
||||||
|
** New uses may have been added since this comment was written.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* This code implements the MD5 message-digest algorithm.
|
||||||
|
* The algorithm is due to Ron Rivest. This code was
|
||||||
|
* written by Colin Plumb in 1993, no copyright is claimed.
|
||||||
|
* This code is in the public domain; do with it what you wish.
|
||||||
|
*
|
||||||
|
* Equivalent code is available from RSA Data Security, Inc.
|
||||||
|
* This code has been tested against that, and is equivalent,
|
||||||
|
* except that you don't need to include two pages of legalese
|
||||||
|
* with every copy.
|
||||||
|
*
|
||||||
|
* To compute the message digest of a chunk of bytes, declare an
|
||||||
|
* MD5Context structure, pass it to MD5Init, call MD5Update as
|
||||||
|
* needed on buffers full of bytes, and then call MD5Final, which
|
||||||
|
* will fill a supplied 16-byte array with the digest.
|
||||||
|
*/
|
||||||
|
#include <tcl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "sqlite3.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If compiled on a machine that doesn't have a 32-bit integer,
|
||||||
|
* you just set "uint32" to the appropriate datatype for an
|
||||||
|
* unsigned 32-bit integer. For example:
|
||||||
|
*
|
||||||
|
* cc -Duint32='unsigned long' md5.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef uint32
|
||||||
|
# define uint32 unsigned int
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Context {
|
||||||
|
uint32 buf[4];
|
||||||
|
uint32 bits[2];
|
||||||
|
unsigned char in[64];
|
||||||
|
};
|
||||||
|
typedef char MD5Context[88];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: this code is harmless on little-endian machines.
|
||||||
|
*/
|
||||||
|
static void byteReverse (unsigned char *buf, unsigned longs){
|
||||||
|
uint32 t;
|
||||||
|
do {
|
||||||
|
t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
|
||||||
|
((unsigned)buf[1]<<8 | buf[0]);
|
||||||
|
*(uint32 *)buf = t;
|
||||||
|
buf += 4;
|
||||||
|
} while (--longs);
|
||||||
|
}
|
||||||
|
/* The four core functions - F1 is optimized somewhat */
|
||||||
|
|
||||||
|
/* #define F1(x, y, z) (x & y | ~x & z) */
|
||||||
|
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||||
|
#define F2(x, y, z) F1(z, x, y)
|
||||||
|
#define F3(x, y, z) (x ^ y ^ z)
|
||||||
|
#define F4(x, y, z) (y ^ (x | ~z))
|
||||||
|
|
||||||
|
/* This is the central step in the MD5 algorithm. */
|
||||||
|
#define MD5STEP(f, w, x, y, z, data, s) \
|
||||||
|
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The core of the MD5 algorithm, this alters an existing MD5 hash to
|
||||||
|
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||||
|
* the data and converts bytes into longwords for this routine.
|
||||||
|
*/
|
||||||
|
static void MD5Transform(uint32 buf[4], const uint32 in[16]){
|
||||||
|
register uint32 a, b, c, d;
|
||||||
|
|
||||||
|
a = buf[0];
|
||||||
|
b = buf[1];
|
||||||
|
c = buf[2];
|
||||||
|
d = buf[3];
|
||||||
|
|
||||||
|
MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
|
||||||
|
MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
|
||||||
|
MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
|
||||||
|
MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
|
||||||
|
MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
|
||||||
|
MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
|
||||||
|
MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
|
||||||
|
MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
|
||||||
|
MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
|
||||||
|
MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
|
||||||
|
MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
|
||||||
|
MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
|
||||||
|
MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
|
||||||
|
MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
|
||||||
|
MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
|
||||||
|
MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
|
||||||
|
|
||||||
|
MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
|
||||||
|
MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
|
||||||
|
MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
|
||||||
|
MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
|
||||||
|
MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
|
||||||
|
MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
|
||||||
|
MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
|
||||||
|
MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
|
||||||
|
MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
|
||||||
|
MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
|
||||||
|
MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
|
||||||
|
MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
|
||||||
|
MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
|
||||||
|
MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
|
||||||
|
MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
|
||||||
|
MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
|
||||||
|
|
||||||
|
MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
|
||||||
|
MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
|
||||||
|
MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
|
||||||
|
MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
|
||||||
|
MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
|
||||||
|
MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
|
||||||
|
MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
|
||||||
|
MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
|
||||||
|
MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
|
||||||
|
MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
|
||||||
|
MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
|
||||||
|
MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
|
||||||
|
MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
|
||||||
|
MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
|
||||||
|
MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
|
||||||
|
MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
|
||||||
|
|
||||||
|
MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
|
||||||
|
MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
|
||||||
|
MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
|
||||||
|
MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
|
||||||
|
MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
|
||||||
|
MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
|
||||||
|
MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
|
||||||
|
MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
|
||||||
|
MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
|
||||||
|
MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
|
||||||
|
MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
|
||||||
|
MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
|
||||||
|
MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
|
||||||
|
MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
|
||||||
|
MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
|
||||||
|
MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
|
||||||
|
|
||||||
|
buf[0] += a;
|
||||||
|
buf[1] += b;
|
||||||
|
buf[2] += c;
|
||||||
|
buf[3] += d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
||||||
|
* initialization constants.
|
||||||
|
*/
|
||||||
|
static void MD5Init(MD5Context *pCtx){
|
||||||
|
struct Context *ctx = (struct Context *)pCtx;
|
||||||
|
ctx->buf[0] = 0x67452301;
|
||||||
|
ctx->buf[1] = 0xefcdab89;
|
||||||
|
ctx->buf[2] = 0x98badcfe;
|
||||||
|
ctx->buf[3] = 0x10325476;
|
||||||
|
ctx->bits[0] = 0;
|
||||||
|
ctx->bits[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update context to reflect the concatenation of another buffer full
|
||||||
|
* of bytes.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void MD5Update(MD5Context *pCtx, const unsigned char *buf, unsigned int len){
|
||||||
|
struct Context *ctx = (struct Context *)pCtx;
|
||||||
|
uint32 t;
|
||||||
|
|
||||||
|
/* Update bitcount */
|
||||||
|
|
||||||
|
t = ctx->bits[0];
|
||||||
|
if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
|
||||||
|
ctx->bits[1]++; /* Carry from low to high */
|
||||||
|
ctx->bits[1] += len >> 29;
|
||||||
|
|
||||||
|
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
|
||||||
|
|
||||||
|
/* Handle any leading odd-sized chunks */
|
||||||
|
|
||||||
|
if ( t ) {
|
||||||
|
unsigned char *p = (unsigned char *)ctx->in + t;
|
||||||
|
|
||||||
|
t = 64-t;
|
||||||
|
if (len < t) {
|
||||||
|
memcpy(p, buf, len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(p, buf, t);
|
||||||
|
byteReverse(ctx->in, 16);
|
||||||
|
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||||
|
buf += t;
|
||||||
|
len -= t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process data in 64-byte chunks */
|
||||||
|
|
||||||
|
while (len >= 64) {
|
||||||
|
memcpy(ctx->in, buf, 64);
|
||||||
|
byteReverse(ctx->in, 16);
|
||||||
|
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||||
|
buf += 64;
|
||||||
|
len -= 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle any remaining bytes of data. */
|
||||||
|
|
||||||
|
memcpy(ctx->in, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||||
|
* 1 0* (64-bit count of bits processed, MSB-first)
|
||||||
|
*/
|
||||||
|
static void MD5Final(unsigned char digest[16], MD5Context *pCtx){
|
||||||
|
struct Context *ctx = (struct Context *)pCtx;
|
||||||
|
unsigned count;
|
||||||
|
unsigned char *p;
|
||||||
|
|
||||||
|
/* Compute number of bytes mod 64 */
|
||||||
|
count = (ctx->bits[0] >> 3) & 0x3F;
|
||||||
|
|
||||||
|
/* Set the first char of padding to 0x80. This is safe since there is
|
||||||
|
always at least one byte free */
|
||||||
|
p = ctx->in + count;
|
||||||
|
*p++ = 0x80;
|
||||||
|
|
||||||
|
/* Bytes of padding needed to make 64 bytes */
|
||||||
|
count = 64 - 1 - count;
|
||||||
|
|
||||||
|
/* Pad out to 56 mod 64 */
|
||||||
|
if (count < 8) {
|
||||||
|
/* Two lots of padding: Pad the first block to 64 bytes */
|
||||||
|
memset(p, 0, count);
|
||||||
|
byteReverse(ctx->in, 16);
|
||||||
|
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||||
|
|
||||||
|
/* Now fill the next block with 56 bytes */
|
||||||
|
memset(ctx->in, 0, 56);
|
||||||
|
} else {
|
||||||
|
/* Pad block to 56 bytes */
|
||||||
|
memset(p, 0, count-8);
|
||||||
|
}
|
||||||
|
byteReverse(ctx->in, 14);
|
||||||
|
|
||||||
|
/* Append length in bits and transform */
|
||||||
|
((uint32 *)ctx->in)[ 14 ] = ctx->bits[0];
|
||||||
|
((uint32 *)ctx->in)[ 15 ] = ctx->bits[1];
|
||||||
|
|
||||||
|
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||||
|
byteReverse((unsigned char *)ctx->buf, 4);
|
||||||
|
memcpy(digest, ctx->buf, 16);
|
||||||
|
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Convert a digest into base-16. digest should be declared as
|
||||||
|
** "unsigned char digest[16]" in the calling function. The MD5
|
||||||
|
** digest is stored in the first 16 bytes. zBuf should
|
||||||
|
** be "char zBuf[33]".
|
||||||
|
*/
|
||||||
|
static void DigestToBase16(unsigned char *digest, char *zBuf){
|
||||||
|
static char const zEncode[] = "0123456789abcdef";
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for(j=i=0; i<16; i++){
|
||||||
|
int a = digest[i];
|
||||||
|
zBuf[j++] = zEncode[(a>>4)&0xf];
|
||||||
|
zBuf[j++] = zEncode[a & 0xf];
|
||||||
|
}
|
||||||
|
zBuf[j] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** A TCL command for md5. The argument is the text to be hashed. The
|
||||||
|
** Result is the hash in base64.
|
||||||
|
*/
|
||||||
|
static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){
|
||||||
|
MD5Context ctx;
|
||||||
|
unsigned char digest[16];
|
||||||
|
|
||||||
|
if( argc!=2 ){
|
||||||
|
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||||
|
" TEXT\"", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
MD5Init(&ctx);
|
||||||
|
MD5Update(&ctx, (unsigned char*)argv[1], (unsigned)strlen(argv[1]));
|
||||||
|
MD5Final(digest, &ctx);
|
||||||
|
DigestToBase16(digest, interp->result);
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** A TCL command to take the md5 hash of a file. The argument is the
|
||||||
|
** name of the file.
|
||||||
|
*/
|
||||||
|
static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){
|
||||||
|
FILE *in;
|
||||||
|
MD5Context ctx;
|
||||||
|
unsigned char digest[16];
|
||||||
|
char zBuf[10240];
|
||||||
|
|
||||||
|
if( argc!=2 ){
|
||||||
|
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||||
|
" FILENAME\"", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
in = fopen(argv[1],"rb");
|
||||||
|
if( in==0 ){
|
||||||
|
Tcl_AppendResult(interp,"unable to open file \"", argv[1],
|
||||||
|
"\" for reading", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
MD5Init(&ctx);
|
||||||
|
for(;;){
|
||||||
|
int n;
|
||||||
|
n = fread(zBuf, 1, sizeof(zBuf), in);
|
||||||
|
if( n<=0 ) break;
|
||||||
|
MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n);
|
||||||
|
}
|
||||||
|
fclose(in);
|
||||||
|
MD5Final(digest, &ctx);
|
||||||
|
DigestToBase16(digest, interp->result);
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Register the two TCL commands above with the TCL interpreter.
|
||||||
|
*/
|
||||||
|
int Md5_Init(Tcl_Interp *interp){
|
||||||
|
Tcl_CreateCommand(interp, "md5", (Tcl_CmdProc*)md5_cmd, 0, 0);
|
||||||
|
Tcl_CreateCommand(interp, "md5file", (Tcl_CmdProc*)md5file_cmd, 0, 0);
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** During testing, the special md5sum() aggregate function is available.
|
||||||
|
** inside SQLite. The following routines implement that function.
|
||||||
|
*/
|
||||||
|
static void md5step(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||||
|
MD5Context *p;
|
||||||
|
int i;
|
||||||
|
if( argc<1 ) return;
|
||||||
|
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||||
|
if( p==0 ) return;
|
||||||
|
if( sqlite3_aggregate_count(context)==1 ){
|
||||||
|
MD5Init(p);
|
||||||
|
}
|
||||||
|
for(i=0; i<argc; i++){
|
||||||
|
const char *zData = (char*)sqlite3_value_text(argv[i]);
|
||||||
|
if( zData ){
|
||||||
|
MD5Update(p, (unsigned char*)zData, strlen(zData));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void md5finalize(sqlite3_context *context){
|
||||||
|
MD5Context *p;
|
||||||
|
unsigned char digest[16];
|
||||||
|
char zBuf[33];
|
||||||
|
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||||
|
MD5Final(digest,p);
|
||||||
|
DigestToBase16(digest, zBuf);
|
||||||
|
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
||||||
|
}
|
||||||
|
void Md5_Register(sqlite3 *db){
|
||||||
|
sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0,
|
||||||
|
md5step, md5finalize);
|
||||||
|
}
|
||||||
485
src/test_server.c
Normal file
485
src/test_server.c
Normal file
@@ -0,0 +1,485 @@
|
|||||||
|
/*
|
||||||
|
** 2006 January 07
|
||||||
|
**
|
||||||
|
** 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 demonstration code. Nothing in this file gets compiled
|
||||||
|
** or linked into the SQLite library unless you use a non-standard option:
|
||||||
|
**
|
||||||
|
** -DSQLITE_SERVER=1
|
||||||
|
**
|
||||||
|
** The configure script will never generate a Makefile with the option
|
||||||
|
** above. You will need to manually modify the Makefile if you want to
|
||||||
|
** include any of the code from this file in your project. Or, at your
|
||||||
|
** option, you may copy and paste the code from this file and
|
||||||
|
** thereby avoiding a recompile of SQLite.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** This source file demonstrates how to use SQLite to create an SQL database
|
||||||
|
** server thread in a multiple-threaded program. One or more client threads
|
||||||
|
** send messages to the server thread and the server thread processes those
|
||||||
|
** messages in the order received and returns the results to the client.
|
||||||
|
**
|
||||||
|
** One might ask: "Why bother? Why not just let each thread connect
|
||||||
|
** to the database directly?" There are a several of reasons to
|
||||||
|
** prefer the client/server approach.
|
||||||
|
**
|
||||||
|
** (1) Some systems (ex: Redhat9) have broken threading implementations
|
||||||
|
** that prevent SQLite database connections from being used in
|
||||||
|
** a thread different from the one where they were created. With
|
||||||
|
** the client/server approach, all database connections are created
|
||||||
|
** and used within the server thread. Client calls to the database
|
||||||
|
** can be made from multiple threads (though not at the same time!)
|
||||||
|
**
|
||||||
|
** (2) Beginning with SQLite version 3.3.0, when two or more
|
||||||
|
** connections to the same database occur within the same thread,
|
||||||
|
** they can optionally share their database cache. This reduces
|
||||||
|
** I/O and memory requirements. Cache shared is controlled using
|
||||||
|
** the sqlite3_enable_shared_cache() API.
|
||||||
|
**
|
||||||
|
** (3) Database connections on a shared cache use table-level locking
|
||||||
|
** instead of file-level locking for improved concurrency.
|
||||||
|
**
|
||||||
|
** (4) Database connections on a shared cache can by optionally
|
||||||
|
** set to READ UNCOMMITTED isolation. (The default isolation for
|
||||||
|
** SQLite is SERIALIZABLE.) When this occurs, readers will
|
||||||
|
** never be blocked by a writer and writers will not be
|
||||||
|
** blocked by readers. There can still only be a single writer
|
||||||
|
** at a time, but multiple readers can simultaneously exist with
|
||||||
|
** that writer. This is a huge increase in concurrency.
|
||||||
|
**
|
||||||
|
** To summarize the rational for using a client/server approach: prior
|
||||||
|
** to SQLite version 3.3.0 it probably was not worth the trouble. But
|
||||||
|
** with SQLite version 3.3.0 and beyond you can get significant performance
|
||||||
|
** and concurrency improvements and memory usage reductions by going
|
||||||
|
** client/server.
|
||||||
|
**
|
||||||
|
** Note: The extra features of version 3.3.0 described by points (2)
|
||||||
|
** through (4) above are only available if you compile without the
|
||||||
|
** option -DSQLITE_OMIT_SHARED_CACHE.
|
||||||
|
**
|
||||||
|
** Here is how the client/server approach works: The database server
|
||||||
|
** thread is started on this procedure:
|
||||||
|
**
|
||||||
|
** void *sqlite3_server(void *NotUsed);
|
||||||
|
**
|
||||||
|
** The sqlite_server procedure runs as long as the g.serverHalt variable
|
||||||
|
** is false. A mutex is used to make sure no more than one server runs
|
||||||
|
** at a time. The server waits for messages to arrive on a message
|
||||||
|
** queue and processes the messages in order.
|
||||||
|
**
|
||||||
|
** Two convenience routines are provided for starting and stopping the
|
||||||
|
** server thread:
|
||||||
|
**
|
||||||
|
** void sqlite3_server_start(void);
|
||||||
|
** void sqlite3_server_stop(void);
|
||||||
|
**
|
||||||
|
** Both of the convenience routines return immediately. Neither will
|
||||||
|
** ever give an error. If a server is already started or already halted,
|
||||||
|
** then the routines are effectively no-ops.
|
||||||
|
**
|
||||||
|
** Clients use the following interfaces:
|
||||||
|
**
|
||||||
|
** sqlite3_client_open
|
||||||
|
** sqlite3_client_prepare
|
||||||
|
** sqlite3_client_step
|
||||||
|
** sqlite3_client_reset
|
||||||
|
** sqlite3_client_finalize
|
||||||
|
** sqlite3_client_close
|
||||||
|
**
|
||||||
|
** These interfaces work exactly like the standard core SQLite interfaces
|
||||||
|
** having the same names without the "_client_" infix. Many other SQLite
|
||||||
|
** interfaces can be used directly without having to send messages to the
|
||||||
|
** server as long as SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined.
|
||||||
|
** The following interfaces fall into this second category:
|
||||||
|
**
|
||||||
|
** sqlite3_bind_*
|
||||||
|
** sqlite3_changes
|
||||||
|
** sqlite3_clear_bindings
|
||||||
|
** sqlite3_column_*
|
||||||
|
** sqlite3_complete
|
||||||
|
** sqlite3_create_collation
|
||||||
|
** sqlite3_create_function
|
||||||
|
** sqlite3_data_count
|
||||||
|
** sqlite3_db_handle
|
||||||
|
** sqlite3_errcode
|
||||||
|
** sqlite3_errmsg
|
||||||
|
** sqlite3_last_insert_rowid
|
||||||
|
** sqlite3_total_changes
|
||||||
|
** sqlite3_transfer_bindings
|
||||||
|
**
|
||||||
|
** A single SQLite connection (an sqlite3* object) or an SQLite statement
|
||||||
|
** (an sqlite3_stmt* object) should only be passed to a single interface
|
||||||
|
** function at a time. The connections and statements can be passed from
|
||||||
|
** any thread to any of the functions listed in the second group above as
|
||||||
|
** long as the same connection is not in use by two threads at once and
|
||||||
|
** as long as SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined. Additional
|
||||||
|
** information about the SQLITE_ENABLE_MEMORY_MANAGEMENT constraint is
|
||||||
|
** below.
|
||||||
|
**
|
||||||
|
** The busy handler for all database connections should remain turned
|
||||||
|
** off. That means that any lock contention will cause the associated
|
||||||
|
** sqlite3_client_step() call to return immediately with an SQLITE_BUSY
|
||||||
|
** error code. If a busy handler is enabled and lock contention occurs,
|
||||||
|
** then the entire server thread will block. This will cause not only
|
||||||
|
** the requesting client to block but every other database client as
|
||||||
|
** well. It is possible to enhance the code below so that lock
|
||||||
|
** contention will cause the message to be placed back on the top of
|
||||||
|
** the queue to be tried again later. But such enhanced processing is
|
||||||
|
** not included here, in order to keep the example simple.
|
||||||
|
**
|
||||||
|
** This example code assumes the use of pthreads. Pthreads
|
||||||
|
** implementations are available for windows. (See, for example
|
||||||
|
** http://sourceware.org/pthreads-win32/announcement.html.) Or, you
|
||||||
|
** can translate the locking and thread synchronization code to use
|
||||||
|
** windows primitives easily enough. The details are left as an
|
||||||
|
** exercise to the reader.
|
||||||
|
**
|
||||||
|
**** Restrictions Associated With SQLITE_ENABLE_MEMORY_MANAGEMENT ****
|
||||||
|
**
|
||||||
|
** If you compile with SQLITE_ENABLE_MEMORY_MANAGEMENT defined, then
|
||||||
|
** SQLite includes code that tracks how much memory is being used by
|
||||||
|
** each thread. These memory counts can become confused if memory
|
||||||
|
** is allocated by one thread and then freed by another. For that
|
||||||
|
** reason, when SQLITE_ENABLE_MEMORY_MANAGEMENT is used, all operations
|
||||||
|
** that might allocate or free memory should be performanced in the same
|
||||||
|
** thread that originally created the database connection. In that case,
|
||||||
|
** many of the operations that are listed above as safe to be performed
|
||||||
|
** in separate threads would need to be sent over to the server to be
|
||||||
|
** done there. If SQLITE_ENABLE_MEMORY_MANAGEMENT is defined, then
|
||||||
|
** the following functions can be used safely from different threads
|
||||||
|
** without messing up the allocation counts:
|
||||||
|
**
|
||||||
|
** sqlite3_bind_parameter_name
|
||||||
|
** sqlite3_bind_parameter_index
|
||||||
|
** sqlite3_changes
|
||||||
|
** sqlite3_column_blob
|
||||||
|
** sqlite3_column_count
|
||||||
|
** sqlite3_complete
|
||||||
|
** sqlite3_data_count
|
||||||
|
** sqlite3_db_handle
|
||||||
|
** sqlite3_errcode
|
||||||
|
** sqlite3_errmsg
|
||||||
|
** sqlite3_last_insert_rowid
|
||||||
|
** sqlite3_total_changes
|
||||||
|
**
|
||||||
|
** The remaining functions are not thread-safe when memory management
|
||||||
|
** is enabled. So one would have to define some new interface routines
|
||||||
|
** along the following lines:
|
||||||
|
**
|
||||||
|
** sqlite3_client_bind_*
|
||||||
|
** sqlite3_client_clear_bindings
|
||||||
|
** sqlite3_client_column_*
|
||||||
|
** sqlite3_client_create_collation
|
||||||
|
** sqlite3_client_create_function
|
||||||
|
** sqlite3_client_transfer_bindings
|
||||||
|
**
|
||||||
|
** The example code in this file is intended for use with memory
|
||||||
|
** management turned off. So the implementation of these additional
|
||||||
|
** client interfaces is left as an exercise to the reader.
|
||||||
|
**
|
||||||
|
** It may seem surprising to the reader that the list of safe functions
|
||||||
|
** above does not include things like sqlite3_bind_int() or
|
||||||
|
** sqlite3_column_int(). But those routines might, in fact, allocate
|
||||||
|
** or deallocate memory. In the case of sqlite3_bind_int(), if the
|
||||||
|
** parameter was previously bound to a string that string might need
|
||||||
|
** to be deallocated before the new integer value is inserted. In
|
||||||
|
** the case of sqlite3_column_int(), the value of the column might be
|
||||||
|
** a UTF-16 string which will need to be converted to UTF-8 then into
|
||||||
|
** an integer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Only compile the code in this file on UNIX with a THREADSAFE build
|
||||||
|
** and only if the SQLITE_SERVER macro is defined.
|
||||||
|
*/
|
||||||
|
#ifdef SQLITE_SERVER
|
||||||
|
#if defined(OS_UNIX) && OS_UNIX && defined(THREADSAFE) && THREADSAFE
|
||||||
|
|
||||||
|
/*
|
||||||
|
** We require only pthreads and the public interface of SQLite.
|
||||||
|
*/
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "sqlite3.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Messages are passed from client to server and back again as
|
||||||
|
** instances of the following structure.
|
||||||
|
*/
|
||||||
|
typedef struct SqlMessage SqlMessage;
|
||||||
|
struct SqlMessage {
|
||||||
|
int op; /* Opcode for the message */
|
||||||
|
sqlite3 *pDb; /* The SQLite connection */
|
||||||
|
sqlite3_stmt *pStmt; /* A specific statement */
|
||||||
|
int errCode; /* Error code returned */
|
||||||
|
const char *zIn; /* Input filename or SQL statement */
|
||||||
|
int nByte; /* Size of the zIn parameter for prepare() */
|
||||||
|
const char *zOut; /* Tail of the SQL statement */
|
||||||
|
SqlMessage *pNext; /* Next message in the queue */
|
||||||
|
SqlMessage *pPrev; /* Previous message in the queue */
|
||||||
|
pthread_mutex_t clientMutex; /* Hold this mutex to access the message */
|
||||||
|
pthread_cond_t clientWakeup; /* Signal to wake up the client */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Legal values for SqlMessage.op
|
||||||
|
*/
|
||||||
|
#define MSG_Open 1 /* sqlite3_open(zIn, &pDb) */
|
||||||
|
#define MSG_Prepare 2 /* sqlite3_prepare(pDb, zIn, nByte, &pStmt, &zOut) */
|
||||||
|
#define MSG_Step 3 /* sqlite3_step(pStmt) */
|
||||||
|
#define MSG_Reset 4 /* sqlite3_reset(pStmt) */
|
||||||
|
#define MSG_Finalize 5 /* sqlite3_finalize(pStmt) */
|
||||||
|
#define MSG_Close 6 /* sqlite3_close(pDb) */
|
||||||
|
#define MSG_Done 7 /* Server has finished with this message */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** State information about the server is stored in a static variable
|
||||||
|
** named "g" as follows:
|
||||||
|
*/
|
||||||
|
static struct ServerState {
|
||||||
|
pthread_mutex_t queueMutex; /* Hold this mutex to access the msg queue */
|
||||||
|
pthread_mutex_t serverMutex; /* Held by the server while it is running */
|
||||||
|
pthread_cond_t serverWakeup; /* Signal this condvar to wake up the server */
|
||||||
|
volatile int serverHalt; /* Server halts itself when true */
|
||||||
|
SqlMessage *pQueueHead; /* Head of the message queue */
|
||||||
|
SqlMessage *pQueueTail; /* Tail of the message queue */
|
||||||
|
} g = {
|
||||||
|
PTHREAD_MUTEX_INITIALIZER,
|
||||||
|
PTHREAD_MUTEX_INITIALIZER,
|
||||||
|
PTHREAD_COND_INITIALIZER,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Send a message to the server. Block until we get a reply.
|
||||||
|
**
|
||||||
|
** The mutex and condition variable in the message are uninitialized
|
||||||
|
** when this routine is called. This routine takes care of
|
||||||
|
** initializing them and destroying them when it has finished.
|
||||||
|
*/
|
||||||
|
static void sendToServer(SqlMessage *pMsg){
|
||||||
|
/* Initialize the mutex and condition variable on the message
|
||||||
|
*/
|
||||||
|
pthread_mutex_init(&pMsg->clientMutex, 0);
|
||||||
|
pthread_cond_init(&pMsg->clientWakeup, 0);
|
||||||
|
|
||||||
|
/* Add the message to the head of the server's message queue.
|
||||||
|
*/
|
||||||
|
pthread_mutex_lock(&g.queueMutex);
|
||||||
|
pMsg->pNext = g.pQueueHead;
|
||||||
|
if( g.pQueueHead==0 ){
|
||||||
|
g.pQueueTail = pMsg;
|
||||||
|
}else{
|
||||||
|
g.pQueueHead->pPrev = pMsg;
|
||||||
|
}
|
||||||
|
pMsg->pPrev = 0;
|
||||||
|
g.pQueueHead = pMsg;
|
||||||
|
pthread_mutex_unlock(&g.queueMutex);
|
||||||
|
|
||||||
|
/* Signal the server that the new message has be queued, then
|
||||||
|
** block waiting for the server to process the message.
|
||||||
|
*/
|
||||||
|
pthread_mutex_lock(&pMsg->clientMutex);
|
||||||
|
pthread_cond_signal(&g.serverWakeup);
|
||||||
|
while( pMsg->op!=MSG_Done ){
|
||||||
|
pthread_cond_wait(&pMsg->clientWakeup, &pMsg->clientMutex);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&pMsg->clientMutex);
|
||||||
|
|
||||||
|
/* Destroy the mutex and condition variable of the message.
|
||||||
|
*/
|
||||||
|
pthread_mutex_destroy(&pMsg->clientMutex);
|
||||||
|
pthread_cond_destroy(&pMsg->clientWakeup);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following 6 routines are client-side implementations of the
|
||||||
|
** core SQLite interfaces:
|
||||||
|
**
|
||||||
|
** sqlite3_open
|
||||||
|
** sqlite3_prepare
|
||||||
|
** sqlite3_step
|
||||||
|
** sqlite3_reset
|
||||||
|
** sqlite3_finalize
|
||||||
|
** sqlite3_close
|
||||||
|
**
|
||||||
|
** Clients should use the following client-side routines instead of
|
||||||
|
** the core routines above.
|
||||||
|
**
|
||||||
|
** sqlite3_client_open
|
||||||
|
** sqlite3_client_prepare
|
||||||
|
** sqlite3_client_step
|
||||||
|
** sqlite3_client_reset
|
||||||
|
** sqlite3_client_finalize
|
||||||
|
** sqlite3_client_close
|
||||||
|
**
|
||||||
|
** Each of these routines creates a message for the desired operation,
|
||||||
|
** sends that message to the server, waits for the server to process
|
||||||
|
** then message and return a response.
|
||||||
|
*/
|
||||||
|
int sqlite3_client_open(const char *zDatabaseName, sqlite3 **ppDb){
|
||||||
|
SqlMessage msg;
|
||||||
|
msg.op = MSG_Open;
|
||||||
|
msg.zIn = zDatabaseName;
|
||||||
|
sendToServer(&msg);
|
||||||
|
*ppDb = msg.pDb;
|
||||||
|
return msg.errCode;
|
||||||
|
}
|
||||||
|
int sqlite3_client_prepare(
|
||||||
|
sqlite3 *pDb,
|
||||||
|
const char *zSql,
|
||||||
|
int nByte,
|
||||||
|
sqlite3_stmt **ppStmt,
|
||||||
|
const char **pzTail
|
||||||
|
){
|
||||||
|
SqlMessage msg;
|
||||||
|
msg.op = MSG_Prepare;
|
||||||
|
msg.pDb = pDb;
|
||||||
|
msg.zIn = zSql;
|
||||||
|
msg.nByte = nByte;
|
||||||
|
sendToServer(&msg);
|
||||||
|
*ppStmt = msg.pStmt;
|
||||||
|
if( pzTail ) *pzTail = msg.zOut;
|
||||||
|
return msg.errCode;
|
||||||
|
}
|
||||||
|
int sqlite3_client_step(sqlite3_stmt *pStmt){
|
||||||
|
SqlMessage msg;
|
||||||
|
msg.op = MSG_Step;
|
||||||
|
msg.pStmt = pStmt;
|
||||||
|
sendToServer(&msg);
|
||||||
|
return msg.errCode;
|
||||||
|
}
|
||||||
|
int sqlite3_client_reset(sqlite3_stmt *pStmt){
|
||||||
|
SqlMessage msg;
|
||||||
|
msg.op = MSG_Reset;
|
||||||
|
msg.pStmt = pStmt;
|
||||||
|
sendToServer(&msg);
|
||||||
|
return msg.errCode;
|
||||||
|
}
|
||||||
|
int sqlite3_client_finalize(sqlite3_stmt *pStmt){
|
||||||
|
SqlMessage msg;
|
||||||
|
msg.op = MSG_Finalize;
|
||||||
|
msg.pStmt = pStmt;
|
||||||
|
sendToServer(&msg);
|
||||||
|
return msg.errCode;
|
||||||
|
}
|
||||||
|
int sqlite3_client_close(sqlite3 *pDb){
|
||||||
|
SqlMessage msg;
|
||||||
|
msg.op = MSG_Close;
|
||||||
|
msg.pDb = pDb;
|
||||||
|
sendToServer(&msg);
|
||||||
|
return msg.errCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This routine implements the server. To start the server, first
|
||||||
|
** make sure g.serverHalt is false, then create a new detached thread
|
||||||
|
** on this procedure. See the sqlite3_server_start() routine below
|
||||||
|
** for an example. This procedure loops until g.serverHalt becomes
|
||||||
|
** true.
|
||||||
|
*/
|
||||||
|
void *sqlite3_server(void *NotUsed){
|
||||||
|
sqlite3_enable_shared_cache(1);
|
||||||
|
if( pthread_mutex_trylock(&g.serverMutex) ){
|
||||||
|
sqlite3_enable_shared_cache(0);
|
||||||
|
return 0; /* Another server is already running */
|
||||||
|
}
|
||||||
|
while( !g.serverHalt ){
|
||||||
|
SqlMessage *pMsg;
|
||||||
|
|
||||||
|
/* Remove the last message from the message queue.
|
||||||
|
*/
|
||||||
|
pthread_mutex_lock(&g.queueMutex);
|
||||||
|
while( g.pQueueTail==0 && g.serverHalt==0 ){
|
||||||
|
pthread_cond_wait(&g.serverWakeup, &g.queueMutex);
|
||||||
|
}
|
||||||
|
pMsg = g.pQueueTail;
|
||||||
|
if( pMsg ){
|
||||||
|
if( pMsg->pPrev ){
|
||||||
|
pMsg->pPrev->pNext = 0;
|
||||||
|
}else{
|
||||||
|
g.pQueueHead = 0;
|
||||||
|
}
|
||||||
|
g.pQueueTail = pMsg->pPrev;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&g.queueMutex);
|
||||||
|
if( pMsg==0 ) break;
|
||||||
|
|
||||||
|
/* Process the message just removed
|
||||||
|
*/
|
||||||
|
pthread_mutex_lock(&pMsg->clientMutex);
|
||||||
|
switch( pMsg->op ){
|
||||||
|
case MSG_Open: {
|
||||||
|
pMsg->errCode = sqlite3_open(pMsg->zIn, &pMsg->pDb);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_Prepare: {
|
||||||
|
pMsg->errCode = sqlite3_prepare(pMsg->pDb, pMsg->zIn, pMsg->nByte,
|
||||||
|
&pMsg->pStmt, &pMsg->zOut);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_Step: {
|
||||||
|
pMsg->errCode = sqlite3_step(pMsg->pStmt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_Reset: {
|
||||||
|
pMsg->errCode = sqlite3_reset(pMsg->pStmt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_Finalize: {
|
||||||
|
pMsg->errCode = sqlite3_finalize(pMsg->pStmt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_Close: {
|
||||||
|
pMsg->errCode = sqlite3_close(pMsg->pDb);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Signal the client that the message has been processed.
|
||||||
|
*/
|
||||||
|
pMsg->op = MSG_Done;
|
||||||
|
pthread_mutex_unlock(&pMsg->clientMutex);
|
||||||
|
pthread_cond_signal(&pMsg->clientWakeup);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&g.serverMutex);
|
||||||
|
sqlite3_thread_cleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Start a server thread if one is not already running. If there
|
||||||
|
** is aleady a server thread running, the new thread will quickly
|
||||||
|
** die and this routine is effectively a no-op.
|
||||||
|
*/
|
||||||
|
void sqlite3_server_start(void){
|
||||||
|
pthread_t x;
|
||||||
|
int rc;
|
||||||
|
g.serverHalt = 0;
|
||||||
|
rc = pthread_create(&x, 0, sqlite3_server, 0);
|
||||||
|
if( rc==0 ){
|
||||||
|
pthread_detach(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** If a server thread is running, then stop it. If no server is
|
||||||
|
** running, this routine is effectively a no-op.
|
||||||
|
**
|
||||||
|
** This routine returns immediately without waiting for the server
|
||||||
|
** thread to stop. But be assured that the server will eventually stop.
|
||||||
|
*/
|
||||||
|
void sqlite3_server_stop(void){
|
||||||
|
g.serverHalt = 1;
|
||||||
|
pthread_cond_broadcast(&g.serverWakeup);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* defined(OS_UNIX) && OS_UNIX && defined(THREADSAFE) && THREADSAFE */
|
||||||
|
#endif /* defined(SQLITE_SERVER) */
|
||||||
Reference in New Issue
Block a user