1:
2: /*
3: ** The code in this file runs a few multi-threaded test cases using the
4: ** SQLite library. It can be compiled to an executable on unix using the
5: ** following command:
6: **
7: ** gcc -O2 threadtest3.c sqlite3.c -ldl -lpthread -lm
8: **
9: ** Then run the compiled program. The exit status is non-zero if any tests
10: ** failed (hopefully there is also some output to stdout to clarify what went
11: ** wrong).
12: **
13: ** There are three parts to the code in this file, in the following order:
14: **
15: ** 1. Code for the SQL aggregate function md5sum() copied from
16: ** tclsqlite.c in the SQLite distribution. The names of all the
17: ** types and functions in this section begin with "MD5" or "md5".
18: **
19: ** 2. A set of utility functions that may be used to implement
20: ** multi-threaded test cases. These are all called by test code
21: ** via macros that help with error reporting. The macros are defined
22: ** immediately below this comment.
23: **
24: ** 3. The test code itself. And a main() routine to drive the test
25: ** code.
26: */
27:
28: /*************************************************************************
29: ** Start of test code/infrastructure interface macros.
30: **
31: ** The following macros constitute the interface between the test
32: ** programs and the test infrastructure. Test infrastructure code
33: ** does not itself use any of these macros. Test code should not
34: ** call any of the macroname_x() functions directly.
35: **
36: ** See the header comments above the corresponding macroname_x()
37: ** function for a description of each interface.
38: */
39:
40: /* Database functions */
41: #define opendb(w,x,y,z) (SEL(w), opendb_x(w,x,y,z))
42: #define closedb(y,z) (SEL(y), closedb_x(y,z))
43:
44: /* Functions to execute SQL */
45: #define sql_script(x,y,z) (SEL(x), sql_script_x(x,y,z))
46: #define integrity_check(x,y) (SEL(x), integrity_check_x(x,y))
47: #define execsql_i64(x,y,...) (SEL(x), execsql_i64_x(x,y,__VA_ARGS__))
48: #define execsql_text(x,y,z,...) (SEL(x), execsql_text_x(x,y,z,__VA_ARGS__))
49: #define execsql(x,y,...) (SEL(x), (void)execsql_i64_x(x,y,__VA_ARGS__))
50:
51: /* Thread functions */
52: #define launch_thread(w,x,y,z) (SEL(w), launch_thread_x(w,x,y,z))
53: #define join_all_threads(y,z) (SEL(y), join_all_threads_x(y,z))
54:
55: /* Timer functions */
56: #define setstoptime(y,z) (SEL(y), setstoptime_x(y,z))
57: #define timetostop(z) (SEL(z), timetostop_x(z))
58:
59: /* Report/clear errors. */
60: #define test_error(z, ...) test_error_x(z, sqlite3_mprintf(__VA_ARGS__))
61: #define clear_error(y,z) clear_error_x(y, z)
62:
63: /* File-system operations */
64: #define filesize(y,z) (SEL(y), filesize_x(y,z))
65: #define filecopy(x,y,z) (SEL(x), filecopy_x(x,y,z))
66:
67: /*
68: ** End of test code/infrastructure interface macros.
69: *************************************************************************/
70:
71:
72:
73:
74: #include <sqlite3.h>
75: #include <unistd.h>
76: #include <stdio.h>
77: #include <pthread.h>
78: #include <assert.h>
79: #include <sys/types.h>
80: #include <sys/stat.h>
81: #include <string.h>
82: #include <fcntl.h>
83: #include <errno.h>
84:
85: /*
86: * This code implements the MD5 message-digest algorithm.
87: * The algorithm is due to Ron Rivest. This code was
88: * written by Colin Plumb in 1993, no copyright is claimed.
89: * This code is in the public domain; do with it what you wish.
90: *
91: * Equivalent code is available from RSA Data Security, Inc.
92: * This code has been tested against that, and is equivalent,
93: * except that you don't need to include two pages of legalese
94: * with every copy.
95: *
96: * To compute the message digest of a chunk of bytes, declare an
97: * MD5Context structure, pass it to MD5Init, call MD5Update as
98: * needed on buffers full of bytes, and then call MD5Final, which
99: * will fill a supplied 16-byte array with the digest.
100: */
101:
102: /*
103: * If compiled on a machine that doesn't have a 32-bit integer,
104: * you just set "uint32" to the appropriate datatype for an
105: * unsigned 32-bit integer. For example:
106: *
107: * cc -Duint32='unsigned long' md5.c
108: *
109: */
110: #ifndef uint32
111: # define uint32 unsigned int
112: #endif
113:
114: struct MD5Context {
115: int isInit;
116: uint32 buf[4];
117: uint32 bits[2];
118: unsigned char in[64];
119: };
120: typedef struct MD5Context MD5Context;
121:
122: /*
123: * Note: this code is harmless on little-endian machines.
124: */
125: static void byteReverse (unsigned char *buf, unsigned longs){
126: uint32 t;
127: do {
128: t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
129: ((unsigned)buf[1]<<8 | buf[0]);
130: *(uint32 *)buf = t;
131: buf += 4;
132: } while (--longs);
133: }
134: /* The four core functions - F1 is optimized somewhat */
135:
136: /* #define F1(x, y, z) (x & y | ~x & z) */
137: #define F1(x, y, z) (z ^ (x & (y ^ z)))
138: #define F2(x, y, z) F1(z, x, y)
139: #define F3(x, y, z) (x ^ y ^ z)
140: #define F4(x, y, z) (y ^ (x | ~z))
141:
142: /* This is the central step in the MD5 algorithm. */
143: #define MD5STEP(f, w, x, y, z, data, s) \
144: ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
145:
146: /*
147: * The core of the MD5 algorithm, this alters an existing MD5 hash to
148: * reflect the addition of 16 longwords of new data. MD5Update blocks
149: * the data and converts bytes into longwords for this routine.
150: */
151: static void MD5Transform(uint32 buf[4], const uint32 in[16]){
152: register uint32 a, b, c, d;
153:
154: a = buf[0];
155: b = buf[1];
156: c = buf[2];
157: d = buf[3];
158:
159: MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
160: MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
161: MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
162: MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
163: MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
164: MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
165: MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
166: MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
167: MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
168: MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
169: MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
170: MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
171: MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
172: MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
173: MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
174: MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
175:
176: MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
177: MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
178: MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
179: MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
180: MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
181: MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
182: MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
183: MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
184: MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
185: MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
186: MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
187: MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
188: MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
189: MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
190: MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
191: MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
192:
193: MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
194: MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
195: MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
196: MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
197: MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
198: MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
199: MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
200: MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
201: MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
202: MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
203: MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
204: MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
205: MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
206: MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
207: MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
208: MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
209:
210: MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
211: MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
212: MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
213: MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
214: MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
215: MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
216: MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
217: MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
218: MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
219: MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
220: MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
221: MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
222: MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
223: MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
224: MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
225: MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
226:
227: buf[0] += a;
228: buf[1] += b;
229: buf[2] += c;
230: buf[3] += d;
231: }
232:
233: /*
234: * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
235: * initialization constants.
236: */
237: static void MD5Init(MD5Context *ctx){
238: ctx->isInit = 1;
239: ctx->buf[0] = 0x67452301;
240: ctx->buf[1] = 0xefcdab89;
241: ctx->buf[2] = 0x98badcfe;
242: ctx->buf[3] = 0x10325476;
243: ctx->bits[0] = 0;
244: ctx->bits[1] = 0;
245: }
246:
247: /*
248: * Update context to reflect the concatenation of another buffer full
249: * of bytes.
250: */
251: static
252: void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
253: uint32 t;
254:
255: /* Update bitcount */
256:
257: t = ctx->bits[0];
258: if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
259: ctx->bits[1]++; /* Carry from low to high */
260: ctx->bits[1] += len >> 29;
261:
262: t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
263:
264: /* Handle any leading odd-sized chunks */
265:
266: if ( t ) {
267: unsigned char *p = (unsigned char *)ctx->in + t;
268:
269: t = 64-t;
270: if (len < t) {
271: memcpy(p, buf, len);
272: return;
273: }
274: memcpy(p, buf, t);
275: byteReverse(ctx->in, 16);
276: MD5Transform(ctx->buf, (uint32 *)ctx->in);
277: buf += t;
278: len -= t;
279: }
280:
281: /* Process data in 64-byte chunks */
282:
283: while (len >= 64) {
284: memcpy(ctx->in, buf, 64);
285: byteReverse(ctx->in, 16);
286: MD5Transform(ctx->buf, (uint32 *)ctx->in);
287: buf += 64;
288: len -= 64;
289: }
290:
291: /* Handle any remaining bytes of data. */
292:
293: memcpy(ctx->in, buf, len);
294: }
295:
296: /*
297: * Final wrapup - pad to 64-byte boundary with the bit pattern
298: * 1 0* (64-bit count of bits processed, MSB-first)
299: */
300: static void MD5Final(unsigned char digest[16], MD5Context *ctx){
301: unsigned count;
302: unsigned char *p;
303:
304: /* Compute number of bytes mod 64 */
305: count = (ctx->bits[0] >> 3) & 0x3F;
306:
307: /* Set the first char of padding to 0x80. This is safe since there is
308: always at least one byte free */
309: p = ctx->in + count;
310: *p++ = 0x80;
311:
312: /* Bytes of padding needed to make 64 bytes */
313: count = 64 - 1 - count;
314:
315: /* Pad out to 56 mod 64 */
316: if (count < 8) {
317: /* Two lots of padding: Pad the first block to 64 bytes */
318: memset(p, 0, count);
319: byteReverse(ctx->in, 16);
320: MD5Transform(ctx->buf, (uint32 *)ctx->in);
321:
322: /* Now fill the next block with 56 bytes */
323: memset(ctx->in, 0, 56);
324: } else {
325: /* Pad block to 56 bytes */
326: memset(p, 0, count-8);
327: }
328: byteReverse(ctx->in, 14);
329:
330: /* Append length in bits and transform */
331: ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0];
332: ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1];
333:
334: MD5Transform(ctx->buf, (uint32 *)ctx->in);
335: byteReverse((unsigned char *)ctx->buf, 4);
336: memcpy(digest, ctx->buf, 16);
337: memset(ctx, 0, sizeof(ctx)); /* In case it is sensitive */
338: }
339:
340: /*
341: ** Convert a 128-bit MD5 digest into a 32-digit base-16 number.
342: */
343: static void MD5DigestToBase16(unsigned char *digest, char *zBuf){
344: static char const zEncode[] = "0123456789abcdef";
345: int i, j;
346:
347: for(j=i=0; i<16; i++){
348: int a = digest[i];
349: zBuf[j++] = zEncode[(a>>4)&0xf];
350: zBuf[j++] = zEncode[a & 0xf];
351: }
352: zBuf[j] = 0;
353: }
354:
355: /*
356: ** During testing, the special md5sum() aggregate function is available.
357: ** inside SQLite. The following routines implement that function.
358: */
359: static void md5step(sqlite3_context *context, int argc, sqlite3_value **argv){
360: MD5Context *p;
361: int i;
362: if( argc<1 ) return;
363: p = sqlite3_aggregate_context(context, sizeof(*p));
364: if( p==0 ) return;
365: if( !p->isInit ){
366: MD5Init(p);
367: }
368: for(i=0; i<argc; i++){
369: const char *zData = (char*)sqlite3_value_text(argv[i]);
370: if( zData ){
371: MD5Update(p, (unsigned char*)zData, strlen(zData));
372: }
373: }
374: }
375: static void md5finalize(sqlite3_context *context){
376: MD5Context *p;
377: unsigned char digest[16];
378: char zBuf[33];
379: p = sqlite3_aggregate_context(context, sizeof(*p));
380: MD5Final(digest,p);
381: MD5DigestToBase16(digest, zBuf);
382: sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
383: }
384:
385: /*************************************************************************
386: ** End of copied md5sum() code.
387: */
388:
389: typedef sqlite3_int64 i64;
390:
391: typedef struct Error Error;
392: typedef struct Sqlite Sqlite;
393: typedef struct Statement Statement;
394:
395: typedef struct Threadset Threadset;
396: typedef struct Thread Thread;
397:
398: /* Total number of errors in this process so far. */
399: static int nGlobalErr = 0;
400:
401: /* Set to true to run in "process" instead of "thread" mode. */
402: static int bProcessMode = 0;
403:
404: struct Error {
405: int rc;
406: int iLine;
407: char *zErr;
408: };
409:
410: struct Sqlite {
411: sqlite3 *db; /* Database handle */
412: Statement *pCache; /* Linked list of cached statements */
413: int nText; /* Size of array at aText[] */
414: char **aText; /* Stored text results */
415: };
416:
417: struct Statement {
418: sqlite3_stmt *pStmt; /* Pre-compiled statement handle */
419: Statement *pNext; /* Next statement in linked-list */
420: };
421:
422: struct Thread {
423: int iTid; /* Thread number within test */
424: int iArg; /* Integer argument passed by caller */
425:
426: pthread_t tid; /* Thread id */
427: char *(*xProc)(int, int); /* Thread main proc */
428: Thread *pNext; /* Next in this list of threads */
429: };
430:
431: struct Threadset {
432: int iMaxTid; /* Largest iTid value allocated so far */
433: Thread *pThread; /* Linked list of threads */
434: };
435:
436: static void free_err(Error *p){
437: sqlite3_free(p->zErr);
438: p->zErr = 0;
439: p->rc = 0;
440: }
441:
442: static void print_err(Error *p){
443: if( p->rc!=SQLITE_OK ){
444: printf("Error: (%d) \"%s\" at line %d\n", p->rc, p->zErr, p->iLine);
445: nGlobalErr++;
446: }
447: }
448:
449: static void print_and_free_err(Error *p){
450: print_err(p);
451: free_err(p);
452: }
453:
454: static void system_error(Error *pErr, int iSys){
455: pErr->rc = iSys;
456: pErr->zErr = (char *)sqlite3_malloc(512);
457: strerror_r(iSys, pErr->zErr, 512);
458: pErr->zErr[511] = '\0';
459: }
460:
461: static void sqlite_error(
462: Error *pErr,
463: Sqlite *pDb,
464: const char *zFunc
465: ){
466: pErr->rc = sqlite3_errcode(pDb->db);
467: pErr->zErr = sqlite3_mprintf(
468: "sqlite3_%s() - %s (%d)", zFunc, sqlite3_errmsg(pDb->db),
469: sqlite3_extended_errcode(pDb->db)
470: );
471: }
472:
473: static void test_error_x(
474: Error *pErr,
475: char *zErr
476: ){
477: if( pErr->rc==SQLITE_OK ){
478: pErr->rc = 1;
479: pErr->zErr = zErr;
480: }else{
481: sqlite3_free(zErr);
482: }
483: }
484:
485: static void clear_error_x(
486: Error *pErr,
487: int rc
488: ){
489: if( pErr->rc==rc ){
490: pErr->rc = SQLITE_OK;
491: sqlite3_free(pErr->zErr);
492: pErr->zErr = 0;
493: }
494: }
495:
496: static int busyhandler(void *pArg, int n){
497: usleep(10*1000);
498: return 1;
499: }
500:
501: static void opendb_x(
502: Error *pErr, /* IN/OUT: Error code */
503: Sqlite *pDb, /* OUT: Database handle */
504: const char *zFile, /* Database file name */
505: int bDelete /* True to delete db file before opening */
506: ){
507: if( pErr->rc==SQLITE_OK ){
508: int rc;
509: if( bDelete ) unlink(zFile);
510: rc = sqlite3_open(zFile, &pDb->db);
511: if( rc ){
512: sqlite_error(pErr, pDb, "open");
513: sqlite3_close(pDb->db);
514: pDb->db = 0;
515: }else{
516: sqlite3_create_function(
517: pDb->db, "md5sum", -1, SQLITE_UTF8, 0, 0, md5step, md5finalize
518: );
519: sqlite3_busy_handler(pDb->db, busyhandler, 0);
520: sqlite3_exec(pDb->db, "PRAGMA synchronous=OFF", 0, 0, 0);
521: }
522: }
523: }
524:
525: static void closedb_x(
526: Error *pErr, /* IN/OUT: Error code */
527: Sqlite *pDb /* OUT: Database handle */
528: ){
529: int rc;
530: int i;
531: Statement *pIter;
532: Statement *pNext;
533: for(pIter=pDb->pCache; pIter; pIter=pNext){
534: pNext = pIter->pNext;
535: sqlite3_finalize(pIter->pStmt);
536: sqlite3_free(pIter);
537: }
538: for(i=0; i<pDb->nText; i++){
539: sqlite3_free(pDb->aText[i]);
540: }
541: sqlite3_free(pDb->aText);
542: rc = sqlite3_close(pDb->db);
543: if( rc && pErr->rc==SQLITE_OK ){
544: pErr->zErr = sqlite3_mprintf("%s", sqlite3_errmsg(pDb->db));
545: }
546: memset(pDb, 0, sizeof(Sqlite));
547: }
548:
549: static void sql_script_x(
550: Error *pErr, /* IN/OUT: Error code */
551: Sqlite *pDb, /* Database handle */
552: const char *zSql /* SQL script to execute */
553: ){
554: if( pErr->rc==SQLITE_OK ){
555: pErr->rc = sqlite3_exec(pDb->db, zSql, 0, 0, &pErr->zErr);
556: }
557: }
558:
559: static Statement *getSqlStatement(
560: Error *pErr, /* IN/OUT: Error code */
561: Sqlite *pDb, /* Database handle */
562: const char *zSql /* SQL statement */
563: ){
564: Statement *pRet;
565: int rc;
566:
567: for(pRet=pDb->pCache; pRet; pRet=pRet->pNext){
568: if( 0==strcmp(sqlite3_sql(pRet->pStmt), zSql) ){
569: return pRet;
570: }
571: }
572:
573: pRet = sqlite3_malloc(sizeof(Statement));
574: rc = sqlite3_prepare_v2(pDb->db, zSql, -1, &pRet->pStmt, 0);
575: if( rc!=SQLITE_OK ){
576: sqlite_error(pErr, pDb, "prepare_v2");
577: return 0;
578: }
579: assert( 0==strcmp(sqlite3_sql(pRet->pStmt), zSql) );
580:
581: pRet->pNext = pDb->pCache;
582: pDb->pCache = pRet;
583: return pRet;
584: }
585:
586: static sqlite3_stmt *getAndBindSqlStatement(
587: Error *pErr, /* IN/OUT: Error code */
588: Sqlite *pDb, /* Database handle */
589: va_list ap /* SQL followed by parameters */
590: ){
591: Statement *pStatement; /* The SQLite statement wrapper */
592: sqlite3_stmt *pStmt; /* The SQLite statement to return */
593: int i; /* Used to iterate through parameters */
594:
595: pStatement = getSqlStatement(pErr, pDb, va_arg(ap, const char *));
596: if( !pStatement ) return 0;
597: pStmt = pStatement->pStmt;
598: for(i=1; i<=sqlite3_bind_parameter_count(pStmt); i++){
599: const char *zName = sqlite3_bind_parameter_name(pStmt, i);
600: void * pArg = va_arg(ap, void*);
601:
602: switch( zName[1] ){
603: case 'i':
604: sqlite3_bind_int64(pStmt, i, *(i64 *)pArg);
605: break;
606:
607: default:
608: pErr->rc = 1;
609: pErr->zErr = sqlite3_mprintf("Cannot discern type: \"%s\"", zName);
610: pStmt = 0;
611: break;
612: }
613: }
614:
615: return pStmt;
616: }
617:
618: static i64 execsql_i64_x(
619: Error *pErr, /* IN/OUT: Error code */
620: Sqlite *pDb, /* Database handle */
621: ... /* SQL and pointers to parameter values */
622: ){
623: i64 iRet = 0;
624: if( pErr->rc==SQLITE_OK ){
625: sqlite3_stmt *pStmt; /* SQL statement to execute */
626: va_list ap; /* ... arguments */
627: int i; /* Used to iterate through parameters */
628: va_start(ap, pDb);
629: pStmt = getAndBindSqlStatement(pErr, pDb, ap);
630: if( pStmt ){
631: int rc;
632: int first = 1;
633: while( SQLITE_ROW==sqlite3_step(pStmt) ){
634: if( first && sqlite3_column_count(pStmt)>0 ){
635: iRet = sqlite3_column_int64(pStmt, 0);
636: }
637: first = 0;
638: }
639: if( SQLITE_OK!=sqlite3_reset(pStmt) ){
640: sqlite_error(pErr, pDb, "reset");
641: }
642: }
643: va_end(ap);
644: }
645: return iRet;
646: }
647:
648: static char * execsql_text_x(
649: Error *pErr, /* IN/OUT: Error code */
650: Sqlite *pDb, /* Database handle */
651: int iSlot, /* Db handle slot to store text in */
652: ... /* SQL and pointers to parameter values */
653: ){
654: char *zRet = 0;
655:
656: if( iSlot>=pDb->nText ){
657: int nByte = sizeof(char *)*(iSlot+1);
658: pDb->aText = (char **)sqlite3_realloc(pDb->aText, nByte);
659: memset(&pDb->aText[pDb->nText], 0, sizeof(char*)*(iSlot+1-pDb->nText));
660: pDb->nText = iSlot+1;
661: }
662:
663: if( pErr->rc==SQLITE_OK ){
664: sqlite3_stmt *pStmt; /* SQL statement to execute */
665: va_list ap; /* ... arguments */
666: int i; /* Used to iterate through parameters */
667: va_start(ap, iSlot);
668: pStmt = getAndBindSqlStatement(pErr, pDb, ap);
669: if( pStmt ){
670: int rc;
671: int first = 1;
672: while( SQLITE_ROW==sqlite3_step(pStmt) ){
673: if( first && sqlite3_column_count(pStmt)>0 ){
674: zRet = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
675: sqlite3_free(pDb->aText[iSlot]);
676: pDb->aText[iSlot] = zRet;
677: }
678: first = 0;
679: }
680: if( SQLITE_OK!=sqlite3_reset(pStmt) ){
681: sqlite_error(pErr, pDb, "reset");
682: }
683: }
684: va_end(ap);
685: }
686:
687: return zRet;
688: }
689:
690: static void integrity_check_x(
691: Error *pErr, /* IN/OUT: Error code */
692: Sqlite *pDb /* Database handle */
693: ){
694: if( pErr->rc==SQLITE_OK ){
695: Statement *pStatement; /* Statement to execute */
696: int rc; /* Return code */
697: char *zErr = 0; /* Integrity check error */
698:
699: pStatement = getSqlStatement(pErr, pDb, "PRAGMA integrity_check");
700: if( pStatement ){
701: sqlite3_stmt *pStmt = pStatement->pStmt;
702: while( SQLITE_ROW==sqlite3_step(pStmt) ){
703: const char *z = sqlite3_column_text(pStmt, 0);
704: if( strcmp(z, "ok") ){
705: if( zErr==0 ){
706: zErr = sqlite3_mprintf("%s", z);
707: }else{
708: zErr = sqlite3_mprintf("%z\n%s", zErr, z);
709: }
710: }
711: }
712: sqlite3_reset(pStmt);
713:
714: if( zErr ){
715: pErr->zErr = zErr;
716: pErr->rc = 1;
717: }
718: }
719: }
720: }
721:
722: static void *launch_thread_main(void *pArg){
723: Thread *p = (Thread *)pArg;
724: return (void *)p->xProc(p->iTid, p->iArg);
725: }
726:
727: static void launch_thread_x(
728: Error *pErr, /* IN/OUT: Error code */
729: Threadset *pThreads, /* Thread set */
730: char *(*xProc)(int, int), /* Proc to run */
731: int iArg /* Argument passed to thread proc */
732: ){
733: if( pErr->rc==SQLITE_OK ){
734: int iTid = ++pThreads->iMaxTid;
735: Thread *p;
736: int rc;
737:
738: p = (Thread *)sqlite3_malloc(sizeof(Thread));
739: memset(p, 0, sizeof(Thread));
740: p->iTid = iTid;
741: p->iArg = iArg;
742: p->xProc = xProc;
743:
744: rc = pthread_create(&p->tid, NULL, launch_thread_main, (void *)p);
745: if( rc!=0 ){
746: system_error(pErr, rc);
747: sqlite3_free(p);
748: }else{
749: p->pNext = pThreads->pThread;
750: pThreads->pThread = p;
751: }
752: }
753: }
754:
755: static void join_all_threads_x(
756: Error *pErr, /* IN/OUT: Error code */
757: Threadset *pThreads /* Thread set */
758: ){
759: Thread *p;
760: Thread *pNext;
761: for(p=pThreads->pThread; p; p=pNext){
762: void *ret;
763: pNext = p->pNext;
764: int rc;
765: rc = pthread_join(p->tid, &ret);
766: if( rc!=0 ){
767: if( pErr->rc==SQLITE_OK ) system_error(pErr, rc);
768: }else{
769: printf("Thread %d says: %s\n", p->iTid, (ret==0 ? "..." : (char *)ret));
770: }
771: sqlite3_free(p);
772: }
773: pThreads->pThread = 0;
774: }
775:
776: static i64 filesize_x(
777: Error *pErr,
778: const char *zFile
779: ){
780: i64 iRet = 0;
781: if( pErr->rc==SQLITE_OK ){
782: struct stat sStat;
783: if( stat(zFile, &sStat) ){
784: iRet = -1;
785: }else{
786: iRet = sStat.st_size;
787: }
788: }
789: return iRet;
790: }
791:
792: static void filecopy_x(
793: Error *pErr,
794: const char *zFrom,
795: const char *zTo
796: ){
797: if( pErr->rc==SQLITE_OK ){
798: i64 nByte = filesize_x(pErr, zFrom);
799: if( nByte<0 ){
800: test_error_x(pErr, sqlite3_mprintf("no such file: %s", zFrom));
801: }else{
802: i64 iOff;
803: char aBuf[1024];
804: int fd1;
805: int fd2;
806: unlink(zTo);
807:
808: fd1 = open(zFrom, O_RDONLY);
809: if( fd1<0 ){
810: system_error(pErr, errno);
811: return;
812: }
813: fd2 = open(zTo, O_RDWR|O_CREAT|O_EXCL, 0644);
814: if( fd2<0 ){
815: system_error(pErr, errno);
816: close(fd1);
817: return;
818: }
819:
820: iOff = 0;
821: while( iOff<nByte ){
822: int nCopy = sizeof(aBuf);
823: if( nCopy+iOff>nByte ){
824: nCopy = nByte - iOff;
825: }
826: if( nCopy!=read(fd1, aBuf, nCopy) ){
827: system_error(pErr, errno);
828: break;
829: }
830: if( nCopy!=write(fd2, aBuf, nCopy) ){
831: system_error(pErr, errno);
832: break;
833: }
834: iOff += nCopy;
835: }
836:
837: close(fd1);
838: close(fd2);
839: }
840: }
841: }
842:
843: /*
844: ** Used by setstoptime() and timetostop().
845: */
846: static double timelimit = 0.0;
847: static sqlite3_vfs *pTimelimitVfs = 0;
848:
849: static void setstoptime_x(
850: Error *pErr, /* IN/OUT: Error code */
851: int nMs /* Milliseconds until "stop time" */
852: ){
853: if( pErr->rc==SQLITE_OK ){
854: double t;
855: int rc;
856: pTimelimitVfs = sqlite3_vfs_find(0);
857: rc = pTimelimitVfs->xCurrentTime(pTimelimitVfs, &t);
858: if( rc!=SQLITE_OK ){
859: pErr->rc = rc;
860: }else{
861: timelimit = t + ((double)nMs)/(1000.0*60.0*60.0*24.0);
862: }
863: }
864: }
865:
866: static int timetostop_x(
867: Error *pErr /* IN/OUT: Error code */
868: ){
869: int ret = 1;
870: if( pErr->rc==SQLITE_OK ){
871: double t;
872: int rc;
873: rc = pTimelimitVfs->xCurrentTime(pTimelimitVfs, &t);
874: if( rc!=SQLITE_OK ){
875: pErr->rc = rc;
876: }else{
877: ret = (t >= timelimit);
878: }
879: }
880: return ret;
881: }
882:
883: /*
884: ** The "Set Error Line" macro.
885: */
886: #define SEL(e) ((e)->iLine = ((e)->rc ? (e)->iLine : __LINE__))
887:
888:
889: /*************************************************************************
890: **************************************************************************
891: **************************************************************************
892: ** End infrastructure. Begin tests.
893: */
894:
895: #define WALTHREAD1_NTHREAD 10
896: #define WALTHREAD3_NTHREAD 6
897:
898: static char *walthread1_thread(int iTid, int iArg){
899: Error err = {0}; /* Error code and message */
900: Sqlite db = {0}; /* SQLite database connection */
901: int nIter = 0; /* Iterations so far */
902:
903: opendb(&err, &db, "test.db", 0);
904: while( !timetostop(&err) ){
905: const char *azSql[] = {
906: "SELECT md5sum(x) FROM t1 WHERE rowid != (SELECT max(rowid) FROM t1)",
907: "SELECT x FROM t1 WHERE rowid = (SELECT max(rowid) FROM t1)",
908: };
909: char *z1, *z2, *z3;
910:
911: execsql(&err, &db, "BEGIN");
912: integrity_check(&err, &db);
913: z1 = execsql_text(&err, &db, 1, azSql[0]);
914: z2 = execsql_text(&err, &db, 2, azSql[1]);
915: z3 = execsql_text(&err, &db, 3, azSql[0]);
916: execsql(&err, &db, "COMMIT");
917:
918: if( strcmp(z1, z2) || strcmp(z1, z3) ){
919: test_error(&err, "Failed read: %s %s %s", z1, z2, z3);
920: }
921:
922: sql_script(&err, &db,
923: "BEGIN;"
924: "INSERT INTO t1 VALUES(randomblob(100));"
925: "INSERT INTO t1 VALUES(randomblob(100));"
926: "INSERT INTO t1 SELECT md5sum(x) FROM t1;"
927: "COMMIT;"
928: );
929: nIter++;
930: }
931: closedb(&err, &db);
932:
933: print_and_free_err(&err);
934: return sqlite3_mprintf("%d iterations", nIter);
935: }
936:
937: static char *walthread1_ckpt_thread(int iTid, int iArg){
938: Error err = {0}; /* Error code and message */
939: Sqlite db = {0}; /* SQLite database connection */
940: int nCkpt = 0; /* Checkpoints so far */
941:
942: opendb(&err, &db, "test.db", 0);
943: while( !timetostop(&err) ){
944: usleep(500*1000);
945: execsql(&err, &db, "PRAGMA wal_checkpoint");
946: if( err.rc==SQLITE_OK ) nCkpt++;
947: clear_error(&err, SQLITE_BUSY);
948: }
949: closedb(&err, &db);
950:
951: print_and_free_err(&err);
952: return sqlite3_mprintf("%d checkpoints", nCkpt);
953: }
954:
955: static void walthread1(int nMs){
956: Error err = {0}; /* Error code and message */
957: Sqlite db = {0}; /* SQLite database connection */
958: Threadset threads = {0}; /* Test threads */
959: int i; /* Iterator variable */
960:
961: opendb(&err, &db, "test.db", 1);
962: sql_script(&err, &db,
963: "PRAGMA journal_mode = WAL;"
964: "CREATE TABLE t1(x PRIMARY KEY);"
965: "INSERT INTO t1 VALUES(randomblob(100));"
966: "INSERT INTO t1 VALUES(randomblob(100));"
967: "INSERT INTO t1 SELECT md5sum(x) FROM t1;"
968: );
969:
970: setstoptime(&err, nMs);
971: for(i=0; i<WALTHREAD1_NTHREAD; i++){
972: launch_thread(&err, &threads, walthread1_thread, 0);
973: }
974: launch_thread(&err, &threads, walthread1_ckpt_thread, 0);
975: join_all_threads(&err, &threads);
976:
977: print_and_free_err(&err);
978: }
979:
980: static char *walthread2_thread(int iTid, int iArg){
981: Error err = {0}; /* Error code and message */
982: Sqlite db = {0}; /* SQLite database connection */
983: int anTrans[2] = {0, 0}; /* Number of WAL and Rollback transactions */
984:
985: const char *zJournal = "PRAGMA journal_mode = WAL";
986: if( iArg ){ zJournal = "PRAGMA journal_mode = DELETE"; }
987:
988: while( !timetostop(&err) ){
989: int journal_exists = 0;
990: int wal_exists = 0;
991:
992: opendb(&err, &db, "test.db", 0);
993:
994: sql_script(&err, &db, zJournal);
995: clear_error(&err, SQLITE_BUSY);
996: sql_script(&err, &db, "BEGIN");
997: sql_script(&err, &db, "INSERT INTO t1 VALUES(NULL, randomblob(100))");
998:
999: journal_exists = (filesize(&err, "test.db-journal") >= 0);
1000: wal_exists = (filesize(&err, "test.db-wal") >= 0);
1001: if( (journal_exists+wal_exists)!=1 ){
1002: test_error(&err, "File system looks incorrect (%d, %d)",
1003: journal_exists, wal_exists
1004: );
1005: }
1006: anTrans[journal_exists]++;
1007:
1008: sql_script(&err, &db, "COMMIT");
1009: integrity_check(&err, &db);
1010: closedb(&err, &db);
1011: }
1012:
1013: print_and_free_err(&err);
1014: return sqlite3_mprintf("W %d R %d", anTrans[0], anTrans[1]);
1015: }
1016:
1017: static void walthread2(int nMs){
1018: Error err = {0};
1019: Sqlite db = {0};
1020: Threadset threads = {0};
1021:
1022: opendb(&err, &db, "test.db", 1);
1023: sql_script(&err, &db, "CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE)");
1024: closedb(&err, &db);
1025:
1026: setstoptime(&err, nMs);
1027: launch_thread(&err, &threads, walthread2_thread, 0);
1028: launch_thread(&err, &threads, walthread2_thread, 0);
1029: launch_thread(&err, &threads, walthread2_thread, 1);
1030: launch_thread(&err, &threads, walthread2_thread, 1);
1031: join_all_threads(&err, &threads);
1032:
1033: print_and_free_err(&err);
1034: }
1035:
1036: static char *walthread3_thread(int iTid, int iArg){
1037: Error err = {0}; /* Error code and message */
1038: Sqlite db = {0}; /* SQLite database connection */
1039: i64 iNextWrite; /* Next value this thread will write */
1040:
1041: opendb(&err, &db, "test.db", 0);
1042: sql_script(&err, &db, "PRAGMA wal_autocheckpoint = 10");
1043:
1044: iNextWrite = iArg+1;
1045: while( 1 ){
1046: i64 sum1;
1047: i64 sum2;
1048: int stop = 0; /* True to stop executing (test timed out) */
1049:
1050: while( 0==(stop = timetostop(&err)) ){
1051: i64 iMax = execsql_i64(&err, &db, "SELECT max(cnt) FROM t1");
1052: if( iMax+1==iNextWrite ) break;
1053: }
1054: if( stop ) break;
1055:
1056: sum1 = execsql_i64(&err, &db, "SELECT sum(cnt) FROM t1");
1057: sum2 = execsql_i64(&err, &db, "SELECT sum(sum1) FROM t1");
1058: execsql_i64(&err, &db,
1059: "INSERT INTO t1 VALUES(:iNextWrite, :iSum1, :iSum2)",
1060: &iNextWrite, &sum1, &sum2
1061: );
1062: integrity_check(&err, &db);
1063:
1064: iNextWrite += WALTHREAD3_NTHREAD;
1065: }
1066:
1067: closedb(&err, &db);
1068: print_and_free_err(&err);
1069: return 0;
1070: }
1071:
1072: static void walthread3(int nMs){
1073: Error err = {0};
1074: Sqlite db = {0};
1075: Threadset threads = {0};
1076: int i;
1077:
1078: opendb(&err, &db, "test.db", 1);
1079: sql_script(&err, &db,
1080: "PRAGMA journal_mode = WAL;"
1081: "CREATE TABLE t1(cnt PRIMARY KEY, sum1, sum2);"
1082: "CREATE INDEX i1 ON t1(sum1);"
1083: "CREATE INDEX i2 ON t1(sum2);"
1084: "INSERT INTO t1 VALUES(0, 0, 0);"
1085: );
1086: closedb(&err, &db);
1087:
1088: setstoptime(&err, nMs);
1089: for(i=0; i<WALTHREAD3_NTHREAD; i++){
1090: launch_thread(&err, &threads, walthread3_thread, i);
1091: }
1092: join_all_threads(&err, &threads);
1093:
1094: print_and_free_err(&err);
1095: }
1096:
1097: static char *walthread4_reader_thread(int iTid, int iArg){
1098: Error err = {0}; /* Error code and message */
1099: Sqlite db = {0}; /* SQLite database connection */
1100:
1101: opendb(&err, &db, "test.db", 0);
1102: while( !timetostop(&err) ){
1103: integrity_check(&err, &db);
1104: }
1105: closedb(&err, &db);
1106:
1107: print_and_free_err(&err);
1108: return 0;
1109: }
1110:
1111: static char *walthread4_writer_thread(int iTid, int iArg){
1112: Error err = {0}; /* Error code and message */
1113: Sqlite db = {0}; /* SQLite database connection */
1114: i64 iRow = 1;
1115:
1116: opendb(&err, &db, "test.db", 0);
1117: sql_script(&err, &db, "PRAGMA wal_autocheckpoint = 15;");
1118: while( !timetostop(&err) ){
1119: execsql_i64(
1120: &err, &db, "REPLACE INTO t1 VALUES(:iRow, randomblob(300))", &iRow
1121: );
1122: iRow++;
1123: if( iRow==10 ) iRow = 0;
1124: }
1125: closedb(&err, &db);
1126:
1127: print_and_free_err(&err);
1128: return 0;
1129: }
1130:
1131: static void walthread4(int nMs){
1132: Error err = {0};
1133: Sqlite db = {0};
1134: Threadset threads = {0};
1135:
1136: opendb(&err, &db, "test.db", 1);
1137: sql_script(&err, &db,
1138: "PRAGMA journal_mode = WAL;"
1139: "CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE);"
1140: );
1141: closedb(&err, &db);
1142:
1143: setstoptime(&err, nMs);
1144: launch_thread(&err, &threads, walthread4_reader_thread, 0);
1145: launch_thread(&err, &threads, walthread4_writer_thread, 0);
1146: join_all_threads(&err, &threads);
1147:
1148: print_and_free_err(&err);
1149: }
1150:
1151: static char *walthread5_thread(int iTid, int iArg){
1152: Error err = {0}; /* Error code and message */
1153: Sqlite db = {0}; /* SQLite database connection */
1154: i64 nRow;
1155:
1156: opendb(&err, &db, "test.db", 0);
1157: nRow = execsql_i64(&err, &db, "SELECT count(*) FROM t1");
1158: closedb(&err, &db);
1159:
1160: if( nRow!=65536 ) test_error(&err, "Bad row count: %d", (int)nRow);
1161: print_and_free_err(&err);
1162: return 0;
1163: }
1164: static void walthread5(int nMs){
1165: Error err = {0};
1166: Sqlite db = {0};
1167: Threadset threads = {0};
1168:
1169: opendb(&err, &db, "test.db", 1);
1170: sql_script(&err, &db,
1171: "PRAGMA wal_autocheckpoint = 0;"
1172: "PRAGMA page_size = 1024;"
1173: "PRAGMA journal_mode = WAL;"
1174: "CREATE TABLE t1(x);"
1175: "BEGIN;"
1176: "INSERT INTO t1 VALUES(randomblob(900));"
1177: "INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 2 */"
1178: "INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 4 */"
1179: "INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 8 */"
1180: "INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 16 */"
1181: "INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 32 */"
1182: "INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 64 */"
1183: "INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 128 */"
1184: "INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 256 */"
1185: "INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 512 */"
1186: "INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 1024 */"
1187: "INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 2048 */"
1188: "INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 4096 */"
1189: "INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 8192 */"
1190: "INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 16384 */"
1191: "INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 32768 */"
1192: "INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 65536 */"
1193: "COMMIT;"
1194: );
1195: filecopy(&err, "test.db", "test_sv.db");
1196: filecopy(&err, "test.db-wal", "test_sv.db-wal");
1197: closedb(&err, &db);
1198:
1199: filecopy(&err, "test_sv.db", "test.db");
1200: filecopy(&err, "test_sv.db-wal", "test.db-wal");
1201:
1202: if( err.rc==SQLITE_OK ){
1203: printf(" WAL file is %d bytes,", (int)filesize(&err,"test.db-wal"));
1204: printf(" DB file is %d.\n", (int)filesize(&err,"test.db"));
1205: }
1206:
1207: setstoptime(&err, nMs);
1208: launch_thread(&err, &threads, walthread5_thread, 0);
1209: launch_thread(&err, &threads, walthread5_thread, 0);
1210: launch_thread(&err, &threads, walthread5_thread, 0);
1211: launch_thread(&err, &threads, walthread5_thread, 0);
1212: launch_thread(&err, &threads, walthread5_thread, 0);
1213: join_all_threads(&err, &threads);
1214:
1215: if( err.rc==SQLITE_OK ){
1216: printf(" WAL file is %d bytes,", (int)filesize(&err,"test.db-wal"));
1217: printf(" DB file is %d.\n", (int)filesize(&err,"test.db"));
1218: }
1219:
1220: print_and_free_err(&err);
1221: }
1222:
1223: /*------------------------------------------------------------------------
1224: ** Test case "cgt_pager_1"
1225: */
1226: #define CALLGRINDTEST1_NROW 10000
1227: static void cgt_pager_1_populate(Error *pErr, Sqlite *pDb){
1228: const char *zInsert = "INSERT INTO t1 VALUES(:iRow, zeroblob(:iBlob))";
1229: i64 iRow;
1230: sql_script(pErr, pDb, "BEGIN");
1231: for(iRow=1; iRow<=CALLGRINDTEST1_NROW; iRow++){
1232: i64 iBlob = 600 + (iRow%300);
1233: execsql(pErr, pDb, zInsert, &iRow, &iBlob);
1234: }
1235: sql_script(pErr, pDb, "COMMIT");
1236: }
1237: static void cgt_pager_1_update(Error *pErr, Sqlite *pDb){
1238: const char *zUpdate = "UPDATE t1 SET b = zeroblob(:iBlob) WHERE a = :iRow";
1239: i64 iRow;
1240: sql_script(pErr, pDb, "BEGIN");
1241: for(iRow=1; iRow<=CALLGRINDTEST1_NROW; iRow++){
1242: i64 iBlob = 600 + ((iRow+100)%300);
1243: execsql(pErr, pDb, zUpdate, &iBlob, &iRow);
1244: }
1245: sql_script(pErr, pDb, "COMMIT");
1246: }
1247: static void cgt_pager_1_read(Error *pErr, Sqlite *pDb){
1248: i64 iRow;
1249: sql_script(pErr, pDb, "BEGIN");
1250: for(iRow=1; iRow<=CALLGRINDTEST1_NROW; iRow++){
1251: execsql(pErr, pDb, "SELECT * FROM t1 WHERE a = :iRow", &iRow);
1252: }
1253: sql_script(pErr, pDb, "COMMIT");
1254: }
1255: static void cgt_pager_1(int nMs){
1256: void (*xSub)(Error *, Sqlite *);
1257: Error err = {0};
1258: Sqlite db = {0};
1259:
1260: opendb(&err, &db, "test.db", 1);
1261: sql_script(&err, &db,
1262: "PRAGMA cache_size = 2000;"
1263: "PRAGMA page_size = 1024;"
1264: "CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB);"
1265: );
1266:
1267: xSub = cgt_pager_1_populate; xSub(&err, &db);
1268: xSub = cgt_pager_1_update; xSub(&err, &db);
1269: xSub = cgt_pager_1_read; xSub(&err, &db);
1270:
1271: closedb(&err, &db);
1272: print_and_free_err(&err);
1273: }
1274:
1275: /*------------------------------------------------------------------------
1276: ** Test case "dynamic_triggers"
1277: **
1278: ** Two threads executing statements that cause deeply nested triggers
1279: ** to fire. And one thread busily creating and deleting triggers. This
1280: ** is an attempt to find a bug reported to us.
1281: */
1282:
1283: static char *dynamic_triggers_1(int iTid, int iArg){
1284: Error err = {0}; /* Error code and message */
1285: Sqlite db = {0}; /* SQLite database connection */
1286: int nDrop = 0;
1287: int nCreate = 0;
1288:
1289: opendb(&err, &db, "test.db", 0);
1290: while( !timetostop(&err) ){
1291: int i;
1292:
1293: for(i=1; i<9; i++){
1294: char *zSql = sqlite3_mprintf(
1295: "CREATE TRIGGER itr%d BEFORE INSERT ON t%d BEGIN "
1296: "INSERT INTO t%d VALUES(new.x, new.y);"
1297: "END;", i, i, i+1
1298: );
1299: execsql(&err, &db, zSql);
1300: sqlite3_free(zSql);
1301: nCreate++;
1302: }
1303:
1304: for(i=1; i<9; i++){
1305: char *zSql = sqlite3_mprintf(
1306: "CREATE TRIGGER dtr%d BEFORE DELETE ON t%d BEGIN "
1307: "DELETE FROM t%d WHERE x = old.x; "
1308: "END;", i, i, i+1
1309: );
1310: execsql(&err, &db, zSql);
1311: sqlite3_free(zSql);
1312: nCreate++;
1313: }
1314:
1315: for(i=1; i<9; i++){
1316: char *zSql = sqlite3_mprintf("DROP TRIGGER itr%d", i);
1317: execsql(&err, &db, zSql);
1318: sqlite3_free(zSql);
1319: nDrop++;
1320: }
1321:
1322: for(i=1; i<9; i++){
1323: char *zSql = sqlite3_mprintf("DROP TRIGGER dtr%d", i);
1324: execsql(&err, &db, zSql);
1325: sqlite3_free(zSql);
1326: nDrop++;
1327: }
1328: }
1329:
1330: print_and_free_err(&err);
1331: return sqlite3_mprintf("%d created, %d dropped", nCreate, nDrop);
1332: }
1333:
1334: static char *dynamic_triggers_2(int iTid, int iArg){
1335: Error err = {0}; /* Error code and message */
1336: Sqlite db = {0}; /* SQLite database connection */
1337: i64 iVal = 0;
1338: int nInsert = 0;
1339: int nDelete = 0;
1340:
1341: opendb(&err, &db, "test.db", 0);
1342: while( !timetostop(&err) ){
1343: do {
1344: iVal = (iVal+1)%100;
1345: execsql(&err, &db, "INSERT INTO t1 VALUES(:iX, :iY+1)", &iVal, &iVal);
1346: nInsert++;
1347: } while( iVal );
1348:
1349: do {
1350: iVal = (iVal+1)%100;
1351: execsql(&err, &db, "DELETE FROM t1 WHERE x = :iX", &iVal);
1352: nDelete++;
1353: } while( iVal );
1354: }
1355:
1356: print_and_free_err(&err);
1357: return sqlite3_mprintf("%d inserts, %d deletes", nInsert, nDelete);
1358: }
1359:
1360: static void dynamic_triggers(int nMs){
1361: Error err = {0};
1362: Sqlite db = {0};
1363: Threadset threads = {0};
1364:
1365: opendb(&err, &db, "test.db", 1);
1366: sql_script(&err, &db,
1367: "PRAGMA page_size = 1024;"
1368: "PRAGMA journal_mode = WAL;"
1369: "CREATE TABLE t1(x, y);"
1370: "CREATE TABLE t2(x, y);"
1371: "CREATE TABLE t3(x, y);"
1372: "CREATE TABLE t4(x, y);"
1373: "CREATE TABLE t5(x, y);"
1374: "CREATE TABLE t6(x, y);"
1375: "CREATE TABLE t7(x, y);"
1376: "CREATE TABLE t8(x, y);"
1377: "CREATE TABLE t9(x, y);"
1378: );
1379:
1380: setstoptime(&err, nMs);
1381:
1382: sqlite3_enable_shared_cache(1);
1383: launch_thread(&err, &threads, dynamic_triggers_2, 0);
1384: launch_thread(&err, &threads, dynamic_triggers_2, 0);
1385: sqlite3_enable_shared_cache(0);
1386:
1387: sleep(2);
1388:
1389: launch_thread(&err, &threads, dynamic_triggers_2, 0);
1390: launch_thread(&err, &threads, dynamic_triggers_1, 0);
1391:
1392: join_all_threads(&err, &threads);
1393:
1394: print_and_free_err(&err);
1395: }
1396:
1397: #include "tt3_checkpoint.c"
1398:
1399: int main(int argc, char **argv){
1400: struct ThreadTest {
1401: void (*xTest)(int);
1402: const char *zTest;
1403: int nMs;
1404: } aTest[] = {
1405: { walthread1, "walthread1", 20000 },
1406: { walthread2, "walthread2", 20000 },
1407: { walthread3, "walthread3", 20000 },
1408: { walthread4, "walthread4", 20000 },
1409: { walthread5, "walthread5", 1000 },
1410: { walthread5, "walthread5", 1000 },
1411:
1412: { cgt_pager_1, "cgt_pager_1", 0 },
1413: { dynamic_triggers, "dynamic_triggers", 20000 },
1414:
1415: { checkpoint_starvation_1, "checkpoint_starvation_1", 10000 },
1416: { checkpoint_starvation_2, "checkpoint_starvation_2", 10000 },
1417: };
1418:
1419: int i;
1420: char *zTest = 0;
1421: int nTest = 0;
1422: int bTestfound = 0;
1423: int bPrefix = 0;
1424:
1425: if( argc>2 ) goto usage;
1426: if( argc==2 ){
1427: zTest = argv[1];
1428: nTest = strlen(zTest);
1429: if( zTest[nTest-1]=='*' ){
1430: nTest--;
1431: bPrefix = 1;
1432: }
1433: }
1434:
1435: sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
1436:
1437: for(i=0; i<sizeof(aTest)/sizeof(aTest[0]); i++){
1438: char const *z = aTest[i].zTest;
1439: int n = strlen(z);
1440: if( !zTest || ((bPrefix || n==nTest) && 0==strncmp(zTest, z, nTest)) ){
1441: printf("Running %s for %d seconds...\n", z, aTest[i].nMs/1000);
1442: aTest[i].xTest(aTest[i].nMs);
1443: bTestfound++;
1444: }
1445: }
1446: if( bTestfound==0 ) goto usage;
1447:
1448: printf("Total of %d errors across all tests\n", nGlobalErr);
1449: return (nGlobalErr>0 ? 255 : 0);
1450:
1451: usage:
1452: printf("Usage: %s [testname|testprefix*]\n", argv[0]);
1453: printf("Available tests are:\n");
1454: for(i=0; i<sizeof(aTest)/sizeof(aTest[0]); i++){
1455: printf(" %s\n", aTest[i].zTest);
1456: }
1457:
1458: return 254;
1459: }
1460:
1461:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>