From 0917e3c4da446ba573a85e95cd5ddf921071c13b Mon Sep 17 00:00:00 2001 From: Philipp Date: Mon, 26 Feb 2024 22:13:50 +0100 Subject: [PATCH] Added preprocessor macros. --- .github/workflows/build.yml | 2 +- Makefile | 10 ++- README.md | 24 ++++++ ford.md | 1 + src/{sqlite3.f90 => sqlite3.F90} | 143 ++++++++++++++++--------------- test/test_sqlite3.f90 | 42 +++++---- 6 files changed, 133 insertions(+), 89 deletions(-) rename src/{sqlite3.f90 => sqlite3.F90} (99%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0a37043..919c25e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,7 +26,7 @@ jobs: sudo apt-get install -y gcc-${GCC_V} gfortran-${GCC_V} make sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_V} 100 \ --slave /usr/bin/gfortran gfortran /usr/bin/gfortran-${GCC_V} - sudo apt-get remove -y sqlite3 libsqlite3-0 libsqlite3-dev + sudo apt-get remove -y sqlite3 libsqlite3-dev - name: Build and Install SQLite 3 (Linux) if: contains(matrix.os, 'ubuntu') diff --git a/Makefile b/Makefile index b48a637..05748bf 100644 --- a/Makefile +++ b/Makefile @@ -11,10 +11,13 @@ RELEASE = -O2 -march=native CFLAGS = $(RELEASE) FFLAGS = $(RELEASE) +PPFLAGS = -DSQLITE_ENABLE_COLUMN_METADATA=0 LDFLAGS = -I$(PREFIX)/include -L$(PREFIX)/lib LDLIBS = -lsqlite3 ARFLAGS = rcs TARGET = libfortran-sqlite3.a +SRC = src/sqlite3_macro.c src/sqlite3.F90 src/sqlite3_util.f90 +OBJ = sqlite3.o sqlite3_macro.o sqlite3_util.o .PHONY: all clean test @@ -22,11 +25,11 @@ all: $(TARGET) test: test_sqlite3 -$(TARGET): src/sqlite3_util.f90 src/sqlite3.f90 +$(TARGET): $(SRC) $(CC) $(CFLAGS) -c src/sqlite3_macro.c $(FC) $(FFLAGS) -c src/sqlite3_util.f90 - $(FC) $(FFLAGS) -c src/sqlite3.f90 - $(AR) $(ARFLAGS) $(TARGET) sqlite3.o sqlite3_macro.o sqlite3_util.o + $(FC) $(FFLAGS) $(PPFLAGS) -c src/sqlite3.F90 + $(AR) $(ARFLAGS) $(TARGET) $(OBJ) test_sqlite3: $(TARGET) test/test_sqlite3.f90 $(FC) $(FFLAGS) $(LDFLAGS) -o test_sqlite3 test/test_sqlite3.f90 $(TARGET) $(LDLIBS) @@ -36,3 +39,4 @@ clean: if [ `ls -1 *.o 2>/dev/null | wc -l` -gt 0 ]; then rm *.o; fi if [ -e $(TARGET) ]; then rm $(TARGET); fi if [ -e test_sqlite3 ]; then rm test_sqlite3; fi + if [ -e test.sqlite ]; then rm test.sqlite; fi diff --git a/README.md b/README.md index ca5f796..6a16a69 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,12 @@ run: # pkg install databases/sqlite3 ``` +On Linux: + +``` +# apt-get install sqlite3 libsqlite3-0 libsqlite3-dev +``` + Then, clone the GitHub repository: ``` @@ -40,9 +46,27 @@ Execute the provided `Makefile`: $ make ``` +Pass the preprocessor flag `-DSQLITE_ENABLE_COLUMN_METADATA=1` to add interface +bindings to column meta data functions: + +``` +$ make PPFLAGS="-DSQLITE_ENABLE_COLUMN_METADATA=1" +``` + You may want to override the default compilers by passing the arguments `CC` (C compiler) and `FC` (Fortran compiler). +## Source-Code Documentation + +Use [FORD](https://github.com/Fortran-FOSS-Programmers/ford) to generate the +source-code documentation: + +``` +$ ford ford.md +``` + +The output files are written to `doc/`. + ## Example The following SQL schema will be created by the example: diff --git a/ford.md b/ford.md index 4db9a79..4bae7fe 100644 --- a/ford.md +++ b/ford.md @@ -2,3 +2,4 @@ project: fortran-sqlite3 summary: A collection of ISO C binding interfaces to SQLite 3. author: Philipp Engel project_github: https://github.com/interkosmos/fortran-sqlite3 +macro: SQLITE_ENABLE_COLUMN_METADATA=1 diff --git a/src/sqlite3.f90 b/src/sqlite3.F90 similarity index 99% rename from src/sqlite3.f90 rename to src/sqlite3.F90 index 16664d9..1b51f49 100644 --- a/src/sqlite3.f90 +++ b/src/sqlite3.F90 @@ -193,16 +193,10 @@ module sqlite3 public :: sqlite3_close public :: sqlite3_close_ public :: sqlite3_column_count - public :: sqlite3_column_database_name - public :: sqlite3_column_database_name_ public :: sqlite3_column_double public :: sqlite3_column_int public :: sqlite3_column_int64 public :: sqlite3_column_name - public :: sqlite3_column_origin_name - public :: sqlite3_column_origin_name_ - public :: sqlite3_column_table_name - public :: sqlite3_column_table_name_ public :: sqlite3_column_text public :: sqlite3_column_type public :: sqlite3_config @@ -264,6 +258,21 @@ module sqlite3 public :: sqlite3_threadsafe public :: sqlite3_update_hook +#if SQLITE_ENABLE_COLUMN_METADATA + public :: sqlite3_column_database_name + public :: sqlite3_column_database_name_ + public :: sqlite3_column_table_name + public :: sqlite3_column_table_name_ + public :: sqlite3_column_origin_name + public :: sqlite3_column_origin_name_ +#endif + + interface sqlite3_config + module procedure :: sqlite3_config_funptr_ptr + module procedure :: sqlite3_config_int + module procedure :: sqlite3_config_null + end interface + interface ! int sqlite3_backup_finish(sqlite3_backup *p) function sqlite3_backup_finish(p) bind(c, name='sqlite3_backup_finish') @@ -420,15 +429,6 @@ function sqlite3_column_count(stmt) bind(c, name='sqlite3_column_count') integer(kind=c_int) :: sqlite3_column_count end function sqlite3_column_count - ! const char *sqlite3_column_database_name(sqlite3_stmt *stmt, int idx) - function sqlite3_column_database_name_(stmt, idx) bind(c, name='sqlite3_column_database_name') - import :: c_int, c_ptr - implicit none - type(c_ptr), intent(in), value :: stmt - integer(kind=c_int), intent(in), value :: idx - type(c_ptr) :: sqlite3_column_database_name_ - end function sqlite3_column_database_name_ - ! double sqlite3_column_double(sqlite3_stmt *stmt, int idx) function sqlite3_column_double(stmt, idx) bind(c, name='sqlite3_column_double') import :: c_double, c_int, c_ptr @@ -465,24 +465,6 @@ function sqlite3_column_name_(stmt, idx) bind(c, name='sqlite3_column_name') type(c_ptr) :: sqlite3_column_name_ end function sqlite3_column_name_ - ! const char *sqlite3_column_origin_name(sqlite3_stmt *stmt, int idx) - function sqlite3_column_origin_name_(stmt, idx) bind(c, name='sqlite3_column_origin_name') - import :: c_int, c_ptr - implicit none - type(c_ptr), intent(in), value :: stmt - integer(kind=c_int), intent(in), value :: idx - type(c_ptr) :: sqlite3_column_origin_name_ - end function sqlite3_column_origin_name_ - - ! const char *sqlite3_column_table_name(sqlite3_stmt *stmt, int idx) - function sqlite3_column_table_name_(stmt, idx) bind(c, name='sqlite3_column_table_name') - import :: c_int, c_ptr - implicit none - type(c_ptr), intent(in), value :: stmt - integer(kind=c_int), intent(in), value :: idx - type(c_ptr) :: sqlite3_column_table_name_ - end function sqlite3_column_table_name_ - ! const unsigned char *sqlite3_column_text(sqlite3_stmt *stmt, int idx) function sqlite3_column_text_(stmt, idx) bind(c, name='sqlite3_column_text') import :: c_int, c_ptr @@ -898,11 +880,36 @@ subroutine sqlite3_str_reset(str) bind(c, name='slqite3_str_reset') end subroutine sqlite3_str_reset end interface - interface sqlite3_config - module procedure :: sqlite3_config_funptr_ptr - module procedure :: sqlite3_config_int - module procedure :: sqlite3_config_null +#if SQLITE_ENABLE_COLUMN_METADATA + interface + ! const char *sqlite3_column_database_name(sqlite3_stmt *stmt, int idx) + function sqlite3_column_database_name_(stmt, idx) bind(c, name='sqlite3_column_database_name') + import :: c_int, c_ptr + implicit none + type(c_ptr), intent(in), value :: stmt + integer(kind=c_int), intent(in), value :: idx + type(c_ptr) :: sqlite3_column_database_name_ + end function sqlite3_column_database_name_ + + ! const char *sqlite3_column_origin_name(sqlite3_stmt *stmt, int idx) + function sqlite3_column_origin_name_(stmt, idx) bind(c, name='sqlite3_column_origin_name') + import :: c_int, c_ptr + implicit none + type(c_ptr), intent(in), value :: stmt + integer(kind=c_int), intent(in), value :: idx + type(c_ptr) :: sqlite3_column_origin_name_ + end function sqlite3_column_origin_name_ + + ! const char *sqlite3_column_table_name(sqlite3_stmt *stmt, int idx) + function sqlite3_column_table_name_(stmt, idx) bind(c, name='sqlite3_column_table_name') + import :: c_int, c_ptr + implicit none + type(c_ptr), intent(in), value :: stmt + integer(kind=c_int), intent(in), value :: idx + type(c_ptr) :: sqlite3_column_table_name_ + end function sqlite3_column_table_name_ end interface +#endif contains function sqlite3_backup_init(dest, dest_name, source, source_name) type(c_ptr), intent(in) :: dest @@ -950,16 +957,6 @@ function sqlite3_close(db) if (sqlite3_close == SQLITE_OK) db = c_null_ptr end function sqlite3_close - function sqlite3_column_database_name(stmt, idx) - type(c_ptr), intent(inout) :: stmt - integer, intent(in) :: idx - character(len=:), allocatable :: sqlite3_column_database_name - type(c_ptr) :: ptr - - ptr = sqlite3_column_database_name_(stmt, idx) - call c_f_str_ptr(ptr, sqlite3_column_database_name) - end function sqlite3_column_database_name - function sqlite3_column_name(stmt, idx) type(c_ptr), intent(inout) :: stmt integer, intent(in) :: idx @@ -970,26 +967,6 @@ function sqlite3_column_name(stmt, idx) call c_f_str_ptr(ptr, sqlite3_column_name) end function sqlite3_column_name - function sqlite3_column_origin_name(stmt, idx) - type(c_ptr), intent(inout) :: stmt - integer, intent(in) :: idx - character(len=:), allocatable :: sqlite3_column_origin_name - type(c_ptr) :: ptr - - ptr = sqlite3_column_origin_name_(stmt, idx) - call c_f_str_ptr(ptr, sqlite3_column_origin_name) - end function sqlite3_column_origin_name - - function sqlite3_column_table_name(stmt, idx) - type(c_ptr), intent(inout) :: stmt - integer, intent(in) :: idx - character(len=:), allocatable :: sqlite3_column_table_name - type(c_ptr) :: ptr - - ptr = sqlite3_column_table_name_(stmt, idx) - call c_f_str_ptr(ptr, sqlite3_column_table_name) - end function sqlite3_column_table_name - function sqlite3_column_text(stmt, idx) type(c_ptr), intent(inout) :: stmt integer, intent(in) :: idx @@ -1173,4 +1150,36 @@ subroutine sqlite3_log(ierr_code, str) call sqlite3_log_(ierr_code, str // c_null_char) end subroutine sqlite3_log + +#if SQLITE_ENABLE_COLUMN_METADATA + function sqlite3_column_database_name(stmt, idx) + type(c_ptr), intent(inout) :: stmt + integer, intent(in) :: idx + character(len=:), allocatable :: sqlite3_column_database_name + type(c_ptr) :: ptr + + ptr = sqlite3_column_database_name_(stmt, idx) + call c_f_str_ptr(ptr, sqlite3_column_database_name) + end function sqlite3_column_database_name + + function sqlite3_column_origin_name(stmt, idx) + type(c_ptr), intent(inout) :: stmt + integer, intent(in) :: idx + character(len=:), allocatable :: sqlite3_column_origin_name + type(c_ptr) :: ptr + + ptr = sqlite3_column_origin_name_(stmt, idx) + call c_f_str_ptr(ptr, sqlite3_column_origin_name) + end function sqlite3_column_origin_name + + function sqlite3_column_table_name(stmt, idx) + type(c_ptr), intent(inout) :: stmt + integer, intent(in) :: idx + character(len=:), allocatable :: sqlite3_column_table_name + type(c_ptr) :: ptr + + ptr = sqlite3_column_table_name_(stmt, idx) + call c_f_str_ptr(ptr, sqlite3_column_table_name) + end function sqlite3_column_table_name +#endif end module sqlite3 diff --git a/test/test_sqlite3.f90 b/test/test_sqlite3.f90 index f473cc6..bd6e093 100644 --- a/test/test_sqlite3.f90 +++ b/test/test_sqlite3.f90 @@ -18,8 +18,9 @@ integer(kind=c_int) function exec_callback(client_data, argc, argv, cols) bind(c integer(kind=c_int), intent(in), value :: argc type(c_ptr), intent(in) :: argv(*) type(c_ptr), intent(in) :: cols(*) - character(len=:), allocatable :: buf - integer :: i + + character(len=:), allocatable :: buf + integer :: i exec_callback = 1 ! No more rows on error. @@ -41,7 +42,8 @@ subroutine error_log_callback(udp, err_code, err_msg) bind(c) type(c_ptr), intent(in), value :: udp integer(kind=c_int), intent(in), value :: err_code type(c_ptr), intent(in), value :: err_msg - character(len=:), allocatable :: msg + + character(len=:), allocatable :: msg call c_f_str_ptr(err_msg, msg) print '(a)', repeat('-', 64) @@ -60,7 +62,8 @@ subroutine update_callback(udp, type, db_name, tbl_name, rowid) bind(c) type(c_ptr), intent(in), value :: db_name type(c_ptr), intent(in), value :: tbl_name integer(kind=c_int64_t), intent(in), value :: rowid - character(len=:), allocatable :: db_str, tbl_str + + character(len=:), allocatable :: db_str, tbl_str call c_f_str_ptr(db_name, db_str) call c_f_str_ptr(tbl_name, tbl_str) @@ -89,15 +92,16 @@ program test_sqlite3 use :: sqlite3 use :: callbacks implicit none (type, external) - character(len=*), parameter :: DB_FILE = 'test.db' + character(len=*), parameter :: DB_FILE = 'test.sqlite' character(len=*), parameter :: DB_TABLE = 'test_table' character(len=:), allocatable :: db_name ! Database name. character(len=:), allocatable :: errmsg ! Error message. - integer :: rc ! Return code. - type(c_ptr) :: db ! SQLite database. - type(c_ptr) :: stmt ! SQLite statement. - type(c_ptr) :: udp ! User-data pointer. + + integer :: rc ! Return code. + type(c_ptr) :: db ! SQLite database. + type(c_ptr) :: stmt ! SQLite statement. + type(c_ptr) :: udp ! User-data pointer. ! Set configuration to single thread. rc = sqlite3_config(SQLITE_CONFIG_SINGLETHREAD) @@ -211,10 +215,11 @@ program test_sqlite3 contains integer function journal_mode_wal(db) result(rc) !! Enables WAL mode. - type(c_ptr), intent(inout) :: db - character(len=:), allocatable :: buf - integer :: err - type(c_ptr) :: stmt + type(c_ptr), intent(inout) :: db + + character(len=:), allocatable :: buf + integer :: err + type(c_ptr) :: stmt rc = -1 @@ -252,11 +257,12 @@ subroutine print_error(rc, func, errmsg) end subroutine print_error subroutine print_values(stmt, ncols) - type(c_ptr), intent(inout) :: stmt - integer, intent(in) :: ncols - integer :: col_type - integer :: i - character(len=:), allocatable :: buf + type(c_ptr), intent(inout) :: stmt + integer, intent(in) :: ncols + + integer :: col_type + integer :: i + character(len=:), allocatable :: buf do i = 0, ncols - 1 col_type = sqlite3_column_type(stmt, i)