Open7
SQLite3 を C を書かずに Fortran で使うことを試みる

どうやら、関数ポインタやダブルポインタと戦う必要がありそうです

INSERT文のように出力がない文はこのようにして実行できます。
mod_sqlite3.f90
module mod_sqlite3
use, intrinsic :: iso_c_binding
implicit none
! Error codes
integer, parameter :: SQLITE_OK = 0
interface
! SQLITE_API int sqlite3_open(
! const char *filename,
! sqlite3 **ppDb
! );
function sqlite3_open(filename, ppDb) bind(c,name="sqlite3_open")
use, intrinsic :: iso_c_binding
implicit none
integer(c_int) :: sqlite3_open
type(c_ptr), value :: filename, ppDb
end function
! SQLITE_API int sqlite3_exec(
! sqlite3*, /* An open database */
! const char *sql, /* SQL to be evaluated */
! int (*callback)(void*,int,char**,char**), /* Callback function */
! void *, /* 1st argument to callback */
! char **errmsg /* Error msg written here */
! );
function sqlite3_exec(ppDb, sql, callback, arg1, errmsg) bind(c)
use, intrinsic :: iso_c_binding
implicit none
integer(c_int) :: sqlite3_exec
type(c_ptr), value :: ppDb, sql, arg1, errmsg
type(c_funptr), value :: callback
end function sqlite3_exec
end interface
contains
end module mod_sqlite3
main.f90
program main
use, intrinsic :: iso_c_binding
use :: mod_sqlite3
implicit none
integer :: status
character(:), allocatable, target :: dbpath, query
type(c_ptr), target :: conn, errmsg
dbpath = "test.db" // c_null_char
query = "INSERT INTO user(name, age) VALUES('Nejikugi', 19);" // c_null_char
status = sqlite3_open(c_loc(dbpath), c_loc(conn))
if (status .ne. SQLITE_OK) then
print*, "Database open error."
stop -1
end if
status = sqlite3_exec(conn, c_loc(query), c_null_funptr ,c_null_ptr, c_loc(errmsg))
end program main

SELECT文のように出力がある文はこんな感じの引数を持った関数をc_loc_funptr()
で渡せばよさそうだけど、row_txtの長さを得るのが大変そう。'\0'
までの長さを数えないとだめ?
subroutine print_resp(arg1, col_count, row_txt, col_name) bind(c)
type(c_ptr), value :: arg1
integer(c_int), value :: col_count
type(c_ptr), value :: row_txt, col_name
! do something
end subroutine

これ、row_txtの長さはcol_countでした

ほぼ成功(文字列長さえきちんと処理すれば)
コールバック関数はサブルーチンじゃなくて関数じゃないとだめっぽい(SQLITE_ABORTする)
main.f90
program main
use, intrinsic :: iso_c_binding
use :: mod_sqlite3
implicit none
integer :: status
character(:), allocatable, target :: dbpath, query
type(c_ptr), target :: conn, errmsg
dbpath = "test.db" // c_null_char
query = "SELECT * FROM user;" // c_null_char
status = sqlite3_open(c_loc(dbpath), c_loc(conn))
if (status .ne. SQLITE_OK) then
print*, "Database open error."
stop -1
end if
status = sqlite3_exec(conn, c_loc(query), c_funloc(print_resp) ,c_null_ptr, c_loc(errmsg))
print*, status
contains
function print_resp(arg1, argc, argv, fields) bind(c)
implicit none
integer(c_int) :: print_resp
type(c_ptr), value :: arg1
integer(c_int), value :: argc
type(c_ptr), value :: argv, fields
type(c_ptr), pointer :: ptr_array(:)
character, pointer :: fstring(:)
integer i
print*, "CALL print_resp()"
! ↓これはあってそう
call c_f_pointer(argv, ptr_array, [argc])
! ↓ここ、文字列長をちゃんと求めなさい
do i=1, argc
call c_f_pointer(ptr_array(i), fstring, [12])
print *, 'Column ', i, ': ', fstring
end do
! ↓これがないとSQLITE_ABORTになります
print_resp = 0
return
end function
end program main

文字列長を求めるところが面倒なら strlen()
を持ってくるのもあり

↑これ、Fortran 2003 (-std=f2003)でコンパイルできません。