www.pudn.com > CppSQLite_3_1_demo_and_src.zip > CppSQLite3DemoMT.cpp


//////////////////////////////////////////////////////////////////////////////// 
// CppSQLite3 - A C++ wrapper around the SQLite3 embedded database library. 
// 
// Copyright (c) 2004 Rob Groves. All Rights Reserved. rob.groves@btinternet.com 
//  
// Permission to use, copy, modify, and distribute this software and its 
// documentation for any purpose, without fee, and without a written 
// agreement, is hereby granted, provided that the above copyright notice,  
// this paragraph and the following two paragraphs appear in all copies,  
// modifications, and distributions. 
// 
// IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, 
// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST 
// PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, 
// EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
// 
// THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT 
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
// PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF 
// ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION 
// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 
// 
// V3.0		03/08/2004	-Initial Version for sqlite3 
//////////////////////////////////////////////////////////////////////////////// 
#include "CppSQLite3.h" 
#include  
#include  
#include  
#include  
#include  
 
const char* gszFile = "C:\\test.db"; 
int nThreads; 
 
using namespace std; 
 
void LongQueryThreadProc(void* p) 
{ 
	CppSQLite3DB* pdb = (CppSQLite3DB*)p; 
 
	try 
	{ 
		// Meaningless query, with sub-query to slow things down 
		const char* szSQL = "select d.dayno, sum(numcalls) " 
							"from details d " 
							"where dayno+numcalls in " 
							"(select d2.dayno+d2.numcalls from details d2) " 
							"group by dayno order by 1;"; 
 
		cout << "LongQueryThreadProc: starting query" << endl; 
		CppSQLite3Query q = pdb->execQuery(szSQL); 
 
		cout << "LongQueryThreadProc: "; 
		for (int fld = 0; fld < q.numFields(); fld++) 
		{ 
			cout << q.fieldName(fld) << "|"; 
		} 
		cout << endl; 
 
		while (!q.eof()) 
		{ 
			cout << "LongQueryThreadProc: "; 
			cout << q.fieldValue(0) << "|"; 
			cout << q.fieldValue(1) << "|" << endl; 
			q.nextRow(); 
		} 
	} 
	catch (CppSQLite3Exception& e) 
	{ 
		cout << "LongQueryThreadProc: " << e.errorCode() << ":" << e.errorMessage() << endl; 
	} 
 
	nThreads--; 
} 
 
 
void ReadLockThreadProc(void* p) 
{ 
	CppSQLite3DB db; 
 
	try 
	{ 
		db.open(gszFile); 
 
		// access rows to lock table 
		cout << "ReadLockThreadProc: creating read lock" << endl; 
 
		CppSQLite3Query q = db.execQuery("select * from details where dayno = 1;"); 
 
		int nLockSeconds(5); 
 
		for (int i = 0; i < nLockSeconds; i++) 
		{ 
			Sleep(1000); 
		} 
 
		q.finalize(); 
		cout << "ReadLockThreadProc: released read lock" << endl; 
	} 
	catch (CppSQLite3Exception& e) 
	{ 
		cout << "ReadLockThreadProc: " << e.errorCode() << ":" << e.errorMessage() << endl; 
	} 
 
	nThreads--; 
} 
 
 
void WriteLockThreadProc(void* p) 
{ 
	CppSQLite3DB db; 
 
	try 
	{ 
		db.open(gszFile); 
		db.setBusyTimeout(20000); 
 
		// access rows to lock table 
		cout << "WriteLockThreadProc: creating write lock" << endl; 
		db.execDML("begin transaction;"); 
		db.execDML("update details set numcalls = 10 where dayno = 1;"); 
 
		int nLockSeconds(5); 
 
		for (int i = 0; i < nLockSeconds; i++) 
		{ 
			Sleep(1000); 
		} 
 
		db.execDML("commit transaction;"); 
		cout << "WriteLockThreadProc: released write lock" << endl; 
	} 
	catch (CppSQLite3Exception& e) 
	{ 
		cout << "WriteLockThreadProc: " << e.errorCode() << ":" << e.errorMessage() << endl; 
	} 
 
	nThreads--; 
} 
 
 
int main(int argc, char** argv) 
{ 
	try 
	{ 
		cout << "SQLite Version: " << CppSQLite3DB::SQLiteVersion() << endl; 
 
		remove(gszFile); 
 
		CppSQLite3DB db; 
 
		cout << endl << "Main thread: Opening DB." << endl; 
		db.open(gszFile); 
		cout << "Main thread: Opened DB." << endl; 
 
		//////////////////////////////////////////////////////////////////////////////// 
		// Create a largish table to use in later tests 
		// For fast PCs increase nRows 
		//////////////////////////////////////////////////////////////////////////////// 
		int nRows(100000); 
 
		cout << endl << "Main thread: creating " << nRows << " rows" << endl; 
		db.execDML("create table details (dayno int, numcalls int);"); 
		db.execDML("begin transaction;"); 
 
		srand((unsigned)time(0)); 
 
		for (int i = 0; i < nRows; i++) 
		{ 
			char buf[128]; 
			sprintf(buf, "insert into details values (%d, %d);", 
					rand()%7, rand()); 
			db.execDML(buf); 
		} 
 
		db.execDML("commit transaction;"); 
		cout << "Main thread: created " << nRows << " rows" << endl; 
 
 
		//////////////////////////////////////////////////////////////////////////////// 
		// INTERRUPT TEST 
		// Create thread to run a longish query that we will interrupt from main thread. 
		// Note that we pass the DB as a parameter to the thread, as sqlite_interrupt() 
		// must be used on the same CppSQLite instance that is running the operation 
		// to be interrupted. 
		//////////////////////////////////////////////////////////////////////////////// 
		cout << endl << "Interrupt test" << endl; 
		nThreads = 1; 
		_beginthread(LongQueryThreadProc, 0, &db); 
		Sleep(1000); 
		db.interrupt(); 
 
		cout << "Waiting for LongQueryThreadProc" << endl; 
		while (nThreads) Sleep(100); 
		cout << "Done waiting for LongQueryThreadProc" << endl; 
 
 
		//////////////////////////////////////////////////////////////////////////////// 
		// BUSY TEST1 on execDML() 
		// Create thread that creates a write lock. We will then try to work on 
		// that table in the main thread, and demonstrate SQLite's retry mechanism. 
		// Main thread will timeout as lock thread has longer 20 second timeout 
		//////////////////////////////////////////////////////////////////////////////// 
		cout << endl << "SQLITE_BUSY test1 on CppSQLite3DB::execDML()" << endl; 
		nThreads = 1; 
		_beginthread(WriteLockThreadProc, 0, 0); 
		Sleep(2000); 
 
		try 
		{ 
			db.setBusyTimeout(10000); 
			int nRows = db.execDML("update details set numcalls = 100 where dayno = 1;"); 
			cout << "Main thread: updated " << nRows << " rows" << endl; 
		} 
		catch (CppSQLite3Exception& e) 
		{ 
			cout << "Main thread: " << e.errorCode() << ":" << e.errorMessage() << endl; 
		} 
		while (nThreads) Sleep(100); 
 
 
		//////////////////////////////////////////////////////////////////////////////// 
		// BUSY TEST2 on execDML() 
		// Create thread that creates a write lock. We will then try to work on 
		// that table in the main thread, and demonstrate SQLite's retry mechanism. 
		// This time the thread will timeout as main thread has longer timeout set 
		// Only works if DLL compiled with SQLITE_BUSY_RESERVED_LOCK defined 
		//////////////////////////////////////////////////////////////////////////////// 
		cout << endl << "SQLITE_BUSY test2 on CppSQLite3DB::execDML()" << endl; 
		nThreads = 1; 
		_beginthread(WriteLockThreadProc, 0, 0); 
		Sleep(2000); 
 
		try 
		{ 
			db.setBusyTimeout(30000); 
			int nRows = db.execDML("update details set numcalls = 100 where dayno = 1;"); 
			cout << "Main thread: updated " << nRows << " rows" << endl; 
		} 
		catch (CppSQLite3Exception& e) 
		{ 
			cout << "Main thread: " << e.errorCode() << ":" << e.errorMessage() << endl; 
		} 
		while (nThreads) Sleep(100); 
 
 
		//////////////////////////////////////////////////////////////////////////////// 
		// BUSY TEST3 on execDML() 
		// Create thread that read locks a table for 5 secs. We will then try to work on 
		// that table in the main thread, and demonstrate SQLite's retry mechanism. 
		// Main thread will retry until read lock is released 
		//////////////////////////////////////////////////////////////////////////////// 
		cout << endl << "SQLITE_BUSY test3 on CppSQLite3DB::execDML()" << endl; 
		nThreads = 1; 
		_beginthread(ReadLockThreadProc, 0, 0); 
		Sleep(2000); 
 
		try 
		{ 
			db.setBusyTimeout(10000); 
			int nRows = db.execDML("update details set numcalls = 100 where dayno = 1;"); 
			cout << "Main thread: updated " << nRows << " rows" << endl; 
		} 
		catch (CppSQLite3Exception& e) 
		{ 
			cout << "Main thread: " << e.errorCode() << ":" << e.errorMessage() << endl; 
		} 
		while (nThreads) Sleep(100); 
 
 
	    //////////////////////////////////////////////////////////////////////////////// 
		// BUSY TEST1 on pre-compiled DML 
		// Create thread that creates a write lock. We will then try to work on 
		// that table in the main thread, and demonstrate SQLite's retry mechanism. 
		// Main thread will timeout as lock thread has longer 20 second timeout 
		//////////////////////////////////////////////////////////////////////////////// 
		cout << endl << "SQLITE_BUSY test1 on pre-compiled DML" << endl; 
		nThreads = 1; 
		_beginthread(WriteLockThreadProc, 0, 0); 
		Sleep(1000); 
 
		try 
		{ 
			db.setBusyTimeout(10000); 
			CppSQLite3Statement stmt = db.compileStatement("update details set numcalls = 100 where dayno = 1;"); 
			stmt.execDML(); 
			cout << "Main thread: executed pre-compiled DML" << endl; 
		} 
		catch (CppSQLite3Exception& e) 
		{ 
			cout << "Main thread: " << e.errorCode() << ":" << e.errorMessage() << endl; 
		} 
		while (nThreads) Sleep(100); 
 
 
		//////////////////////////////////////////////////////////////////////////////// 
		// BUSY TEST2 on pre-compiled DML 
		// Create thread that creates a write lock. We will then try to work on 
		// that table in the main thread, and demonstrate SQLite's retry mechanism. 
		// This time the thread will timeout as main thread has longer timeout set 
		// Only works if DLL compiled with SQLITE_BUSY_RESERVED_LOCK defined 
		//////////////////////////////////////////////////////////////////////////////// 
		cout << endl << "SQLITE_BUSY test2 on pre-compiled DML" << endl; 
		nThreads = 1; 
		_beginthread(WriteLockThreadProc, 0, 0); 
		Sleep(1000); 
 
		try 
		{ 
			db.setBusyTimeout(30000); 
			CppSQLite3Statement stmt = db.compileStatement("update details set numcalls = 100 where dayno = 1;"); 
			stmt.execDML(); 
			cout << "Main thread: executed pre-compiled DML" << endl; 
		} 
		catch (CppSQLite3Exception& e) 
		{ 
			cout << "Main thread: " << e.errorCode() << ":" << e.errorMessage() << endl; 
		} 
		while (nThreads) Sleep(100); 
 
 
		//////////////////////////////////////////////////////////////////////////////// 
		// BUSY TEST3 on pre-compiled DML 
		// Create thread that read locks a table for 5 secs. We will then try to work on 
		// that table in the main thread, and demonstrate SQLite's retry mechanism. 
		// Main thread will retry until read lock is released 
		//////////////////////////////////////////////////////////////////////////////// 
		cout << endl << "SQLITE_BUSY test3 on pre-compiled DML" << endl; 
		nThreads = 1; 
		_beginthread(ReadLockThreadProc, 0, 0); 
		Sleep(1000); 
 
		try 
		{ 
			db.setBusyTimeout(10000); 
			CppSQLite3Statement stmt = db.compileStatement("update details set numcalls = 100 where dayno = 1;"); 
			stmt.execDML(); 
			cout << "Main thread: executed pre-compiled DML" << endl; 
		} 
		catch (CppSQLite3Exception& e) 
		{ 
			cout << "Main thread: " << e.errorCode() << ":" << e.errorMessage() << endl; 
		} 
		while (nThreads) Sleep(100); 
	} 
	catch (CppSQLite3Exception& e) 
	{ 
		cout << e.errorCode() << ":" << e.errorMessage() << endl; 
	} 
 
 
	//////////////////////////////////////////////////////////////////////////////// 
	// Loop until user enters q or Q 
	//////////////////////////////////////////////////////////////////////////////// 
	char c(' '); 
 
	while (c != 'q' && c != 'Q') 
	{ 
		cout << "Press q then enter to quit: "; 
		cin >> c; 
	} 
	return 0; 
}