Hello.
It seems to me I've found a bug in the Sqlite. I have database with two tables. TestTable is ordinary table, TestTableRTree is virtual rtree table. Each table has two records. Also database has after update trigger for table TestTable, this trigger updates corresponding record in the table TestTableRTree. The problem appears if I have a select statement and update statement which changes the current record of the select statement. After execution update statement sqlite3_step returns SQLITE_ROW instead of SQLITE_DONE for the select statement. RowID of the current row of the select statement does not change after this sqlite3_step. Pseudocode: 1. Query1.CreateAndExecute( "SELECT ... FROM TestTable INNER JOIN TestTableRTree ON ... WHERE (...)") // This query should return one and only record 2. Query2.Create( "UPDATE TestTable SET (....) WHERE (...) // Trying to update currect record of the Query1, this cause execution trigger that changes record in the TestTableRTree 3. Query2.Execute(); 4. Query1.MoveNext(); // This call is finished with code SQLITE_ROW, not SQLITE_DONE. It is error The bug is not reproduced if: 1. Query1 has no inner join, in other words if Query1 is query to TestTable only or 2. There is no after update trigger in the table TestTable or 3. There is no update execution on stage 3 C++ code( SQLITE_ENABLE_RTREE should be defined! ): int Test(bool bPerformUpdate) { const char szFileName[]="c:/test.db3"; DeleteFile( szFileName ); sqlite3* db=0; int nValue=sqlite3_open( szFileName, &db ); if ( SQLITE_OK != nValue || !db ) { std::cout<<"sqlite3_open returned "<<nValue<<std::endl; return -1; } const char szCreatedDBSQL[]= "DROP TABLE IF EXISTS TestTable;\ DROP TABLE IF EXISTS TestTable_rtreeindex;\ CREATE TABLE TestTable(x_1 INTEGER NOT NULL DEFAULT 0 , x_8 BLOB NULL , x_65536 REAL NULL DEFAULT 0 , x_65537 TEXT NULL , x_65538 TEXT NULL , x_65539 TEXT NULL , x_65540 TEXT NULL , x_65541 INTEGER PRIMARY KEY NOT NULL DEFAULT 1 );\ CREATE UNIQUE INDEX TestTable_x_65541_index ON TestTable (x_65541);\ CREATE TRIGGER TestTable_on_update_trigger AFTER UPDATE ON TestTable BEGIN UPDATE TestTable_rtreeindex SET x_2 = 0., x_3 = 0., x_4 = 0., x_5 = 0. WHERE ID=old.OID; END;\ CREATE VIRTUAL TABLE TestTable_rtreeindex USING rtree ( ID INTEGER PRIMARY KEY , x_2 REAL, x_3 REAL, x_5 REAL, x_4 REAL);\ INSERT INTO TestTable (x_1, x_8, x_65536, x_65537, x_65538, x_65539, x_65540, x_65541 ) VALUES ( 7, 'SomeBlob', 64619678.0, NULL, 4, NULL, 'SomeText', 3);\ INSERT INTO TestTable (x_1, x_8, x_65536, x_65537, x_65538, x_65539, x_65540, x_65541 ) VALUES ( 07, 'SomeAnotherBlob', -398444.0, 'SomeAnotherText', 6, NULL, NULL, 4 );\ INSERT INTO TestTable_rtreeindex (ID, x_2, x_3, x_5, x_4 ) VALUES ( 4, 4., 4., 4., 4. );\ INSERT INTO TestTable_rtreeindex (ID, x_2, x_3, x_5, x_4 ) VALUES ( 3, 3., 3., 3., 3. );\ "; char* szErrorMsg=0; int nRes=sqlite3_exec( db, szCreatedDBSQL, 0, 0, &szErrorMsg ); if ( SQLITE_OK != nRes ) { std::cout<<"exec_sql failed. sqlite3_exec returned "<<nRes<<". Error is "<<szErrorMsg<<std::endl; sqlite3_free(szErrorMsg); return false; } sqlite3_stmt* select_stmt=0; if ( SQLITE_OK != sqlite3_prepare_v2( db,"SELECT L.x_65541,L.x_1,L.x_8,L.x_65536,LI.x_2,LI.x_4,LI.x_3,LI.x_5, L.OID FROM TestTable L, TestTable_rtreeindex LI WHERE L.OID=LI.ID AND (L.x_65536=?)" , -1, &select_stmt, 0 ) ) { std::cout<<"sqlite3_prepare_v2 failed"<<std::endl; return -2; } if ( SQLITE_OK != sqlite3_bind_int( select_stmt, 1, -398444 ) ) { std::cout<<"sqlite3_bind_int failed"<<std::endl; return -3; } int nResult=0; nResult=sqlite3_step( select_stmt ); if ( SQLITE_ROW != nResult ) { std::cout<<"sqlite3_step failed. Error is "<<nResult<<std::endl; return -4; } sqlite3_stmt* update_stmt=0; if ( SQLITE_OK != sqlite3_prepare_v2( db, "UPDATE TestTable SET x_65541 = ?, x_1= ?, x_8 = ?, x_65536 = ? WHERE OID = ?" , -1, &update_stmt, 0 ) ) { std::cout<<"sqlite3_prepare_v2 failed"<<std::endl; return -109; } if ( SQLITE_OK != sqlite3_bind_int( update_stmt, 1, 4 ) ) { std::cout<<"sqlite3_bind_int failed"<<std::endl; return -110; } unsigned char uc=7; if ( SQLITE_OK != sqlite3_bind_int( update_stmt, 2, uc ) ) { std::cout<<"sqlite3_bind_int failed"<<std::endl; return -112; } std::vector<char> x; int nBytes=sqlite3_column_bytes( select_stmt, 2 ); if ( nBytes<0 ) { std::cout<<"sqlite3_column_bytes returned "<<nBytes<<std::endl; return -113; } if ( nBytes!=0 ) { x.resize( nBytes ); const void * pX=sqlite3_column_blob( select_stmt, 2 ); memcpy( &*x.begin(), pX, nBytes ); } if ( SQLITE_OK != sqlite3_bind_blob( update_stmt, 3, &*x.begin(), x.size(), 0 ) ) { std::cout<<"sqlite3_bind_int failed"<<std::endl; return -113; } if ( SQLITE_OK != sqlite3_bind_int( update_stmt, 4, -398444 ) ) { std::cout<<"sqlite3_bind_int failed"<<std::endl; return -114; } if ( SQLITE_OK != sqlite3_bind_int( update_stmt, 5, 4 ) ) { std::cout<<"sqlite3_bind_int failed"<<std::endl; return -115; } if ( bPerformUpdate ) { if ( SQLITE_DONE != sqlite3_step( update_stmt ) ) { std::cout<<"update.execute failed"<<std::endl; return -116; } } nResult=sqlite3_step( select_stmt ); if ( SQLITE_ROW == nResult ) { std::cout<<"ERROR: move_next2 successed"<<std::endl; return -117; } else if ( SQLITE_DONE != nResult ) { std::cout<<"move_next2 returned "<<nResult<<std::endl; return -118; } std::cout<<"OK"<<std::endl; if ( update_stmt ) { sqlite3_finalize( update_stmt ); update_stmt = 0; } if ( select_stmt ) { sqlite3_finalize( select_stmt ); select_stmt = 0; } if ( db ) { sqlite3_close(db); db=0; } return 0; } int _tmain(int argc, _TCHAR* argv[]) { Test( false ); Test( true ); } If we call function Test with argument equal to false then this function perform no update and everything is correct. If we call function Test with argument equal to true then we can see reproduced bug. The bug was reproduced on Windows XP + MS Visual C++ 2010. Sqlite version is 3.7.6.1. Best wishes, Osipov Andrey. _______________________________________________ sqlite-users mailing list sqlite-users@sqlite.org http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users