如何从sqlite3_open存储数据库连接句柄?

时间:2017-02-16 10:29:44

标签: c sqlite fortran fortran-iso-c-binding

我已经从SQLite(版本3.16.2)C-API中包装了 sqlite3_open sqlite3_close sqlite3_exec 例程,以便使用ISO_C_BINDING模块从Fortran 2003程序中调用它们。我在Windows上使用英特尔Fortran 17编译器(ifort)与MSVC 14,在Linux上使用gcc。

我的目标是打开SQLite DB并存储指向数据库连接句柄的指针,以便在Fortran程序循环计算时可以使用它来存储/检索结果。主程序伪代码看起来像:

program main
  use, intrinsic :: iso_c_binding
  use sqlite_wrapper_module
  implicit none

  ! QUESTION: SHOULD DB_HANDLE BE TYPE(C_PTR) OR A STRUCT OF SOME KIND? 
  type(C_PTR) :: db_handle

  character(len=:), allocatable :: db_name

  db_name = "test.db"//C_NULL_CHAR
  call sqlite3_open_WRAPPER(db_name, db_handle)       ! wraps sqlite3_open

  do i=1,n
    ...compute stuff...
    call sqlite3_exec_WRAPPER(db_handle, sql_stmt)    ! wraps sqlite3_exec
    ...compute stuff...
  enddo

  call sqlite3_close_WRAPPER(db_handle)               ! wraps sqlite3_close
end program main

我已在单独的模块中定义了包装器C例程的显式接口。例如:

module sqlite_wrapper_module
  use, intrisic :: iso_c_binding
  implicit none
  interface
    subroutine sqlite3_open_WRAPPER(db_name, db_handle) bind(C)
      import
      character(kind=C_CHAR), dimension(*) :: db_name
      type(C_PTR), value :: db_handle
    end subroutine sqlite3_open_wrapper
  end interface
end module sqlite_wrapper_module

我不确定我理解official docs,但他们似乎声明* db是一个表示数据库连接句柄的指针,这是一个"不透明的结构"定义为typedef struct sqlite3 sqlite3;。我不确切地知道这意味着什么(C编程不是我的强项)。所以我尝试从Fortran设置C_PTR,如下所示:

int sqlite3_open_WRAPPER(char *filename, sqlite3 *pdb) {
  sqlite3 *db;
  int rc=sqlite3_open(filename, &db);
  pdb=db;        // <---------------------------------This
  ...check rc...
  return 0;
}

起初,这似乎有效。但是,一旦传回Fortran程序,指针就会返回NULL,并且无法在 sqlite3_exec sqlite3_close 中使用。我应该在Fortran程序中定义某种struct作为数据库连接结构,并将其传递给C例程吗?

1 个答案:

答案 0 :(得分:3)

您正在为一个本地变量(db)分配一个值(pdb),该变量的生命周期以该函数结束,使用指向指针的指针,以便在函数外部显示这些更改:

int sqlite3_open_WRAPPER(char *filename, sqlite3 *pdb) {
  sqlite3 *db;
  int rc=sqlite3_open(filename, &db);
  pdb=db;        // <---------------------------------This
  ...check rc...
  return 0;
}

应该是

int sqlite3_open_WRAPPER(char *filename, sqlite3 **pdb) {
  sqlite3 *db;
  int rc=sqlite3_open(filename, &db);
  *pdb=db;        // <---------------------------------This
  ...check rc...
  return 0;
}

或者更好的是,直接使用pdb

int sqlite3_open_WRAPPER(char *filename, sqlite3 **pdb) {
  int rc=sqlite3_open(filename, pdb);
  ...check rc...
  return 0;
}