Как сохранить дескриптор подключения к базе данных из sqlite3_open?

Я обернул подпрограммы sqlite3_open, sqlite3_close и sqlite3_exec из C-API SQLite (версия 3.16.2), чтобы вызывать их из программа на Фортране 2003, использующая модуль ISO_C_BINDING. Я использую компилятор Intel Fortran 17 (ifort) с MSVC 14 в Windows и с gcc в Linux.

Моя цель — открыть базу данных SQLite и сохранить указатель на дескриптор соединения с базой данных, чтобы я мог использовать его для хранения/извлечения результатов, когда программа 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

Я не уверен, что понимаю официальную документацию, но они, похоже, утверждают, что *db указатель, представляющий дескриптор соединения с базой данных, который представляет собой «непрозрачную структуру», определенную как typedef struct sqlite3 sqlite3;. Я точно не знаю, что это значит (программирование на C не моя сильная сторона). Поэтому я попытался установить C_PTR из Fortran следующим образом:

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

Сначала кажется, что это работает. Однако указатель возвращается к NULL после передачи обратно в программу на Фортране и не может использоваться в sqlite3_exec или sqlite3_close. Должен ли я определить какую-то struct в программе на Фортране, чтобы она действовала как структура соединения с базой данных, и передать ее в подпрограммы C?


person Matt P    schedule 16.02.2017    source источник
comment
Используйте тег fortran, чтобы привлечь больше внимания. Добавьте тег версии, чтобы различать конкретную версию, но здесь это неприменимо, ваш вопрос подходит и для более поздних версий.   -  person Vladimir F    schedule 16.02.2017


Ответы (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;
}
person David Ranieri    schedule 16.02.2017
comment
Да, это была проблема и решение. Как вы предполагаете, я использовал pdb напрямую. Забавно - я думал о масштабе/времени жизни и могу поклясться, что попробовал именно это, прежде чем публиковать исходный вопрос... Но все хорошо, что хорошо кончается! - person Matt P; 16.02.2017