Skip to main content

ri/java/classes/
database.rs

1//! Copyright © 2025-2026 Wenze Wei. All Rights Reserved.
2//!
3//! This file is part of Ri.
4//! The Ri project belongs to the Dunimd Team.
5//!
6//! Licensed under the Apache License, Version 2.0 (the "License");
7//! You may not use this file except in compliance with the License.
8//! You may obtain a copy of the License at
9//!
10//!     http://www.apache.org/licenses/LICENSE-2.0
11//!
12//! Unless required by applicable law or agreed to in writing, software
13//! distributed under the License is distributed on an "AS IS" BASIS,
14//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15//! See the License for the specific language governing permissions and
16//! limitations under the License.
17
18//! # Database Module JNI Bindings
19//!
20//! JNI bindings for Ri database classes.
21
22use jni::JNIEnv;
23use jni::objects::{JClass, JString};
24use jni::sys::{jlong, jboolean, jint, jdouble, jstring};
25use crate::database::{RiDatabaseConfig, RiDatabasePool, RiDatabaseMetrics, RiDynamicPoolConfig, RiDBRow, RiDBResult, RiDatabaseMigration};
26use crate::java::exception::check_not_null;
27use crate::java::exception::throw_ri_error;
28
29// =============================================================================
30// RiDatabaseConfig JNI Bindings
31// =============================================================================
32
33#[no_mangle]
34pub extern "system" fn Java_com_dunimd_ri_database_RiDatabaseConfig_new0(
35    _env: JNIEnv,
36    _class: JClass,
37) -> jlong {
38    let config = Box::new(RiDatabaseConfig::default());
39    Box::into_raw(config) as jlong
40}
41
42#[no_mangle]
43pub extern "system" fn Java_com_dunimd_ri_database_RiDatabaseConfig_free0(
44    _env: JNIEnv,
45    _class: JClass,
46    ptr: jlong,
47) {
48    if ptr != 0 {
49        unsafe {
50            let _ = Box::from_raw(ptr as *mut RiDatabaseConfig);
51        }
52    }
53}
54
55// =============================================================================
56// RiDatabasePool JNI Bindings
57// =============================================================================
58
59#[no_mangle]
60pub extern "system" fn Java_com_dunimd_ri_database_RiDatabasePool_new0(
61    mut env: JNIEnv,
62    _class: JClass,
63    config_ptr: jlong,
64) -> jlong {
65    if !check_not_null(&mut env, config_ptr, "RiDatabaseConfig") {
66        return 0;
67    }
68
69    let config = unsafe { &*(config_ptr as *const crate::database::RiDatabaseConfig) };
70
71    match crate::java::runtime::block_on_jni(&mut env, "RiDatabasePool::new", async {
72        crate::database::RiDatabasePool::new(config.clone()).await
73    }) {
74        Some(Ok(pool)) => {
75            let boxed = Box::new(pool);
76            Box::into_raw(boxed) as jlong
77        }
78        Some(Err(e)) => {
79            throw_ri_error(&mut env, &e.to_string());
80            0
81        }
82        None => 0,
83    }
84}
85
86#[no_mangle]
87pub extern "system" fn Java_com_dunimd_ri_database_RiDatabasePool_execute0(
88    mut env: JNIEnv,
89    _class: JClass,
90    ptr: jlong,
91    sql: JString,
92) -> jlong {
93    if !check_not_null(&mut env, ptr, "RiDatabasePool") {
94        return 0;
95    }
96    
97    let sql_str: String = match env.get_string(&sql) {
98        Ok(s) => s.into(),
99        Err(_) => return 0,
100    };
101    
102    let pool = unsafe { &*(ptr as *const RiDatabasePool) };
103    match crate::java::runtime::block_on_local(
104        &mut env,
105        "RiDatabasePool::execute",
106        async {
107            let db = pool.get().await?;
108            let affected = db.execute(&sql_str).await;
109            pool.release(db).await;
110            affected
111        },
112    ) {
113        Some(Ok(affected)) => affected as jlong,
114        Some(Err(e)) => {
115            throw_ri_error(&mut env, &e.to_string());
116            0
117        }
118        None => 0,
119    }
120}
121
122#[no_mangle]
123pub extern "system" fn Java_com_dunimd_ri_database_RiDatabasePool_query0(
124    mut env: JNIEnv,
125    _class: JClass,
126    ptr: jlong,
127    sql: JString,
128) -> jlong {
129    if !check_not_null(&mut env, ptr, "RiDatabasePool") {
130        return 0;
131    }
132    
133    let sql_str: String = match env.get_string(&sql) {
134        Ok(s) => s.into(),
135        Err(_) => return 0,
136    };
137    
138    let pool = unsafe { &*(ptr as *const RiDatabasePool) };
139    match crate::java::runtime::block_on_local(
140        &mut env,
141        "RiDatabasePool::query",
142        async {
143            let db = pool.get().await?;
144            let result = db.query(&sql_str).await;
145            pool.release(db).await;
146            result
147        },
148    ) {
149        Some(Ok(result)) => Box::into_raw(Box::new(result)) as jlong,
150        Some(Err(e)) => {
151            throw_ri_error(&mut env, &e.to_string());
152            0
153        }
154        None => 0,
155    }
156}
157
158#[no_mangle]
159pub extern "system" fn Java_com_dunimd_ri_database_RiDatabasePool_getMetrics0(
160    mut env: JNIEnv,
161    _class: JClass,
162    ptr: jlong,
163) -> jlong {
164    if !check_not_null(&mut env, ptr, "RiDatabasePool") {
165        return 0;
166    }
167    
168    let pool = unsafe { &*(ptr as *const RiDatabasePool) };
169    let metrics = Box::new(pool.metrics());
170    Box::into_raw(metrics) as jlong
171}
172
173#[no_mangle]
174pub extern "system" fn Java_com_dunimd_ri_database_RiDatabasePool_getUtilizationRate0(
175    mut env: JNIEnv,
176    _class: JClass,
177    ptr: jlong,
178) -> jdouble {
179    if !check_not_null(&mut env, ptr, "RiDatabasePool") {
180        return 0.0;
181    }
182    
183    let pool = unsafe { &*(ptr as *const RiDatabasePool) };
184    pool.utilization_rate()
185}
186
187#[no_mangle]
188pub extern "system" fn Java_com_dunimd_ri_database_RiDatabasePool_getDynamicConfig0(
189    mut env: JNIEnv,
190    _class: JClass,
191    ptr: jlong,
192) -> jlong {
193    if !check_not_null(&mut env, ptr, "RiDatabasePool") {
194        return 0;
195    }
196    
197    let pool = unsafe { &*(ptr as *const RiDatabasePool) };
198    let config = Box::new(pool.get_dynamic_config());
199    Box::into_raw(config) as jlong
200}
201
202#[no_mangle]
203pub extern "system" fn Java_com_dunimd_ri_database_RiDatabasePool_free0(
204    _env: JNIEnv,
205    _class: JClass,
206    ptr: jlong,
207) {
208    if ptr != 0 {
209        unsafe {
210            let _ = Box::from_raw(ptr as *mut RiDatabasePool);
211        }
212    }
213}
214
215// =============================================================================
216// RiDBRow JNI Bindings
217// =============================================================================
218
219#[no_mangle]
220pub extern "system" fn Java_com_dunimd_ri_database_RiDBRow_getString0(
221    mut env: JNIEnv,
222    _class: JClass,
223    ptr: jlong,
224    name: JString,
225) -> jstring {
226    if !check_not_null(&mut env, ptr, "RiDBRow") {
227        return std::ptr::null_mut();
228    }
229    
230    let _name_str: String = match env.get_string(&name) {
231        Ok(s) => s.into(),
232        Err(_) => {
233            crate::java::exception::throw_ri_error(&mut env, "Failed to get column name");
234            return std::ptr::null_mut();
235        }
236    };
237    
238    std::ptr::null_mut()
239}
240
241#[no_mangle]
242pub extern "system" fn Java_com_dunimd_ri_database_RiDBRow_getInt0(
243    mut env: JNIEnv,
244    _class: JClass,
245    ptr: jlong,
246    name: JString,
247) -> jint {
248    if !check_not_null(&mut env, ptr, "RiDBRow") {
249        return 0;
250    }
251    
252    let _name_str: String = match env.get_string(&name) {
253        Ok(s) => s.into(),
254        Err(_) => {
255            crate::java::exception::throw_ri_error(&mut env, "Failed to get column name");
256            return 0;
257        }
258    };
259    
260    0
261}
262
263#[no_mangle]
264pub extern "system" fn Java_com_dunimd_ri_database_RiDBRow_getLong0(
265    mut env: JNIEnv,
266    _class: JClass,
267    ptr: jlong,
268    name: JString,
269) -> jlong {
270    if !check_not_null(&mut env, ptr, "RiDBRow") {
271        return 0;
272    }
273    
274    let _name_str: String = match env.get_string(&name) {
275        Ok(s) => s.into(),
276        Err(_) => {
277            crate::java::exception::throw_ri_error(&mut env, "Failed to get column name");
278            return 0;
279        }
280    };
281    
282    0
283}
284
285#[no_mangle]
286pub extern "system" fn Java_com_dunimd_ri_database_RiDBRow_getDouble0(
287    mut env: JNIEnv,
288    _class: JClass,
289    ptr: jlong,
290    name: JString,
291) -> jdouble {
292    if !check_not_null(&mut env, ptr, "RiDBRow") {
293        return 0.0;
294    }
295    
296    let _name_str: String = match env.get_string(&name) {
297        Ok(s) => s.into(),
298        Err(_) => {
299            crate::java::exception::throw_ri_error(&mut env, "Failed to get column name");
300            return 0.0;
301        }
302    };
303    
304    0.0
305}
306
307#[no_mangle]
308pub extern "system" fn Java_com_dunimd_ri_database_RiDBRow_getBoolean0(
309    mut env: JNIEnv,
310    _class: JClass,
311    ptr: jlong,
312    name: JString,
313) -> jboolean {
314    if !check_not_null(&mut env, ptr, "RiDBRow") {
315        return 0;
316    }
317    
318    let _name_str: String = match env.get_string(&name) {
319        Ok(s) => s.into(),
320        Err(_) => {
321            crate::java::exception::throw_ri_error(&mut env, "Failed to get column name");
322            return 0;
323        }
324    };
325    
326    0
327}
328
329#[no_mangle]
330pub extern "system" fn Java_com_dunimd_ri_database_RiDBRow_isNull0(
331    mut env: JNIEnv,
332    _class: JClass,
333    ptr: jlong,
334    name: JString,
335) -> jboolean {
336    if !check_not_null(&mut env, ptr, "RiDBRow") {
337        return 1;
338    }
339    
340    let _name_str: String = match env.get_string(&name) {
341        Ok(s) => s.into(),
342        Err(_) => {
343            crate::java::exception::throw_ri_error(&mut env, "Failed to get column name");
344            return 0;
345        }
346    };
347    
348    1
349}
350
351#[no_mangle]
352pub extern "system" fn Java_com_dunimd_ri_database_RiDBRow_hasColumn0(
353    mut env: JNIEnv,
354    _class: JClass,
355    ptr: jlong,
356    name: JString,
357) -> jboolean {
358    if !check_not_null(&mut env, ptr, "RiDBRow") {
359        return 0;
360    }
361    
362    let _name_str: String = match env.get_string(&name) {
363        Ok(s) => s.into(),
364        Err(_) => {
365            crate::java::exception::throw_ri_error(&mut env, "Failed to get column name");
366            return 0;
367        }
368    };
369    
370    0
371}
372
373#[no_mangle]
374pub extern "system" fn Java_com_dunimd_ri_database_RiDBRow_getColumnCount0(
375    mut env: JNIEnv,
376    _class: JClass,
377    ptr: jlong,
378) -> jint {
379    if !check_not_null(&mut env, ptr, "RiDBRow") {
380        return 0;
381    }
382    
383    0
384}
385
386#[no_mangle]
387pub extern "system" fn Java_com_dunimd_ri_database_RiDBRow_free0(
388    _env: JNIEnv,
389    _class: JClass,
390    ptr: jlong,
391) {
392    if ptr != 0 {
393        unsafe {
394            let _ = Box::from_raw(ptr as *mut RiDBRow);
395        }
396    }
397}
398
399// =============================================================================
400// RiDBResult JNI Bindings
401// =============================================================================
402
403#[no_mangle]
404pub extern "system" fn Java_com_dunimd_ri_database_RiDBResult_getRowCount0(
405    mut env: JNIEnv,
406    _class: JClass,
407    ptr: jlong,
408) -> jint {
409    if !check_not_null(&mut env, ptr, "RiDBResult") {
410        return 0;
411    }
412    
413    let result = unsafe { &*(ptr as *const RiDBResult) };
414    result.row_count() as jint
415}
416
417#[no_mangle]
418pub extern "system" fn Java_com_dunimd_ri_database_RiDBResult_getAffectedRows0(
419    mut env: JNIEnv,
420    _class: JClass,
421    ptr: jlong,
422) -> jlong {
423    if !check_not_null(&mut env, ptr, "RiDBResult") {
424        return 0;
425    }
426    
427    let result = unsafe { &*(ptr as *const RiDBResult) };
428    result.affected_rows() as jlong
429}
430
431#[no_mangle]
432pub extern "system" fn Java_com_dunimd_ri_database_RiDBResult_getLastInsertId0(
433    mut env: JNIEnv,
434    _class: JClass,
435    ptr: jlong,
436) -> jlong {
437    if !check_not_null(&mut env, ptr, "RiDBResult") {
438        return -1;
439    }
440    
441    let result = unsafe { &*(ptr as *const RiDBResult) };
442    result.last_insert_id().unwrap_or(-1)
443}
444
445#[no_mangle]
446pub extern "system" fn Java_com_dunimd_ri_database_RiDBResult_isEmpty0(
447    mut env: JNIEnv,
448    _class: JClass,
449    ptr: jlong,
450) -> jboolean {
451    if !check_not_null(&mut env, ptr, "RiDBResult") {
452        return 1;
453    }
454    
455    let result = unsafe { &*(ptr as *const RiDBResult) };
456    result.is_empty() as jboolean
457}
458
459#[no_mangle]
460pub extern "system" fn Java_com_dunimd_ri_database_RiDBResult_getRow0(
461    mut env: JNIEnv,
462    _class: JClass,
463    ptr: jlong,
464    index: jint,
465) -> jlong {
466    if !check_not_null(&mut env, ptr, "RiDBResult") {
467        return 0;
468    }
469    
470    let result = unsafe { &*(ptr as *const RiDBResult) };
471    if let Some(_row) = result.get(index as usize) {
472        let row = Box::new(RiDBRow::new());
473        return Box::into_raw(row) as jlong;
474    }
475    
476    0
477}
478
479#[no_mangle]
480pub extern "system" fn Java_com_dunimd_ri_database_RiDBResult_free0(
481    _env: JNIEnv,
482    _class: JClass,
483    ptr: jlong,
484) {
485    if ptr != 0 {
486        unsafe {
487            let _ = Box::from_raw(ptr as *mut RiDBResult);
488        }
489    }
490}
491
492// =============================================================================
493// RiDatabaseMetrics JNI Bindings
494// =============================================================================
495
496#[no_mangle]
497pub extern "system" fn Java_com_dunimd_ri_database_RiDatabaseMetrics_getActiveConnections0(
498    mut env: JNIEnv,
499    _class: JClass,
500    ptr: jlong,
501) -> jlong {
502    if !check_not_null(&mut env, ptr, "RiDatabaseMetrics") {
503        return 0;
504    }
505    
506    let metrics = unsafe { &*(ptr as *const RiDatabaseMetrics) };
507    metrics.active_connections as jlong
508}
509
510#[no_mangle]
511pub extern "system" fn Java_com_dunimd_ri_database_RiDatabaseMetrics_getIdleConnections0(
512    mut env: JNIEnv,
513    _class: JClass,
514    ptr: jlong,
515) -> jlong {
516    if !check_not_null(&mut env, ptr, "RiDatabaseMetrics") {
517        return 0;
518    }
519    
520    let metrics = unsafe { &*(ptr as *const RiDatabaseMetrics) };
521    metrics.idle_connections as jlong
522}
523
524#[no_mangle]
525pub extern "system" fn Java_com_dunimd_ri_database_RiDatabaseMetrics_getTotalConnections0(
526    mut env: JNIEnv,
527    _class: JClass,
528    ptr: jlong,
529) -> jlong {
530    if !check_not_null(&mut env, ptr, "RiDatabaseMetrics") {
531        return 0;
532    }
533    
534    let metrics = unsafe { &*(ptr as *const RiDatabaseMetrics) };
535    metrics.total_connections as jlong
536}
537
538#[no_mangle]
539pub extern "system" fn Java_com_dunimd_ri_database_RiDatabaseMetrics_getQueriesExecuted0(
540    mut env: JNIEnv,
541    _class: JClass,
542    ptr: jlong,
543) -> jlong {
544    if !check_not_null(&mut env, ptr, "RiDatabaseMetrics") {
545        return 0;
546    }
547    
548    let metrics = unsafe { &*(ptr as *const RiDatabaseMetrics) };
549    metrics.queries_executed as jlong
550}
551
552#[no_mangle]
553pub extern "system" fn Java_com_dunimd_ri_database_RiDatabaseMetrics_getQueryDurationMs0(
554    mut env: JNIEnv,
555    _class: JClass,
556    ptr: jlong,
557) -> jdouble {
558    if !check_not_null(&mut env, ptr, "RiDatabaseMetrics") {
559        return 0.0;
560    }
561    
562    let metrics = unsafe { &*(ptr as *const RiDatabaseMetrics) };
563    metrics.query_duration_ms
564}
565
566#[no_mangle]
567pub extern "system" fn Java_com_dunimd_ri_database_RiDatabaseMetrics_getErrors0(
568    mut env: JNIEnv,
569    _class: JClass,
570    ptr: jlong,
571) -> jlong {
572    if !check_not_null(&mut env, ptr, "RiDatabaseMetrics") {
573        return 0;
574    }
575    
576    let metrics = unsafe { &*(ptr as *const RiDatabaseMetrics) };
577    metrics.errors as jlong
578}
579
580#[no_mangle]
581pub extern "system" fn Java_com_dunimd_ri_database_RiDatabaseMetrics_getUtilizationRate0(
582    mut env: JNIEnv,
583    _class: JClass,
584    ptr: jlong,
585) -> jdouble {
586    if !check_not_null(&mut env, ptr, "RiDatabaseMetrics") {
587        return 0.0;
588    }
589    
590    let metrics = unsafe { &*(ptr as *const RiDatabaseMetrics) };
591    metrics.utilization_rate
592}
593
594#[no_mangle]
595pub extern "system" fn Java_com_dunimd_ri_database_RiDatabaseMetrics_free0(
596    _env: JNIEnv,
597    _class: JClass,
598    ptr: jlong,
599) {
600    if ptr != 0 {
601        unsafe {
602            let _ = Box::from_raw(ptr as *mut RiDatabaseMetrics);
603        }
604    }
605}
606
607// =============================================================================
608// RiDynamicPoolConfig JNI Bindings
609// =============================================================================
610
611#[no_mangle]
612pub extern "system" fn Java_com_dunimd_ri_database_RiDynamicPoolConfig_new0(
613    _env: JNIEnv,
614    _class: JClass,
615) -> jlong {
616    let config = Box::new(RiDynamicPoolConfig::default());
617    Box::into_raw(config) as jlong
618}
619
620#[no_mangle]
621pub extern "system" fn Java_com_dunimd_ri_database_RiDynamicPoolConfig_isDynamicScalingEnabled0(
622    mut env: JNIEnv,
623    _class: JClass,
624    ptr: jlong,
625) -> jboolean {
626    if !check_not_null(&mut env, ptr, "RiDynamicPoolConfig") {
627        return 0;
628    }
629    
630    let config = unsafe { &*(ptr as *const RiDynamicPoolConfig) };
631    config.enable_dynamic_scaling as jboolean
632}
633
634#[no_mangle]
635pub extern "system" fn Java_com_dunimd_ri_database_RiDynamicPoolConfig_setDynamicScalingEnabled0(
636    mut env: JNIEnv,
637    _class: JClass,
638    ptr: jlong,
639    enabled: jboolean,
640) {
641    if !check_not_null(&mut env, ptr, "RiDynamicPoolConfig") {
642        return;
643    }
644    
645    let config = unsafe { &mut *(ptr as *mut RiDynamicPoolConfig) };
646    config.enable_dynamic_scaling = enabled != 0;
647}
648
649#[no_mangle]
650pub extern "system" fn Java_com_dunimd_ri_database_RiDynamicPoolConfig_getScaleUpThreshold0(
651    mut env: JNIEnv,
652    _class: JClass,
653    ptr: jlong,
654) -> jdouble {
655    if !check_not_null(&mut env, ptr, "RiDynamicPoolConfig") {
656        return 0.0;
657    }
658    
659    let config = unsafe { &*(ptr as *const RiDynamicPoolConfig) };
660    config.scale_up_threshold
661}
662
663#[no_mangle]
664pub extern "system" fn Java_com_dunimd_ri_database_RiDynamicPoolConfig_setScaleUpThreshold0(
665    mut env: JNIEnv,
666    _class: JClass,
667    ptr: jlong,
668    threshold: jdouble,
669) {
670    if !check_not_null(&mut env, ptr, "RiDynamicPoolConfig") {
671        return;
672    }
673    
674    let config = unsafe { &mut *(ptr as *mut RiDynamicPoolConfig) };
675    config.scale_up_threshold = threshold;
676}
677
678#[no_mangle]
679pub extern "system" fn Java_com_dunimd_ri_database_RiDynamicPoolConfig_getScaleDownThreshold0(
680    mut env: JNIEnv,
681    _class: JClass,
682    ptr: jlong,
683) -> jdouble {
684    if !check_not_null(&mut env, ptr, "RiDynamicPoolConfig") {
685        return 0.0;
686    }
687    
688    let config = unsafe { &*(ptr as *const RiDynamicPoolConfig) };
689    config.scale_down_threshold
690}
691
692#[no_mangle]
693pub extern "system" fn Java_com_dunimd_ri_database_RiDynamicPoolConfig_setScaleDownThreshold0(
694    mut env: JNIEnv,
695    _class: JClass,
696    ptr: jlong,
697    threshold: jdouble,
698) {
699    if !check_not_null(&mut env, ptr, "RiDynamicPoolConfig") {
700        return;
701    }
702    
703    let config = unsafe { &mut *(ptr as *mut RiDynamicPoolConfig) };
704    config.scale_down_threshold = threshold;
705}
706
707#[no_mangle]
708pub extern "system" fn Java_com_dunimd_ri_database_RiDynamicPoolConfig_getMinConnections0(
709    mut env: JNIEnv,
710    _class: JClass,
711    ptr: jlong,
712) -> jint {
713    if !check_not_null(&mut env, ptr, "RiDynamicPoolConfig") {
714        return 0;
715    }
716    
717    let config = unsafe { &*(ptr as *const RiDynamicPoolConfig) };
718    config.min_connections as jint
719}
720
721#[no_mangle]
722pub extern "system" fn Java_com_dunimd_ri_database_RiDynamicPoolConfig_setMinConnections0(
723    mut env: JNIEnv,
724    _class: JClass,
725    ptr: jlong,
726    min: jint,
727) {
728    if !check_not_null(&mut env, ptr, "RiDynamicPoolConfig") {
729        return;
730    }
731    
732    let config = unsafe { &mut *(ptr as *mut RiDynamicPoolConfig) };
733    config.min_connections = min as u32;
734}
735
736#[no_mangle]
737pub extern "system" fn Java_com_dunimd_ri_database_RiDynamicPoolConfig_getMaxConnections0(
738    mut env: JNIEnv,
739    _class: JClass,
740    ptr: jlong,
741) -> jint {
742    if !check_not_null(&mut env, ptr, "RiDynamicPoolConfig") {
743        return 0;
744    }
745    
746    let config = unsafe { &*(ptr as *const RiDynamicPoolConfig) };
747    config.max_connections as jint
748}
749
750#[no_mangle]
751pub extern "system" fn Java_com_dunimd_ri_database_RiDynamicPoolConfig_setMaxConnections0(
752    mut env: JNIEnv,
753    _class: JClass,
754    ptr: jlong,
755    max: jint,
756) {
757    if !check_not_null(&mut env, ptr, "RiDynamicPoolConfig") {
758        return;
759    }
760    
761    let config = unsafe { &mut *(ptr as *mut RiDynamicPoolConfig) };
762    config.max_connections = max as u32;
763}
764
765#[no_mangle]
766pub extern "system" fn Java_com_dunimd_ri_database_RiDynamicPoolConfig_free0(
767    _env: JNIEnv,
768    _class: JClass,
769    ptr: jlong,
770) {
771    if ptr != 0 {
772        unsafe {
773            let _ = Box::from_raw(ptr as *mut RiDynamicPoolConfig);
774        }
775    }
776}
777
778// =============================================================================
779// RiDatabaseMigration JNI Bindings
780// =============================================================================
781
782#[no_mangle]
783pub extern "system" fn Java_com_dunimd_ri_database_RiDatabaseMigration_new0(
784    mut env: JNIEnv,
785    _class: JClass,
786    version: jint,
787    name: JString,
788    sql_up: JString,
789    sql_down: JString,
790) -> jlong {
791    let name_str: String = match env.get_string(&name) {
792        Ok(s) => s.into(),
793        Err(_) => {
794            crate::java::exception::throw_ri_error(&mut env, "Failed to get name");
795            return 0;
796        }
797    };
798    let sql_up_str: String = match env.get_string(&sql_up) {
799        Ok(s) => s.into(),
800        Err(_) => {
801            crate::java::exception::throw_ri_error(&mut env, "Failed to get SQL up");
802            return 0;
803        }
804    };
805    let sql_down_str: Option<String> = if sql_down.is_null() {
806        None
807    } else {
808        env.get_string(&sql_down).ok().map(|s| s.into())
809    };
810    
811    let migration = Box::new(RiDatabaseMigration::new(
812        version as u32,
813        &name_str,
814        &sql_up_str,
815        sql_down_str.as_deref(),
816    ));
817    Box::into_raw(migration) as jlong
818}
819
820#[no_mangle]
821pub extern "system" fn Java_com_dunimd_ri_database_RiDatabaseMigration_getVersion0(
822    mut env: JNIEnv,
823    _class: JClass,
824    ptr: jlong,
825) -> jint {
826    if !check_not_null(&mut env, ptr, "RiDatabaseMigration") {
827        return 0;
828    }
829    
830    let migration = unsafe { &*(ptr as *const RiDatabaseMigration) };
831    migration.version as jint
832}
833
834#[no_mangle]
835pub extern "system" fn Java_com_dunimd_ri_database_RiDatabaseMigration_getName0<'local>(
836    mut env: JNIEnv<'local>,
837    _class: JClass<'local>,
838    ptr: jlong,
839) -> jstring {
840    if !check_not_null(&mut env, ptr, "RiDatabaseMigration") {
841        return std::ptr::null_mut();
842    }
843    
844    let migration = unsafe { &*(ptr as *const RiDatabaseMigration) };
845    match env.new_string(&migration.name) {
846        Ok(s) => s.into_raw(),
847        Err(_) => std::ptr::null_mut(),
848    }
849}
850
851#[no_mangle]
852pub extern "system" fn Java_com_dunimd_ri_database_RiDatabaseMigration_getSqlUp0<'local>(
853    mut env: JNIEnv<'local>,
854    _class: JClass<'local>,
855    ptr: jlong,
856) -> jstring {
857    if !check_not_null(&mut env, ptr, "RiDatabaseMigration") {
858        return std::ptr::null_mut();
859    }
860    
861    let migration = unsafe { &*(ptr as *const RiDatabaseMigration) };
862    match env.new_string(&migration.sql_up) {
863        Ok(s) => s.into_raw(),
864        Err(_) => std::ptr::null_mut(),
865    }
866}
867
868#[no_mangle]
869pub extern "system" fn Java_com_dunimd_ri_database_RiDatabaseMigration_getSqlDown0<'local>(
870    mut env: JNIEnv<'local>,
871    _class: JClass<'local>,
872    ptr: jlong,
873) -> jstring {
874    if !check_not_null(&mut env, ptr, "RiDatabaseMigration") {
875        return std::ptr::null_mut();
876    }
877    
878    let migration = unsafe { &*(ptr as *const RiDatabaseMigration) };
879    match &migration.sql_down {
880        Some(sql) => match env.new_string(sql) {
881        Ok(s) => s.into_raw(),
882        Err(_) => std::ptr::null_mut(),
883    },
884        None => std::ptr::null_mut(),
885    }
886}
887
888#[no_mangle]
889pub extern "system" fn Java_com_dunimd_ri_database_RiDatabaseMigration_free0(
890    _env: JNIEnv,
891    _class: JClass,
892    ptr: jlong,
893) {
894    if ptr != 0 {
895        unsafe {
896            let _ = Box::from_raw(ptr as *mut RiDatabaseMigration);
897        }
898    }
899}