@@ -117,11 +117,17 @@ typedef struct user_function {
117117 struct user_function * next ;
118118} user_function ;
119119
120+ typedef struct user_collation {
121+ value v_fun ;
122+ struct user_collation * next ;
123+ } user_collation ;
124+
120125typedef struct db_wrap {
121126 sqlite3 * db ;
122127 int rc ;
123128 int ref_count ;
124129 user_function * user_functions ;
130+ user_collation * user_collations ;
125131} db_wrap ;
126132
127133typedef struct stmt_wrap {
@@ -360,6 +366,13 @@ static inline void ref_count_finalize_dbw(db_wrap *dbw) {
360366 caml_stat_free (link );
361367 }
362368 dbw -> user_functions = NULL ;
369+ user_collation * link_c , * next_c ;
370+ for (link_c = dbw -> user_collations ; link_c != NULL ; link_c = next_c ) {
371+ caml_remove_generational_global_root (& link_c -> v_fun );
372+ next_c = link_c -> next ;
373+ caml_stat_free (link );
374+ }
375+ dbw -> user_collations = NULL ;
363376 my_sqlite3_close (dbw -> db );
364377 caml_stat_free (dbw );
365378 }
@@ -514,6 +527,7 @@ CAMLprim value caml_sqlite3_open(value v_mode, value v_uri, value v_memory,
514527 dbw -> rc = SQLITE_OK ;
515528 dbw -> ref_count = 1 ;
516529 dbw -> user_functions = NULL ;
530+ dbw -> user_collations = NULL ;
517531 Sqlite3_val (v_res ) = dbw ;
518532 return v_res ;
519533 }
@@ -1525,6 +1539,86 @@ CAMLprim value caml_sqlite3_delete_function(value v_db, value v_name) {
15251539 return Val_unit ;
15261540}
15271541
1542+ /* User defined collations */
1543+
1544+ static inline void unregister_user_collation (db_wrap * db_data , value v_name ) {
1545+ user_collation * prev = NULL , * link = db_data -> user_collations ;
1546+ const char * name = String_val (v_name );
1547+
1548+ while (link != NULL ) {
1549+ if (strcmp (String_val (Field (link -> v_fun , 0 )), name ) == 0 ) {
1550+ if (prev == NULL )
1551+ db_data -> user_collations = link -> next ;
1552+ else
1553+ prev -> next = link -> next ;
1554+ caml_remove_generational_global_root (& link -> v_fun );
1555+ caml_stat_free (link );
1556+ break ;
1557+ }
1558+ prev = link ;
1559+ link = link -> next ;
1560+ }
1561+ }
1562+
1563+ static inline user_collation *
1564+ register_user_collation (db_wrap * db_data , value v_name , value v_fun ) {
1565+ user_collation * link ;
1566+ value v_cell = caml_alloc_small (2 , 0 );
1567+ Field (v_cell , 0 ) = v_name ;
1568+ Field (v_cell , 1 ) = v_fun ;
1569+
1570+ /* Assume parameters are already protected */
1571+ link = caml_stat_alloc (sizeof * link );
1572+ link -> v_fun = v_cell ;
1573+ link -> next = db_data -> user_collations ;
1574+ caml_register_generational_global_root (& link -> v_fun );
1575+ db_data -> user_collations = link ;
1576+ return link ;
1577+ }
1578+
1579+ int caml_sqlite3_user_collation (void * ctx , int nLeft , const void * zLeft ,
1580+ int nRight , const void * zRight ) {
1581+ user_collation * data = ctx ;
1582+ value v_res , v_left , v_right ;
1583+ int v_return ;
1584+ caml_leave_blocking_section ();
1585+ v_left = caml_alloc_initialized_string (nLeft , zLeft );
1586+ v_right = caml_alloc_initialized_string (nRight , zRight );
1587+ v_res = caml_callback2_exn (Field (data -> v_fun , 1 ), v_left , v_right );
1588+ v_return = Int_val (v_res );
1589+ caml_enter_blocking_section ();
1590+ return v_return ;
1591+ }
1592+
1593+ CAMLprim value caml_sqlite3_create_collation (value v_db , value v_name ,
1594+ value v_fun ) {
1595+ CAMLparam3 (v_db , v_name , v_fun );
1596+ user_collation * param ;
1597+ int rc ;
1598+ db_wrap * dbw = Sqlite3_val (v_db );
1599+ check_db (dbw , "create_collation" );
1600+ param = register_user_collation (dbw , v_name , v_fun );
1601+ rc = sqlite3_create_collation (dbw -> db , String_val (v_name ), SQLITE_UTF8 , param ,
1602+ caml_sqlite3_user_collation );
1603+ if (rc != SQLITE_OK ) {
1604+ unregister_user_collation (dbw , v_name );
1605+ raise_sqlite3_current (dbw -> db , "create_collation" );
1606+ }
1607+ CAMLreturn (Val_unit );
1608+ }
1609+
1610+ CAMLprim value caml_sqlite3_delete_collation (value v_db , value v_name ) {
1611+ int rc ;
1612+ db_wrap * dbw = Sqlite3_val (v_db );
1613+ check_db (dbw , "delete_collation" );
1614+ rc = sqlite3_create_collation (dbw -> db , String_val (v_name ), SQLITE_UTF8 , NULL ,
1615+ NULL );
1616+ if (rc != SQLITE_OK )
1617+ raise_sqlite3_current (dbw -> db , "delete_collation" );
1618+ unregister_user_collation (dbw , v_name );
1619+ return Val_unit ;
1620+ }
1621+
15281622CAMLprim value caml_sqlite3_busy_timeout (value v_db , intnat ms ) {
15291623 int rc ;
15301624 db_wrap * dbw = Sqlite3_val (v_db );
0 commit comments