@@ -259,6 +259,44 @@ busy_handler(int argc, VALUE *argv, VALUE self)
259259 return self ;
260260}
261261
262+ static int
263+ rb_sqlite3_statement_timeout (void * context )
264+ {
265+ sqlite3RubyPtr ctx = (sqlite3RubyPtr )context ;
266+ struct timespec currentTime ;
267+ clock_gettime (CLOCK_MONOTONIC , & currentTime );
268+
269+ if (!timespecisset (& ctx -> stmt_deadline )) {
270+ // Set stmt_deadline if not already set
271+ ctx -> stmt_deadline = currentTime ;
272+ } else if (timespecafter (& currentTime , & ctx -> stmt_deadline )) {
273+ return 1 ;
274+ }
275+
276+ return 0 ;
277+ }
278+
279+ /* call-seq: db.statement_timeout = ms
280+ *
281+ * Indicates that if a query lasts longer than the indicated number of
282+ * milliseconds, SQLite should interrupt that query and return an error.
283+ * By default, SQLite does not interrupt queries. To restore the default
284+ * behavior, send 0 as the +ms+ parameter.
285+ */
286+ static VALUE
287+ set_statement_timeout (VALUE self , VALUE milliseconds )
288+ {
289+ sqlite3RubyPtr ctx ;
290+ TypedData_Get_Struct (self , sqlite3Ruby , & database_type , ctx );
291+
292+ ctx -> stmt_timeout = NUM2INT (milliseconds );
293+ int n = NUM2INT (milliseconds ) == 0 ? -1 : 1000 ;
294+
295+ sqlite3_progress_handler (ctx -> db , n , rb_sqlite3_statement_timeout , (void * )ctx );
296+
297+ return self ;
298+ }
299+
262300/* call-seq: last_insert_row_id
263301 *
264302 * Obtains the unique row ID of the last row to be inserted by this Database
@@ -869,6 +907,9 @@ init_sqlite3_database(void)
869907 rb_define_method (cSqlite3Database , "authorizer=" , set_authorizer , 1 );
870908 rb_define_method (cSqlite3Database , "busy_handler" , busy_handler , -1 );
871909 rb_define_method (cSqlite3Database , "busy_timeout=" , set_busy_timeout , 1 );
910+ #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
911+ rb_define_method (cSqlite3Database , "statement_timeout=" , set_statement_timeout , 1 );
912+ #endif
872913 rb_define_method (cSqlite3Database , "extended_result_codes=" , set_extended_result_codes , 1 );
873914 rb_define_method (cSqlite3Database , "transaction_active?" , transaction_active_p , 0 );
874915 rb_define_private_method (cSqlite3Database , "exec_batch" , exec_batch , 2 );
0 commit comments