Hello? ! 
?
I'm using sqlite for a project and with this specific database
https://dev.dadbiz.es/tmp/odoo.db.zip (12MB compressed / 38MB uncompressed)
this is happening: 
?
-1 Registering an sqlite3_trace function when trying to delete a record just
inserted on the table "res_users" the registered sqlite3_trace function is
called lots of times and sometimes it segfaults (I think stack overflow), I
think it enters in a unintended loop. 
?
-2 If we do a dump "sqlite3 odoo.db .dump > odoo.db.sql" and try to recreate
the database with "sqlite3 new-odoo.db < odoo.db.sql" we get errors for
tables/views declarations out of order (trying to create a view
https://www.endad.eu/tmp/odoo.db.zipthat refer to other views not yet
created). 
?
Attached there is the simple "C" test file with a shell file to make it with
the flags I use on this project. 
?
This database uses a lot of foreign keys. 
?
The trigger on the "res_users" table is very simple: 
----- 
BEFORE DELETE ON "res_users" 
BEGIN 
??? SELECT RAISE(ABORT, 'Can not remove root/admin user!') 
??? WHERE OLD.id = 1; 
END; 
----- 
?
I've also tested with a fresh sqlite3.c/h from
https://www.sqlite.org/snapshot/sqlite-amalgamation-201507231639.zip. 
?
When tested with a single table with the above trigger with a fresh database
the test program behaves as expected. 
----- 
CREATE TABLE IF NOT EXISTS tbl(id? INTEGER PRIMARY KEY, name varchar); 
INSERT OR IGNORE INTO tbl(id, name) VALUES 
(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'); 
CREATE TRIGGER IF NOT EXISTS tbl_delete_trigger BEFORE DELETE ON tbl 
BEGIN 
??? SELECT RAISE(ABORT, 'Can not remove root/admin user!') WHERE OLD.id =
1; 
END; 
----- 
?
?
I found a small test that shows how to create a database that after ".dump"
will not properly be restored. 
?
After writing to you about this bug with sqlite3_trace/trigger I start
thinking what I did with this database (odoo.db) that could possibly make
it's ".dump" not usable to restore and I found the reason. 
?
On that database I was constantly droping and recreating tables/views with
slight different fields and that seems what makes sqlite3 get lost. 
?
Example that creates a database not correctly restorable: 
-------- 
begin; 
create table if not exists tbl(id integer primary key, name varchar); 
insert or ignore into tbl(id, name) values (1,'a'), (2, 'b'); 
create view if not exists tbl_view as select * from tbl; 
create view if not exists tbl_view_view as select * from tbl_view; 
drop view if exists tbl_view; 
create view if not exists tbl_view as select * from tbl; 
end; 
-------- 
?
After creating a database with the above sql we get the following from
".dump": 
-------- 
PRAGMA foreign_keys=OFF; 
BEGIN TRANSACTION; 
CREATE TABLE tbl(id integer primary key, name varchar); 
INSERT INTO "tbl" VALUES(1,'a'); 
INSERT INTO "tbl" VALUES(2,'b'); 
CREATE VIEW tbl_view_view as select * from tbl_view;??? --<<<<<< here we
are trying to create a view on another view not yet created 
CREATE VIEW tbl_view as select * from tbl; 
COMMIT; 
-------- 
?
On the ".dump"/".restore" problem it seems that sqlite3 shell rely on
sqlite3_master rowid order to perform the ".dump" and when we drop/recreate a
table/view that other tables/views depends sqlite3 do not detect it and
simply add a new entry at the end of sqlite3_master. 
?
?
-------- shell script to make the bug test program 
MYINC=$HOME/dev/sqlite3 
#MYINC=. 
?
gcc \ 
??? -DTHREADSAFE=1 \ 
??? -DSQLITE_DEFAULT_FILE_FORMAT=4 \ 
??? -DSQLITE_DEFAULT_AUTOVACUUM=1 \ 
??? -DSQLITE_DEFAULT_FOREIGN_KEYS=  1 \ 
??? -DSQLITE_ENABLE_COLUMN_METADATA=1 \ 
??? -DSQLITE_ENABLE_FTS4=1 \ 
??? -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 \ 
??? -DSQLITE_ENABLE_UNLOCK_NOTIFY=1 \ 
??? -DSQLITE_ENABLE_RTREE=1 \ 
??? -DSQLITE_ENABLE_STAT4=1 \ 
??? -DSQLITE_OMIT_TCL_VARIABLE=1 \ 
??? -DSQLITE_USE_URI=1 \ 
??? -DSQLITE_SOUNDEX=1\ 
??? -o test-sqlite-bug test-sqlite-bug.c -I $MYINC $MYINC/sqlite3.c
-lpthread -lm -ldl 
--------- 
--------- test-sqlite-bug.c 
#include <stdio.h> 
#include "sqlite3.h" 
?
static const char test_sql[] =? 
??? "CREATE TABLE IF NOT EXISTS tbl(id? INTEGER PRIMARY KEY, name
varchar);" 
??? "INSERT OR IGNORE INTO tbl(id, name) VALUES " 
??? "(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd');" 
??? "CREATE TRIGGER IF NOT EXISTS tbl_delete_trigger BEFORE DELETE ON tbl
" 
??? "BEGIN" 
??? " ??? SELECT RAISE(ABORT, 'Can not remove root/admin user!') WHERE
OLD.id = 1;" 
??? "END;"; 
?
static void db_trace_callback(void *user, const char *sql) 
{ 
??? printf("SQL: %s\n", sql ? sql : "??"); 
} 
?
static void insertRecord(sqlite3 *db) 
{ 
??? char *errmsg; 
??? const char szSQL[] = "INSERT INTO
\"res_users\"(\"alias_id\",\"company_id\",\"create_uid\",\"login\",\"partner_i
d\") VALUES('10','3',4,'daddad','12')"; 
??? sqlite3_trace(db, db_trace_callback, NULL); 
??? int rc = sqlite3_exec(db, szSQL, NULL, NULL, &errmsg); 
} 
?
int main(int argc, char *argv[]) 
{ 
??? sqlite3 *db; 
??? int rc = sqlite3_open("../odoo.db", &db); 
??? if(rc == SQLITE_OK) 
??? { 
??? ??? char *errmsg; 
??? ??? const char szSQL[] = "DELETE FROM res_users WHERE id=7"; 
??? ??? sqlite3_trace(db, db_trace_callback, NULL); 
??? ??? insertRecord(db); 
??? ??? //rc = sqlite3_exec(db, test_sql, NULL, NULL, &errmsg); 
??? ??? rc = sqlite3_exec(db, szSQL, NULL, NULL, &errmsg); 
??? ??? sqlite3_close(db); 
??? } 
??? return 0; 
} 
------- 
------- output of test-sqlite-bug 
SQL: INSERT INTO
"res_users"("alias_id","company_id","create_uid","login","partner_id")
VALUES('10','3',4,'daddad','12') 
SQL: DELETE FROM res_users WHERE id=7 
SQL: -- TRIGGER res_users_admin_trigger 
SQL: -- TRIGGER 
.. <<<<<< the above line repeated 1000 times 
------- 
?
Thanks in advance for your time, attention and great work ! 
Cheers !

Reply via email to