【问题标题】:How to store the database connection handle from sqlite3_open?如何存储来自 sqlite3_open 的数据库连接句柄?
【发布时间】:2017-07-05 09:43:33
【问题描述】:

我已经包装了 SQLite(版本 3.16.2)C-API 中的 sqlite3_opensqlite3_closesqlite3_exec 例程,以便使用 ISO_C_BINDING 模块从 Fortran 2003 程序调用它们。我在 Windows 上使用 Intel 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_execsqlite3_close 中使用。我是否应该在 Fortran 程序中定义某种 struct 来充当数据库连接结构,并将其传递给 C 例程?

【问题讨论】:

  • 使用标签fortran 获得更多关注。添加版本标签以区分特定版本,但此处不适用,您的问题在以后的版本中也可以。

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


【解决方案1】:

您正在将一个值 (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;
}

【讨论】:

  • 是的,这就是问题所在和解决方法。正如你所建议的,我最终直接使用了pdb。有趣的事情 - 我考虑了范围/生命周期,我可以发誓在发布原始问题之前我已经尝试过这个东西......但是,一切都很好!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多