1
0
Fork 0
mirror of https://github.com/DBD-SQLite/DBD-SQLite synced 2025-06-07 14:19:10 -04:00

Applied a patch from Rob to fix RT-97598, and added a test

This commit is contained in:
Kenichi Ishigaki 2014-07-30 01:57:50 +09:00
parent 371cfe83a1
commit 539d79f080
3 changed files with 97 additions and 20 deletions

View file

@ -358,6 +358,7 @@ sqlite_db_login6(SV *dbh, imp_dbh_t *imp_dbh, char *dbname, char *user, char *pa
imp_dbh->allow_multiple_statements = FALSE;
imp_dbh->use_immediate_transaction = TRUE;
imp_dbh->see_if_its_a_number = FALSE;
imp_dbh->stmt_list = NULL;
sqlite3_busy_timeout(imp_dbh->db, SQL_TIMEOUT);
@ -482,26 +483,31 @@ sqlite_db_disconnect(SV *dbh, imp_dbh_t *imp_dbh)
croak_if_db_is_null();
rc = sqlite3_close(imp_dbh->db);
if (rc != SQLITE_OK) {
/*
** Most probably we still have unfinalized statements.
** Let's try to close them.
*/
/* COMPAT: sqlite3_next_stmt is only available for 3006000 or newer */
while ( (pStmt = sqlite3_next_stmt(imp_dbh->db, 0)) != NULL ) {
sqlite3_finalize(pStmt);
}
rc = sqlite3_close(imp_dbh->db);
if (rc != SQLITE_OK) {
/*
** We still have problems. probably a backup operation
** is not finished. We may need to wait for a while if
** we get SQLITE_BUSY...
*/
sqlite_error(dbh, rc, sqlite3_errmsg(imp_dbh->db));
sqlite_trace( dbh, imp_dbh, 1, "Closing DB" );
rc = sqlite3_close( imp_dbh->db );
sqlite_trace( dbh, imp_dbh, 1, form("rc = %d", rc) );
if ( SQLITE_BUSY == rc ) { /* We have unfinalized statements */
/* Only close the statements that were prepared by this module */
stmt_list_s * s;
while ( s = imp_dbh->stmt_list ) {
sqlite_trace( dbh, imp_dbh, 1, form("Finalizing statement (%p)", s->stmt) );
sqlite3_finalize( s->stmt );
imp_dbh->stmt_list = s->prev;
sqlite3_free( s );
}
imp_dbh->stmt_list = NULL;
sqlite_trace( dbh, imp_dbh, 1, "Trying to close DB again" );
rc = sqlite3_close( imp_dbh->db );
}
if ( SQLITE_OK != rc ) {
sqlite_error(dbh, rc, sqlite3_errmsg(imp_dbh->db));
}
/* The list should be empty at this point, but if for some unforseen reason
it isn't, free remaining nodes here */
stmt_list_s * s;
while( s = imp_dbh->stmt_list ) {
imp_dbh->stmt_list = s->prev;
sqlite3_free( s );
}
imp_dbh->db = NULL;
@ -701,6 +707,12 @@ sqlite_st_prepare_sv(SV *sth, imp_sth_t *imp_sth, SV *sv_statement, SV *attribs)
else {
imp_sth->unprepared_statements = NULL;
}
/* Add the statement to the front of the list to keep track of
statements that might need to be finalized later on disconnect */
stmt_list_s * new_stmt = (stmt_list_s *) sqlite3_malloc( sizeof(stmt_list_s) );
new_stmt->stmt = imp_sth->stmt;
new_stmt->prev = imp_dbh->stmt_list;
imp_dbh->stmt_list = new_stmt;
DBIc_NUM_PARAMS(imp_sth) = sqlite3_bind_parameter_count(imp_sth->stmt);
DBIc_NUM_FIELDS(imp_sth) = sqlite3_column_count(imp_sth->stmt);
@ -1143,11 +1155,29 @@ sqlite_st_destroy(SV *sth, imp_sth_t *imp_sth)
croak_if_stmt_is_null();
/* finalize sth when active connection */
sqlite_trace( sth, imp_sth, 1, form("Finalizing statement: %p", imp_sth->stmt) );
rc = sqlite3_finalize(imp_sth->stmt);
imp_sth->stmt = NULL;
if (rc != SQLITE_OK) {
sqlite_error(sth, rc, sqlite3_errmsg(imp_dbh->db));
}
/* find the statement in the statement list and delete it */
stmt_list_s * i = imp_dbh->stmt_list;
stmt_list_s * temp = i;
while( i ) {
if ( i->stmt == imp_sth->stmt ) {
if ( temp != i ) temp->prev = i->prev;
if ( i == imp_dbh->stmt_list ) imp_dbh->stmt_list = i->prev;
sqlite_trace( sth, imp_sth, 1, form("Removing statement from list: %p", imp_sth->stmt) );
sqlite3_free( i );
break;
}
else {
temp = i;
i = i->prev;
}
}
imp_sth->stmt = NULL;
}
}
SvREFCNT_dec((SV*)imp_sth->params);

View file

@ -16,6 +16,14 @@
#define sqlite3_int64 sqlite_int64
#endif
/* A linked list of statements prepared by this module */
typedef struct stmt_list_s stmt_list_s;
struct stmt_list_s {
sqlite3_stmt * stmt;
stmt_list_s * prev;
};
/* Driver Handle */
struct imp_drh_st {
dbih_drc_t com;
@ -36,6 +44,7 @@ struct imp_dbh_st {
bool allow_multiple_statements;
bool use_immediate_transaction;
bool see_if_its_a_number;
stmt_list_s * stmt_list;
};
/* Statement Handle */

View file

@ -0,0 +1,38 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use t::lib::Test;
use Test::More tests => 3;
use Test::NoWarnings;
my $dbh = connect_ok(AutoCommit => 0);
$dbh->do($_) for (
'CREATE VIRTUAL TABLE test_fts USING fts4 (
col1,
col2,
)',
'INSERT INTO test_fts (col1, col2) VALUES ("abc", "123")',
'INSERT INTO test_fts (col1, col2) VALUES ("def", "456")',
'INSERT INTO test_fts (col1, col2) VALUES ("abc", "123")',
'INSERT INTO test_fts (col1, col2) VALUES ("def", "456")',
'INSERT INTO test_fts (col1, col2) VALUES ("abc", "123")',
);
my $sth = $dbh->prepare('SELECT * FROM test_fts WHERE col2 MATCh "123"');
$sth->execute;
while ( my @row = $sth->fetchrow_array ) {
note join " ", @row;
}
#$sth->finish;
$dbh->commit;
$dbh->disconnect;
pass "all done without segfault";