88#include <stdio.h>
99#include "sqlite3.h"
1010#include "sqlitejs.h"
11+ #include <pthread.h>
1112
12- #define DB_PATH "js_functions.sqlite"
13+ #define DB_PATH "js_functions.sqlite"
14+
15+ #define TEST_THREAD_NTHREADS 1000
16+ #define TEST_THREAD_FIRST_INIT 0
17+ pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER ;
18+ pthread_cond_t cond = PTHREAD_COND_INITIALIZER ;
1319
1420static int print_results_callback (void * data , int argc , char * * argv , char * * names ) {
1521 for (int i = 0 ; i < argc ; i ++ ) {
@@ -104,6 +110,8 @@ int test_execution (void) {
104110 rc = db_exec (db , "SELECT Cos(123), cos(12.3);" );
105111 rc = db_exec (db , "SELECT js_create_scalar('Sin', '(function(args){return Math.sin(args[0]);})')" );
106112 rc = db_exec (db , "SELECT Sin(123), sin(12.3);" );
113+ rc = db_exec (db , "SELECT js_create_scalar('f-2', '(function(args){return args[0]*10;})')" );
114+ rc = db_exec (db , "SELECT [f-2](2);" );
107115
108116 // aggregate
109117 printf ("\nTesting js_create_aggregate\n" );
@@ -170,6 +178,150 @@ int test_execution (void) {
170178 return rc ;
171179}
172180
181+ void * test_thread_init (void * ptr ) {
182+ sqlite3 * * ppdb = (sqlite3 * * )ptr ;
183+ int rc ;
184+
185+ // printf("test_thread_init\n");
186+
187+ pthread_mutex_lock (& mutex );
188+ rc = sqlite3_open (":memory:" , ppdb );
189+ if (rc != SQLITE_OK ) goto finalize ;
190+
191+ sqlite3 * db = * ppdb ;
192+
193+ #if JS_LOAD_EMBEDDED
194+ rc = sqlite3_js_init (db , NULL , NULL );
195+ #else
196+ // enable load extension
197+ rc = sqlite3_enable_load_extension (db , 1 );
198+ if (rc != SQLITE_OK ) goto finalize ;
199+
200+ rc = db_exec (db , "SELECT load_extension('./dist/js');" );
201+ if (rc != SQLITE_OK ) goto finalize ;
202+ #endif
203+
204+ rc = db_exec (db , "SELECT js_set_max_stack_size(0)" );
205+ if (rc != SQLITE_OK ) goto finalize ;
206+
207+ rc = db_exec (db , "SELECT js_create_scalar('x10', '(function(args){return args[0]*10;})')" );
208+ if (rc != SQLITE_OK ) goto finalize ;
209+
210+ rc = db_exec (db , "SELECT x10(2);" );
211+ if (rc != SQLITE_OK ) goto finalize ;
212+
213+ rc = db_exec (db , "SELECT js_eval('136*10');" );
214+ if (rc != SQLITE_OK ) goto finalize ;
215+
216+ finalize :
217+ pthread_cond_signal (& cond ); // Signal consumer
218+ pthread_mutex_unlock (& mutex );
219+
220+ // printf("test_thread_init return %d\n", rc);
221+ return (void * )(intptr_t )rc ;
222+ }
223+
224+ void * test_thread_sleep (void * ptr ) {
225+ sqlite3_sleep (5000 );
226+ return (void * )(intptr_t )0 ;
227+ }
228+
229+ void * test_thread_worker (void * ptr ) {
230+ sqlite3 * * ppdb = (sqlite3 * * )ptr ;
231+ sqlite3 * db ;
232+
233+ pthread_mutex_lock (& mutex );
234+ while (!(db = * ppdb )) {
235+ pthread_cond_wait (& cond , & mutex ); // Wait for data
236+ }
237+
238+ // printf("test_thread_worker\n");
239+
240+ int rc = db_exec (db , "SELECT x10(2);" );
241+ if (rc != SQLITE_OK ) goto finalize ;
242+
243+ rc = db_exec (db , "SELECT js_eval('136*10');" );
244+ if (rc != SQLITE_OK ) goto finalize ;
245+
246+ rc = db_exec (db , "SELECT js_create_scalar('x20', '(function(args){return args[0]*20;})')" );
247+ if (rc != SQLITE_OK ) goto finalize ;
248+
249+ rc = db_exec (db , "SELECT x20(2);" );
250+ if (rc != SQLITE_OK ) goto finalize ;
251+
252+ finalize :
253+ pthread_mutex_unlock (& mutex );
254+
255+ // printf("test_thread_1 return %d\n", rc);
256+ return (void * )(intptr_t )rc ;
257+ }
258+
259+ int test_thread (void ) {
260+ sqlite3 * db = NULL ;
261+ int rc ;
262+ int iret ;
263+
264+ // Create the a separated thread
265+ pthread_t thread1 , thread_init , thread_sleep [TEST_THREAD_NTHREADS ];
266+
267+ #if TEST_THREAD_FIRST_INIT
268+ iret = pthread_create (& thread_init , NULL , test_thread_init , (void * ) & db );
269+ if (iret ) {
270+ fprintf (stderr , "Error - pthread_create() init return code: %d\n" , iret );
271+ return 1 ;
272+ }
273+ #endif
274+
275+ iret = pthread_create (& thread1 , NULL , test_thread_worker , (void * ) & db );
276+ if (iret ) {
277+ fprintf (stderr , "Error - pthread_create() 1 return code: %d\n" , iret );
278+ return 1 ;
279+ }
280+
281+
282+ for (int i = 0 ; i < TEST_THREAD_NTHREADS ; i ++ ) {
283+ iret = pthread_create (& thread_sleep [i ], NULL , test_thread_sleep , (void * ) & db );
284+ if (iret ) {
285+ fprintf (stderr , "Error - pthread_create() %d return code: %d\n" , i , iret );
286+ return 1 ;
287+ }
288+ }
289+
290+ #if TEST_THREAD_FIRST_INIT == 0
291+ iret = pthread_create (& thread_init , NULL , test_thread_init , (void * ) & db );
292+ if (iret ) {
293+ fprintf (stderr , "Error - pthread_create() init return code: %d\n" , iret );
294+ return 1 ;
295+ }
296+
297+ #endif
298+
299+ // Wait for the threads to complete before the main thread continues
300+ void * thread_1_rc ;
301+ void * thread_init_rc ;
302+ pthread_join (thread1 , & thread_1_rc );
303+ pthread_join (thread_init , & thread_init_rc );
304+ rc = (int )(intptr_t )thread_1_rc ;
305+ // printf("Thread 1 returns: %d\n", rc);
306+ if (rc != SQLITE_OK ) goto abort_test ;
307+ rc = (int )(intptr_t )thread_init_rc ;
308+ // printf("Thread init returns: %d\n", rc);
309+ if (rc != SQLITE_OK ) goto abort_test ;
310+
311+ for (int i = 0 ; i < TEST_THREAD_NTHREADS ; i ++ ) {
312+ void * thread_sleep_rc ;
313+ pthread_join (thread_sleep [i ], & thread_sleep_rc );
314+ rc = (int )(intptr_t )thread_sleep_rc ;
315+ // printf("Thread %d returns: %d\n", i, rc);
316+ if (rc != SQLITE_OK ) goto abort_test ;
317+ }
318+
319+ abort_test :
320+ if (rc != SQLITE_OK ) printf ("Error: %s\n" , sqlite3_errmsg (db ));
321+ if (db ) sqlite3_close (db );
322+ return rc ;
323+ }
324+
173325// MARK: -
174326
175327int main (void ) {
@@ -179,7 +331,8 @@ int main (void) {
179331 rc = test_serialization (DB_PATH , false, 1 ); // create and execute original implementations
180332 rc = test_serialization (DB_PATH , false, 2 ); // update functions previously registered in the js_functions table
181333 rc = test_serialization (DB_PATH , true, 3 ); // load the new implementations
182-
334+ rc = test_thread ();
335+
183336 sqlite3_int64 current = 0 ;
184337 sqlite3_int64 highwater = 0 ;
185338 bool reset = false;
0 commit comments