Compare commits

...

66 Commits

Author SHA1 Message Date
Evan Miller
c6486ce68c Update GCC
Some checks failed
build / linux (clang, enable-glib, disable-iconv) (push) Has been cancelled
build / linux (clang, enable-glib, enable-iconv) (push) Has been cancelled
build / linux (gcc, disable-glib, disable-iconv) (push) Has been cancelled
build / linux (gcc, disable-glib, enable-iconv) (push) Has been cancelled
build / linux (gcc, enable-glib, disable-iconv) (push) Has been cancelled
build / linux (gcc, enable-glib, enable-iconv) (push) Has been cancelled
build / linux (gcc-11, disable-glib, disable-iconv) (push) Has been cancelled
build / linux (gcc-11, disable-glib, enable-iconv) (push) Has been cancelled
build / linux (gcc-11, enable-glib, disable-iconv) (push) Has been cancelled
build / linux (gcc-11, enable-glib, enable-iconv) (push) Has been cancelled
build / linux (gcc-12, disable-glib, disable-iconv) (push) Has been cancelled
build / linux (gcc-12, disable-glib, enable-iconv) (push) Has been cancelled
build / linux (gcc-12, enable-glib, disable-iconv) (push) Has been cancelled
build / linux (gcc-12, enable-glib, enable-iconv) (push) Has been cancelled
build / macos (clang, disable-glib, disable-iconv) (push) Has been cancelled
build / macos (clang, disable-glib, enable-iconv) (push) Has been cancelled
build / macos (clang, enable-glib, disable-iconv) (push) Has been cancelled
build / macos (clang, enable-glib, enable-iconv) (push) Has been cancelled
build / macos (gcc, disable-glib, disable-iconv) (push) Has been cancelled
build / macos (gcc, disable-glib, enable-iconv) (push) Has been cancelled
build / macos (gcc, enable-glib, disable-iconv) (push) Has been cancelled
build / macos (gcc, enable-glib, enable-iconv) (push) Has been cancelled
build / macos-iodbc (clang, disable-glib) (push) Has been cancelled
build / macos-iodbc (clang, enable-glib) (push) Has been cancelled
build / macos-iodbc (gcc, disable-glib) (push) Has been cancelled
build / macos-iodbc (gcc, enable-glib) (push) Has been cancelled
build / windows (disable-glib, disable-iconv) (push) Has been cancelled
build / windows (disable-glib, enable-iconv) (push) Has been cancelled
build / windows (enable-glib, disable-iconv) (push) Has been cancelled
build / windows (enable-glib, enable-iconv) (push) Has been cancelled
2025-05-23 07:58:16 -04:00
Evan Miller
11607108be CI fixes 2025-05-23 07:47:15 -04:00
Trương Chương Dương
6ed4188994
Fix error when ccompile by mingw32 and remove the $ from example shell script (#448)
Some checks failed
build / linux (clang, enable-glib, disable-iconv) (push) Has been cancelled
build / linux (clang, enable-glib, enable-iconv) (push) Has been cancelled
build / linux (gcc, disable-glib, disable-iconv) (push) Has been cancelled
build / linux (gcc, disable-glib, enable-iconv) (push) Has been cancelled
build / linux (gcc, enable-glib, disable-iconv) (push) Has been cancelled
build / linux (gcc, enable-glib, enable-iconv) (push) Has been cancelled
build / linux (gcc-10, disable-glib, disable-iconv) (push) Has been cancelled
build / linux (gcc-10, disable-glib, enable-iconv) (push) Has been cancelled
build / linux (gcc-10, enable-glib, disable-iconv) (push) Has been cancelled
build / linux (gcc-10, enable-glib, enable-iconv) (push) Has been cancelled
build / linux (gcc-9, disable-glib, disable-iconv) (push) Has been cancelled
build / linux (gcc-9, disable-glib, enable-iconv) (push) Has been cancelled
build / linux (gcc-9, enable-glib, disable-iconv) (push) Has been cancelled
build / linux (gcc-9, enable-glib, enable-iconv) (push) Has been cancelled
build / macos (clang, disable-glib, disable-iconv) (push) Has been cancelled
build / macos (clang, disable-glib, enable-iconv) (push) Has been cancelled
build / macos (clang, enable-glib, disable-iconv) (push) Has been cancelled
build / macos (clang, enable-glib, enable-iconv) (push) Has been cancelled
build / macos (gcc, disable-glib, disable-iconv) (push) Has been cancelled
build / macos (gcc, disable-glib, enable-iconv) (push) Has been cancelled
build / macos (gcc, enable-glib, disable-iconv) (push) Has been cancelled
build / macos (gcc, enable-glib, enable-iconv) (push) Has been cancelled
build / macos-iodbc (clang, disable-glib) (push) Has been cancelled
build / macos-iodbc (clang, enable-glib) (push) Has been cancelled
build / macos-iodbc (gcc, disable-glib) (push) Has been cancelled
build / macos-iodbc (gcc, enable-glib) (push) Has been cancelled
build / windows (disable-glib, disable-iconv) (push) Has been cancelled
build / windows (disable-glib, enable-iconv) (push) Has been cancelled
build / windows (enable-glib, disable-iconv) (push) Has been cancelled
build / windows (enable-glib, enable-iconv) (push) Has been cancelled
* Fix build error with mingw32

* Remove $ from shell example

---------

Co-authored-by: hacrot3000 <hacrot3000@gmail.com>
2025-05-20 09:00:20 -04:00
Evan Miller
b81b1c9271 Version 1.0.1
Some checks failed
build / linux (clang, enable-glib, disable-iconv) (push) Has been cancelled
build / linux (clang, enable-glib, enable-iconv) (push) Has been cancelled
build / linux (gcc, disable-glib, disable-iconv) (push) Has been cancelled
build / linux (gcc, disable-glib, enable-iconv) (push) Has been cancelled
build / linux (gcc, enable-glib, disable-iconv) (push) Has been cancelled
build / linux (gcc, enable-glib, enable-iconv) (push) Has been cancelled
build / linux (gcc-10, disable-glib, disable-iconv) (push) Has been cancelled
build / linux (gcc-10, disable-glib, enable-iconv) (push) Has been cancelled
build / linux (gcc-10, enable-glib, disable-iconv) (push) Has been cancelled
build / linux (gcc-10, enable-glib, enable-iconv) (push) Has been cancelled
build / linux (gcc-9, disable-glib, disable-iconv) (push) Has been cancelled
build / linux (gcc-9, disable-glib, enable-iconv) (push) Has been cancelled
build / linux (gcc-9, enable-glib, disable-iconv) (push) Has been cancelled
build / linux (gcc-9, enable-glib, enable-iconv) (push) Has been cancelled
build / macos (clang, disable-glib, disable-iconv) (push) Has been cancelled
build / macos (clang, disable-glib, enable-iconv) (push) Has been cancelled
build / macos (clang, enable-glib, disable-iconv) (push) Has been cancelled
build / macos (clang, enable-glib, enable-iconv) (push) Has been cancelled
build / macos (gcc, disable-glib, disable-iconv) (push) Has been cancelled
build / macos (gcc, disable-glib, enable-iconv) (push) Has been cancelled
build / macos (gcc, enable-glib, disable-iconv) (push) Has been cancelled
build / macos (gcc, enable-glib, enable-iconv) (push) Has been cancelled
build / macos-iodbc (clang, disable-glib) (push) Has been cancelled
build / macos-iodbc (clang, enable-glib) (push) Has been cancelled
build / macos-iodbc (gcc, disable-glib) (push) Has been cancelled
build / macos-iodbc (gcc, enable-glib) (push) Has been cancelled
build / windows (disable-glib, disable-iconv) (push) Has been cancelled
build / windows (disable-glib, enable-iconv) (push) Has been cancelled
build / windows (enable-glib, disable-iconv) (push) Has been cancelled
build / windows (enable-glib, enable-iconv) (push) Has been cancelled
2024-12-26 07:28:56 -05:00
Evan Miller
c5d4d1d4ee Fix txt2man path 2024-12-26 07:27:34 -05:00
Evan Miller
7625bfaebf Build fixes 2024-12-26 06:33:37 -05:00
Yuhang Ji
4c4ff13237
Update HACKING.md (#439)
Add the missing `& offset_mask` to `offset_stop of memo`
2024-07-04 10:19:57 -04:00
Evan Miller
2b2ef525c8 Fix another brew path on macos CI 2024-05-14 16:09:10 -04:00
Evan Miller
3a954c00d4 Fix brew paths on macos CI 2024-05-14 16:01:41 -04:00
Evan Miller
98d17badc6 Install unixodbc on macos CI 2024-05-14 14:24:51 -04:00
Evan Miller
997f4ec846 Install libtool on macos CI 2024-05-14 14:20:16 -04:00
bstoeger
f517db5df0
Move includes out of extern "C" block (#435)
"mbdtools.h" couldn't be included from C++ files, because the "glib.h"
include is in the extern "C" block. The latter includes C++ headers
for C++ source files, which define templates. These don't work with
extern "C" linkage and the compilation falls apart with numerous
errors.

To fix this problem, move the includes out of the extern "C" block.
2024-05-13 09:12:45 -04:00
Akkana Peck
7e057e3197
Fix a minor error in the mdb-json man page (#427) 2024-02-17 13:18:12 -05:00
Michele Locati
bb83142d47
Make test_script.sh less verbose (configurable) (#424) 2023-10-10 08:18:52 -04:00
Benjamin Holstein
bf77523c1d
Add support for SQLGetData converting floating point types (#422) 2023-10-06 18:31:26 -04:00
Michele Locati
c423097326
Fix invalid byte sequence error when running test_script.sh in some cases (#423)
This fixes the following error that may occur:
argument parsing failed: Invalid byte sequence in conversion input
2023-10-06 17:00:07 -04:00
Evan Miller
57d9e7a65e
Fix iodbc path on macos GH action (#421) 2023-09-10 14:16:02 -04:00
Elio Blanca
6640f9c707
fix use after free (#419) 2023-09-03 20:54:22 -04:00
Mladen Milinkovic
328249a628
Fixed truncating 64bit (SQL_NULL_DATA) values (#416) 2023-07-06 06:47:10 -04:00
Cédric Luthi
0d67eb4c73
Fix ODBC_LIBS for unixODBC (#415)
Using `$libdir` doesn't work and produces an error when configuring with ` ./configure --with-unixodbc=$(brew --prefix)`

> configure:21209: gcc -o conftest -g -O2 -Wall -Werror   -L/opt/homebrew/${exec_prefix}/lib conftest.c -lodbcinst   >&5
> ld: warning: directory not found for option '-L/opt/homebrew/${exec_prefix}/lib'
> ld: library not found for -lodbcinst
> clang: error: linker command failed with exit code 1 (use -v to see invocation)

Note that `warning: directory not found for option '-L/.../${exec_prefix}/lib'` is always emitted but if unixodbc is installed in `/usr/local/lib` linking would still work.
2023-07-04 14:56:41 -04:00
Cédric Luthi
633d1c091f
Make DSN and DBQ extraction from connection string case insensitive (#414) 2023-07-03 15:34:02 -04:00
drf5n
1097a48b80
Update README.md to remove INSTALL reference (#407)
Per https://github.com/mdbtools/mdbtools/issues/406#issuecomment-1463541923
2023-05-17 07:10:43 -04:00
Evan Miller
d9025dbf22 Two more code pages 2023-04-27 20:36:22 -04:00
Marco Manfredini
0e77b68e76
Add index and primary key output to the sqlite schema writer backend. (#402) 2023-02-02 05:36:22 -05:00
Evan Miller
9aa68a6ba1 Fix macos-iodbc CI build 2023-02-02 05:35:21 -05:00
Evan Miller
f7ae5e3f3c
Require glib2 2.68 or later (for g_memdup2) (#400) 2022-12-17 07:08:44 -05:00
Evan Miller
f14fbea093 Fix C89 errors 2022-12-17 05:41:45 -05:00
Evan Miller
d54f7b669f update gitignore 2022-12-17 05:36:26 -05:00
Evan Miller
0b96ecaff1
Fix windows GH action (#399) 2022-12-17 05:33:40 -05:00
Evan Miller
9e1ec2a588
Merge pull request #394 from h3xx/fix-bash-completion
Fix wrongly installed mdb-sql completion script
2022-08-26 08:26:57 -04:00
Dan Church
ff544c0b76
Fix wrongly installed mdb-sql completion script
Gate it behind the same conditional that the `mdb-sql` program is gated
behind.
2022-08-24 16:34:11 -05:00
Evan Miller
ab5beff0fa
Merge pull request #381 from schaanie17/dev
Changed mapping of MDB_DOUBLE for MySQL from float to double
2022-03-08 12:14:46 -08:00
Jan Langer
22af793623 Changed mapping of MDB_DOUBLE for MySQL from float to double 2022-03-08 19:18:08 +01:00
Evan Miller
ff085816b2
Merge pull request #377 from jwrdegoede/oss-fuzz-35972-null-ptr-deref-fix
Always check mdb_read_table() return value
2022-01-25 10:46:43 -05:00
Hans de Goede
03391fc913 Always check mdb_read_table() return value
A couple of places were missing NULL return value checks for
mdb_read_table()'s return value. Add these.

This fixes a NULL pointer deref while running ./test_script.sh
on the test mdb file from oss-fuzz/35972 .

Note this does NOT fix the original problem reported in oss-fuzz/35972
which reports a "Dynamic-stack-buffer-overflow WRITE 16" issue,
which I've been unable to reproduce.
2022-01-25 16:35:28 +01:00
Evan Miller
2da65ffdb3
Merge pull request #376 from jwrdegoede/oss-fuzz-36187-null-ptr-deref-fix
Fix null-ptr deref when table->map_sz is 0
2022-01-25 10:24:14 -05:00
Hans de Goede
4febc7b5c6 Fix null-ptr deref when table->map_sz is 0
The oss-fuzz/36187 attached
clusterfuzz-testcase-minimized-fuzz_mdb-4756071066501120
has a table with a map_sz of 0 and the g_memdup2 call returns NULL for
this, while mdb_map_find_next unconditionally derefs table->usage_map
to read the first byte which contains the map-type.

This leads to a NULL-ptr deref (at least with -fsanitize=address builds),
fix this by rejecting tables with a map_sz of 0.

Note this does NOT fix the original problem reported in oss-fuzz/36187
which reports a "Dynamic-stack-buffer-overflow WRITE 16" issue, which
I've been unable to reproduce.
2022-01-25 15:10:38 +01:00
pedromorgan@gmail.com
bcad261464 remove *.css.map 2021-11-24 10:41:48 -05:00
Evan Miller
ab9e4088a9 Merge branch 'dev' 2021-10-24 09:17:04 -04:00
Evan Miller
1f88aac676 Version 1.0.0 2021-10-24 09:05:19 -04:00
Evan Miller
c3df30837e Fix appveyor build 2021-09-30 09:59:16 -04:00
Christian Ehrhardt
22c379a611 Fix gcc-11 error "directive argument is null"
mdbtools triggered
In function ‘printf’,
    inlined from ‘mdb_dump_catalog’ at catalog.c:195:4:
/usr/include/powerpc64le-linux-gnu/bits/stdio2.h:112:10:
error: ‘%-12s’ directive argument is null [-Werror=format-overflow=]
  112 |   return __printf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __va_arg_pack ());

This is due to mdb_get_objtype_string potentially returning NULL
which isn't allowed anymore as it would cause a segfault on the latter
print.

Fixes: #352

Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
2021-09-30 08:19:53 -04:00
Evan Miller
5946750058 Version 1.0.0, Beta 7 2021-09-29 15:53:46 -04:00
Evan Miller
5ddad8660b Clarify some bit-shifting casts 2021-09-29 09:20:24 -04:00
Evan Miller
6de0227a36 Fix export of byte field values >127
Regression introduced in v0.9.3-beta1. Fixes #350
2021-09-29 09:16:22 -04:00
Evan Miller
b0a1f00113 Version 1.0.0, Beta 6 2021-09-12 16:00:21 -04:00
Evan Miller
77ee311eec Rearrange some ODBC code
Move unixODBC specific code to its own source file, and support old
iODBC installations that have only iodbinst.h.
2021-09-08 11:07:17 -04:00
Evan Miller
c04a3fb9a7 Merge branch 'dev' of github.com:mdbtools/mdbtools into dev 2021-09-08 10:58:30 -04:00
Evan Miller
ee5834d239 Print deprecation warnings before usage info 2021-09-08 10:50:28 -04:00
Evan Miller
f0d435ecdb Use TLS macro for cross-platform thread-local storage 2021-09-08 09:09:03 -04:00
Evan Miller
c137d64d13 Improved bounds checking 2021-09-08 06:41:58 -04:00
Evan Miller
4369721363 ODBC: Support SQL_C_WCHAR target type. Fixes #347
Also remove SQLFetchW and SQLGetDataW since they are not documented
in any other ODBC drivers.
2021-09-08 06:15:59 -04:00
Evan Miller
30d55a87ef Version 1.0.0, Beta 5 2021-09-06 15:22:23 -04:00
Evan Miller
a0e72c5dfa Implement SQLFetchW
Fixes #347
2021-09-06 15:09:46 -04:00
Evan Miller
16b2970931
Merge pull request #344 from nyalldawson/repid_odbc_str2
Customizable UUID format with mdb_uuid_to_string_fmt()
2021-08-30 09:17:25 -04:00
Nyall Dawson
98ef4a1663 [odbc] Ensure repid field formatting matching Microsoft Access ODBC
driver formatting of these fields (i.e. without surrounding {} braces)
2021-08-30 09:34:29 +10:00
Evan Miller
92dc91bfe8
Merge pull request #343 from nyalldawson/fix_index_read_errors
Fix accidental reads of non-index data as indices
2021-08-29 07:20:27 -04:00
Evan Miller
9b57c3ff66
Merge pull request #342 from nyalldawson/fix_double_conversion
Fix incorrect conversion of double values
2021-08-29 07:14:36 -04:00
Nyall Dawson
d94796d79b Fix accidental reads of non-index data as indices
Follow up be2a287f5c - it's hard to be sure from the commit message,
but I suspect the intention here was to reduce the number of indices
read in that particular situation, instead of allowing replacing
the number of real indices read direct from the table definition
with a larger number.

In any case, omitting a possible index definition which exists
is a safer approach then trying to read an index from non-index data.

Fixes #335
2021-08-29 16:22:34 +10:00
Nyall Dawson
dccc88b722 Fix incorrect conversion of double values
Fixes #339
2021-08-29 15:31:00 +10:00
Nyall Dawson
4c61f2d49b Handle sql queries where a double constant value has a trailing .
with no extra digits, e.g. "my_double_col" = 123.
2021-08-26 23:54:06 -04:00
Nyall Dawson
036f9b95c6 Handle sql queries where a double column is compared to an int
eg "my_double_column" = 123
2021-08-26 23:54:06 -04:00
Nyall Dawson
f4ca6b9e57 Handle sql queries where an integer column is compared to a double value
(e.g. "my_int_column" = 123.0)
2021-08-26 23:54:06 -04:00
Nyall Dawson
f557e6525b Better error output 2021-08-26 23:49:11 -04:00
Nyall Dawson
fa336fd325 Handle sql queries using REP_ID columns 2021-08-26 20:17:39 -04:00
Evan Miller
05cb0449db Version 0.9.4, final 2021-08-04 16:52:37 -04:00
38 changed files with 677 additions and 343 deletions

View File

@ -1,20 +1,25 @@
name: build
on: [ push, pull_request ]
env:
TEST_DATA_URL: https://github.com/mdbtools/mdbtestdata/archive/refs/heads/master.tar.gz
jobs:
linux:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
compiler: [ clang, gcc, gcc-9, gcc-10 ]
compiler: [ clang, gcc, gcc-11, gcc-12 ]
iconv: [ enable-iconv, disable-iconv]
glib: [ enable-glib, disable-glib ]
steps:
- name: Install packages
run: sudo apt install gettext
run: sudo apt install gettext unixodbc gcc-11 gcc-12
- uses: actions/checkout@v2
- name: Fetch test data
run: git clone https://github.com/mdbtools/mdbtestdata.git test
run: |
rm -rf test
mkdir test
curl -sSLf "$TEST_DATA_URL" | tar xz --strip-components=1 -C test
- name: Autoconf
run: autoreconf -i -f
- name: Configure
@ -24,7 +29,7 @@ jobs:
- name: Make
run: make
- name: CLI tests
run: bash -e -x ./test_script.sh
run: ./test_script.sh --github
- name: SQL tests
run: bash -e -x ./test_sql.sh
- name: ODBC tests
@ -49,21 +54,24 @@ jobs:
glib: [ enable-glib, disable-glib ]
steps:
- name: Install packages
run: brew install bison gawk automake
run: brew install bison gawk automake libtool unixodbc
- uses: actions/checkout@v2
- name: Fetch test data
run: git clone https://github.com/mdbtools/mdbtestdata.git test
run: |
rm -rf test
mkdir test
curl -sSLf "$TEST_DATA_URL" | tar xz --strip-components=1 -C test
- name: Autoconf
run: autoreconf -i -f
run: autoreconf -i -f -I $(brew --prefix)/share/gettext/m4
- name: Configure
run: ./configure --disable-silent-rules --${{ matrix.glib }} --${{ matrix.iconv }} --with-unixodbc=/usr/local/opt
run: ./configure --disable-silent-rules --${{ matrix.glib }} --${{ matrix.iconv }} --with-unixodbc=/opt/homebrew/opt/unixodbc
env:
CC: ${{ matrix.compiler }}
YACC: /usr/local/opt/bison/bin/bison
YACC: /opt/homebrew/opt/bison/bin/bison
- name: Make
run: make
- name: CLI tests
run: bash -e -x ./test_script.sh
run: ./test_script.sh --github
- name: SQL tests
run: bash -e -x ./test_sql.sh
- name: ODBC tests
@ -86,20 +94,23 @@ jobs:
compiler: [ clang, gcc ]
glib: [ enable-glib, disable-glib ]
steps:
- name: Remove packages
run: brew unlink unixodbc
- name: Install packages
run: brew install libiodbc bison gawk automake
run: brew install bison gawk automake libtool libiodbc
- name: Add path
run: echo /opt/homebrew/opt/libiodbc/bin >> $GITHUB_PATH
- uses: actions/checkout@v2
- name: Fetch test data
run: git clone https://github.com/mdbtools/mdbtestdata.git test
run: |
rm -rf test
mkdir test
curl -sSLf "$TEST_DATA_URL" | tar xz --strip-components=1 -C test
- name: Autoconf
run: autoreconf -i -f
run: autoreconf -i -f -I $(brew --prefix)/share/gettext/m4
- name: Configure
run: ./configure --disable-silent-rules --${{ matrix.glib }} --with-iodbc=/usr/local/opt
run: ./configure --disable-silent-rules --${{ matrix.glib }} --with-iodbc=/opt/homebrew/opt/libiodbc
env:
CC: ${{ matrix.compiler }}
YACC: /usr/local/opt/bison/bin/bison
YACC: /opt/homebrew/opt/bison/bin/bison
- name: Make
run: make
- name: ODBC tests
@ -108,19 +119,37 @@ jobs:
MDBPATH: test/data
windows:
runs-on: windows-latest
env:
MSYSTEM: MINGW64
strategy:
fail-fast: false
matrix:
iconv: [ enable-iconv, disable-iconv]
glib: [ enable-glib, disable-glib ]
defaults:
run:
shell: msys2 {0}
steps:
- uses: msys2/setup-msys2@v2
with:
update: true
install: >-
autotools
base-devel
gcc
git
glib2-devel
- uses: actions/checkout@v2
- name: Check out test data
run: git clone https://github.com/mdbtools/mdbtestdata.git test
- name: Fetch test data
run: |
rm -rf test
mkdir test
curl -sSLf "$TEST_DATA_URL" | tar xz --strip-components=1 -C test
- name: Autoconf
run: C:\msys64\usr\bin\bash -c -l 'cd "$GITHUB_WORKSPACE" && autoreconf -i -f'
run: autoreconf -i -f
- name: Configure
run: C:\msys64\usr\bin\bash -c -l 'cd "$GITHUB_WORKSPACE" && ./configure'
run: ./configure --${{ matrix.glib }} --${{ matrix.iconv }}
- name: Make
run: C:\msys64\usr\bin\bash -c -l 'cd "$GITHUB_WORKSPACE" && make'
run: make
- name: Test
run: C:\msys64\usr\bin\bash -c -l 'cd "$GITHUB_WORKSPACE" && bash -e -x ./test_script.sh'
run: ./test_script.sh --github
- name: SQL Test
run: C:\msys64\usr\bin\bash -c -l 'cd "$GITHUB_WORKSPACE" && bash -e -x ./test_sql.sh'
run: bash -e -x ./test_sql.sh

8
.gitignore vendored
View File

@ -17,6 +17,7 @@ m4/
config.log
config.status
configure
/configure~
Makefile.in
Makefile
doc/*.1
@ -26,6 +27,8 @@ include/mdbtools.h
libmdb.pc
libmdbsql.pc
libtool
mdbtools-*.tar.gz
mdbtools-*.zip
src/extras/mdb-hexdump
src/odbc/unittest
src/sql/lexer.c
@ -52,9 +55,10 @@ src/util/prkkd
src/util/prole
src/util/prtable
src/util/updrow
/test/
/.vscode/
## apidocs docs related
public/
.sass-cache/
*.css.map
temp-man-pages/

View File

@ -259,7 +259,7 @@ offset_start of memo = (int16*) LVAL_page[offset_num_rows + (row_id * 2) + 2]
if (row_id = 0)
offset_stop of memo = 2048(jet3) or 4096(jet4)
else
offset_stop of memo = (int16*) LVAL_page[offset_num_row + (row_id * 2)]
offset_stop of memo = (int16*) LVAL_page[offset_num_row + (row_id * 2)] & offset_mask // offset_mask = 0x1fff
```
The length (partial if type 2) for the memo is:

96
NEWS
View File

@ -1,68 +1,62 @@
Version 1.0.0 (Beta 4)
Version 1.0.0
=============
MDB Tools 1.0 includes a number of new features compared to the 0.9 series. The
most significant change is that mdbtools.h is now generated at build time, and
its internal HAVE_ macros have been removed. This means that it is now safe for
clients to compile against mdbtools.h without needing to provide the same
HAVE_ICONV and HAVE_GLIB flags that were present when the library was first
compiled. For most users, MDB Tools 1.0 will be ABI and API compatible with the
0.9 series but see the notes in the "Install" section below.
The SQL engine has two new operators: ILIKE (case-insensitive pattern matching)
and <> (not equals).
Changes since 0.9.4:
Build:
* Generate platform-specific `mdbtools.h` at configure-time #316
* Ensure compiler supports thread-local storage
* Fix `AC_PROG_LEX` warning with autoconf 2.70
* Rely on autoconf to define appropriate values of `_XOPEN_SOURCE` and friends
* New `--disable-iconv` configure option (falls back to `wcstombs` where possible)
* Fix a build error when `./configure` detected iconv, but thought it was not working
* Generating the configure script now requires autoconf 2.64 or later
ODBC:
* The Unicode driver (`libmdbodbcW.so`) no longer uses iconv #332 #333
SQL:
* New `<>` (not equal) operator #329
Version 1.0.0 (Beta 3)
=============
Build:
* Fix warning with autoconf 2.70
* Rely on autoconf to define appropriate values of `_XOPEN_SOURCE` and friends
* Simplify configure script
libmdb:
* Restore previous `MdbHandle` struct layout
* Simplify `pkg-config --cflags`
libmdbsql:
* Provide correct `pkg-config --cflags`
ODBC:
* Format boolean values correctly as SQL_C_CHAR #327
mdb-schema:
* Fix incorrect treatment of CREATE TABLE and DROP TABLE #328 (Bug introduced in Beta 2)
Version 1.0.0 (Beta 2)
=============
Build:
* Ensure compiler supports thread-local storage
libmdb:
* Copy date formats when cloning handles #326
* Restore previous `mdb_register_backend` API
* Restore previous `MdbBackend` struct layout
Version 1.0.0 (Beta 1)
=============
libmdb:
* Generate platform-specific `mdbtools.h` at configure-time #316
SQL:
* New case-insensitive, Unicode-aware `ILIKE` operator #244
Install:
* Install `libmdbodbc.so` and `libmdbodbcW.so` into ${libdir}/odbc #315
* Do not install `mdb-sql` if SQL support was not built #276
* Do not install `libmdbsql.pc` if SQL support was not built
ODBC:
* Install libmdbodbc.so and libmdbodbcW.so into ${libdir}/odbc #315
`pkg-config`:
* Simplify `--cflags` for libmdb
* Provide correct `--cflags` for libmdbsql
mdb-export:
libmdb:
* Copy date formats when cloning handles #326
* Fix incorrect reading of double values #339 #342
* Fix accidental reads of non-index data #335 #343
* New `mdb_set_repid_fmt()` for setting the format of Rep IDs (UUIDs) #344
SQL:
* New case-insensitive, Unicode-aware `ILIKE` operator #244
* New `<>` (not equal) operator #329
* Improved support for comparing floating-point values to integers
* Improved support for floating point literals with no fractional digits (e.g. "3.")
* Add support for querying Rep IDs
ODBC:
* Format boolean values correctly as `SQL_C_CHAR` #327
* Add support for the `SQL_C_WCHAR` (UTF-16) return type #347 #348
* The Unicode driver (`libmdbodbcW.so`) no longer uses iconv #332 #333
* Add support for older iODBC installations lacking `odbcinst.h`
`mdb-export`:
* Convert table names to lower case when exporting to PostgreSQL #322
* Use `CREATE IF NOT EXISTS` when exporting to PostgreSQL #321
* Fix issue where byte columns with values > 127 were exported as negative numbers (regression introduced in v0.9.3-beta1) #350
mdb-hexdump:
`mdb-hexdump`:
* Deprecate tool
Version 0.9.4

View File

@ -116,19 +116,26 @@ If you have cloned the Git repository, you will first need to generate the
`configure` file (skip this step if you have downloaded a formal release):
```bash
$ autoreconf -i -f
autoreconf -i -f
```
Then:
```bash
$ ./configure
./configure
```
OR with mingw32 (--disable-shared --enable-static are optional as you knew):
```bash
./configure --host=x86_64-w64-mingw32 --disable-shared --enable-static
```
OR for a complete install (requires bison, flex, and unixODBC):
```bash
$ ./configure --with-unixodbc=/usr/local
./configure --with-unixodbc=/usr/local
```
By default, MDB Tools is linked against the copy of
@ -152,11 +159,10 @@ mutually exclusive.
By default, the ODBC driver will be installed as /usr/local/lib/odbc/libmdbodbc.so,
with a Unicode-capable driver at /usr/local/lib/odbc/libmdbodbcW.so.
A list of general options is available in the [INSTALL](./INSTALL) file, and
`configure --help` will give you the list of mdbtools specific options.
The command `configure --help` will give you the list of mdbtools specific options.
```bash
$ make
make
```
Once MDB Tools has been compiled, libmdb.[so|a] will be in the src/libmdb
@ -165,14 +171,14 @@ directory and the utility programs will be in the src/util directory.
You can then install (to /usr/local by default) by running the following as root:
```bash
$ make install
make install
```
Some systems will also need the ld cache to be updated after installation;
You can do that running:
```bash
$ ldconfig
ldconfig
```
## Hacking

32
TODO.md
View File

@ -1,34 +1,4 @@
TODO
----
### file format:
- export VBA script
- re-examine KKD records for form design (OLE streams?)
- write support (understood, not coded)
### libmdb:
- Complete the list of datatypes
- Straighten out which functions in libmdb are meant to be used and which
ones should be static.
- Create an API reference for libmdb (maybe some man pages).
- Sargs need to support all datatypes
- Add support for index scanning when using sargs (partial)
- write support
### utils:
- need program to unpack VBA script to file (see prole)
- Access forms to glade converter ?
- need --version flag (done using -M flag on mdb-ver)
### SQL Engine:
- Joins
- insert/updates
- bogus column name in where clause not caught
### ODBC:
- many unimplemented funtions
See the list of [open issues tagged "enhancement"](https://github.com/mdbtools/mdbtools/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement).

File diff suppressed because one or more lines are too long

View File

@ -17,8 +17,10 @@ clone_folder: c:\projects\mdbtools
skip_tags: true
# Installing packages leads to the error:
# Can't locate threads.pm in @INC (you may need to install the threads module)
# So disable the SQL tests on this platform for now
build_script:
- C:\cygwin64\setup-x86_64.exe -q -P bison -P flex -P libiconv-devel
- C:\cygwin64\bin\sh -lc "cd /cygdrive/c/projects/mdbtools && git clone https://github.com/mdbtools/mdbtestdata.git test"
- C:\cygwin64\bin\sh -lc "cd /cygdrive/c/projects/mdbtools && autoreconf -i -f"
- C:\cygwin64\bin\sh -lc "cd /cygdrive/c/projects/mdbtools && ./configure --disable-man --disable-silent-rules"
@ -26,4 +28,3 @@ build_script:
test_script:
- C:\cygwin64\bin\sh -lc "cd /cygdrive/c/projects/mdbtools && ./test_script.sh"
- C:\cygwin64\bin\sh -lc "cd /cygdrive/c/projects/mdbtools && ./test_sql.sh"

View File

@ -1,5 +1,5 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT([mdbtools],[1.0.0-beta4],[https://github.com/mdbtools/mdbtools/issues],[],[https://github.com/mdbtools/mdbtools])
AC_INIT([mdbtools],[1.0.1],[https://github.com/mdbtools/mdbtools/issues],[],[https://github.com/mdbtools/mdbtools])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_SRCDIR(src/extras/mdb-dump.c)
@ -7,11 +7,11 @@ AM_INIT_AUTOMAKE([foreign dist-zip])
MDBTOOLS_VERSION_MAJOR=1
MDBTOOLS_VERSION_MINOR=0
MDBTOOLS_VERSION_MICRO=0
MDBTOOLS_VERSION_MICRO=1
# Update these numbers with every release
# See https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
VERSION_INFO=4:0:1
VERSION_INFO=4:1:1
AC_SUBST(VERSION_INFO)
AM_MAINTAINER_MODE([enable])
@ -83,10 +83,10 @@ AM_CONDITIONAL(SQL, test x$sql = xtrue)
AC_SUBST(SQL)
AC_SUBST(LFLAGS)
CFLAGS="$CFLAGS -Wall -Werror"
CFLAGS="$CFLAGS -Wall"
LOCALE_T=locale_t
AS_CASE([$host],
[*mingw*|*cygwin*], [LDFLAGS="$LDFLAGS -no-undefined" LOCALE_T=_locale_t], [])
[*mingw*], [LDFLAGS="$LDFLAGS -no-undefined" CFLAGS="$CFLAGS -D_spawnv=_spawnv"], [])
AC_SUBST(LOCALE_T)
dnl See if iconv is present and wanted
@ -153,7 +153,6 @@ if test "$with_iodbc"; then
ODBC_CFLAGS=$(iodbc-config --prefix="$with_iodbc" --cflags)
ODBC_LIBS=$(iodbc-config --prefix="$with_iodbc" --libs)
ODBC_LDFLAGS=""
CFLAGS="$CFLAGS -DIODBC"
OLDLDFLAGS=$LDFLAGS
LDFLAGS="$LDFLAGS $ODBC_LIBS"
@ -168,8 +167,7 @@ AC_ARG_WITH(unixodbc,
if test "$with_unixodbc"; then
HAVE_ODBC=true
ODBC_CFLAGS="-I$with_unixodbc/include"
ODBC_LIBS="-L$with_unixodbc/$libdir"
CFLAGS="$CFLAGS -DUNIXODBC"
ODBC_LIBS="-L$with_unixodbc/lib"
dnl SIZEOF_LONG_INT and HAVE_LONG_LONG are required by some versions of unixODBC
dnl https://github.com/lurcher/unixODBC/issues/40
@ -192,12 +190,18 @@ if test "$with_unixodbc"; then
ODBC_LDFLAGS=""])
LDFLAGS=$OLDLDFLAGS
fi
AM_CONDITIONAL([UNIXODBC], test "$with_unixodbc")
if test "x$HAVE_ODBC" = "xtrue"; then
if test "x$sql" != "xtrue" ; then
AC_MSG_ERROR([ODBC requires flex and bison for the SQL engine])
fi
OLDCFLAGS=$CFLAGS
CFLAGS="$CFLAGS $ODBC_CFLAGS"
AC_CHECK_HEADERS(odbcinst.h iodbcinst.h)
CFLAGS=$OLDCFLAGS
AC_SUBST(ODBC_CFLAGS)
AC_SUBST(ODBC_LIBS)
AC_SUBST(ODBC_LDFLAGS)
@ -222,10 +226,9 @@ AC_ARG_ENABLE(glib,
if test "$enable_glib" = "yes"; then
GLIB_PACKAGE=glib-2.0
PKG_CHECK_MODULES([GLIB], [$GLIB_PACKAGE], HAVE_GLIB=true, HAVE_GLIB=false)
PKG_CHECK_MODULES([GLIB], [$GLIB_PACKAGE >= 2.68], HAVE_GLIB=true, HAVE_GLIB=false)
if test "x$HAVE_GLIB" = "xtrue"; then
GLIB_CFLAGS="$GLIB_CFLAGS -DHAVE_GLIB=1"
AC_CHECK_LIB($GLIB_PACKAGE, g_memdup2, [GLIB_CFLAGS="$GLIB_CFLAGS -DHAVE_G_MEMDUP2=1"])
AC_SUBST(GLIB_PACKAGE)
else
enable_glib=no

View File

@ -1,5 +1,5 @@
SHELL = /bin/sh
TXT2MAN = ./txt2man
TXT2MAN = $(srcdir)/txt2man
PRODUCT = MDBTools
dist_man_MANS =

View File

@ -9,7 +9,7 @@ SYNOPSIS
DESCRIPTION
mdb-json is a utility program distributed with MDB Tools.
It produces a CSV (comma separated value) output for the given table. Such output is suitable for importation into databases or spreadsheets.
It produces JSON output for the given table. Such output is suitable for parsing in a variety of languages.
OPTIONS
-D, --date-format fmt Set the date format (see strftime(3) for details).

View File

@ -117,6 +117,7 @@ typedef struct GOptionContext {
#define g_malloc malloc
#define g_free free
#define g_realloc realloc
#define g_memdup2 g_memdup
#define G_STR_DELIMITERS "_-|> <."

View File

@ -26,10 +26,6 @@
* used within mdbtools so they won't be exported to calling programs.
*/
#ifndef HAVE_G_MEMDUP2
#define g_memdup2 g_memdup
#endif
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -21,9 +21,6 @@
#define MDBTOOLS_H_HAVE_ICONV_H @HAVE_ICONV_H@
#define MDBTOOLS_H_HAVE_XLOCALE_H @HAVE_XLOCALE_H@
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
@ -48,6 +45,10 @@
#include <io.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
/** \addtogroup mdbtools
* @{
*/
@ -67,6 +68,13 @@
// M$VC see http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc
#define MDB_DEPRECATED(type, funcname) type __attribute__((deprecated)) funcname
#ifdef __MINGW32__
#include <stdlib.h>
#ifndef locale_t
typedef _locale_t locale_t;
#endif
#endif
typedef @LOCALE_T@ mdb_locale_t;
enum {
@ -158,6 +166,11 @@ enum {
MDB_NO_MEMO = 0x0080, /* don't follow memo fields */
};
typedef enum {
MDB_BRACES_4_2_2_8, /* "{XXXX-XX-XX-XXXXXXXX}" format */
MDB_NOBRACES_4_2_2_2_6, /* "XXXX-XX-XX-XX-XXXXXX" format (matches MS Access ODBC driver) */
} MdbUuidFormat;
#define mdb_is_logical_op(x) (x == MDB_OR || \
x == MDB_AND || \
x == MDB_NOT )
@ -300,6 +313,7 @@ typedef struct {
size_t bind_size;
char date_fmt[64];
char shortdate_fmt[64];
MdbUuidFormat repid_fmt;
const char *boolean_false_value;
const char *boolean_true_value;
unsigned int num_catalog;
@ -530,7 +544,8 @@ int mdb_bind_column_by_name(MdbTableDef *table, gchar *col_name, void *bind_ptr,
void mdb_data_dump(MdbTableDef *table);
void mdb_date_to_tm(double td, struct tm *t);
void mdb_tm_to_date(struct tm *t, double *td);
char *mdb_uuid_to_string(const void *buf, int start);
char *mdb_uuid_to_string(const void *buf, int start); /* Uses default MDB_BRACES_4_2_2_8 format */
char *mdb_uuid_to_string_fmt(const void *buf, int start, MdbUuidFormat format);
int mdb_bind_column(MdbTableDef *table, int col_num, void *bind_ptr, int *len_ptr);
int mdb_rewind_table(MdbTableDef *table);
int mdb_fetch_row(MdbTableDef *table);
@ -547,6 +562,7 @@ void* mdb_ole_read_full(MdbHandle *mdb, MdbColumn *col, size_t *size);
void mdb_set_bind_size(MdbHandle *mdb, size_t bind_size);
void mdb_set_date_fmt(MdbHandle *mdb, const char *);
void mdb_set_shortdate_fmt(MdbHandle *mdb, const char *);
void mdb_set_repid_fmt(MdbHandle *mdb, MdbUuidFormat format);
void mdb_set_boolean_fmt_words(MdbHandle *mdb);
void mdb_set_boolean_fmt_numbers(MdbHandle *mdb);
int mdb_read_row(MdbTableDef *table, unsigned int row);

View File

@ -111,7 +111,7 @@ static const MdbBackendType mdb_mysql_types[] = {
[MDB_LONGINT] = { .name = "int" },
[MDB_MONEY] = { .name = "float" },
[MDB_FLOAT] = { .name = "float" },
[MDB_DOUBLE] = { .name = "float" },
[MDB_DOUBLE] = { .name = "double" },
[MDB_DATETIME] = { .name = "datetime" },
[MDB_BINARY] = { .name = "blob" },
[MDB_TEXT] = { .name = "varchar", .needs_char_length = 1 },
@ -294,7 +294,7 @@ mdb_get_colbacktype_string(const MdbColumn *col)
const MdbBackendType *type = mdb_get_colbacktype(col);
if (!type) {
// return NULL;
static __thread char buf[16];
static TLS char buf[16];
snprintf(buf, sizeof(buf), "Unknown_%04x", col->col_type);
return buf;
}
@ -401,7 +401,7 @@ void mdb_init_backends(MdbHandle *mdb)
"COMMENT %s",
quote_schema_name_rquotes_merge);
mdb_register_backend(mdb, "sqlite",
MDB_SHEXP_DROPTABLE|MDB_SHEXP_DEFVALUES|MDB_SHEXP_BULK_INSERT,
MDB_SHEXP_DROPTABLE|MDB_SHEXP_DEFVALUES|MDB_SHEXP_BULK_INSERT|MDB_SHEXP_INDEXES|MDB_SHEXP_CST_NOTNULL,
mdb_sqlite_types, NULL, NULL,
"date('now')", "date('now')",
"%Y-%m-%d %H:%M:%S",
@ -571,7 +571,47 @@ mdb_get_index_name(int backend, MdbTableDef *table, MdbIndex *idx)
return index_name;
}
/**
* mdb_print_pk - print primary key constraint
* @output: Where to print the sql
* @table: Table to process
*/
static void
mdb_print_pk_if_sqlite(FILE *outfile, MdbTableDef *table)
{
unsigned int i, j;
MdbHandle *mdb = table->entry->mdb;
MdbIndex *idx;
MdbColumn *col;
char *quoted_name;
// this is only necessary for sqlite
if (strcmp(mdb->backend_name, "sqlite") != 0)
return;
if (table->indices==NULL)
mdb_read_indices(table);
for (i = 0; i < table->num_idxs; i++) {
idx = g_ptr_array_index(table->indices, i);
if (idx->index_type == 1) {
fprintf(outfile, "\t, PRIMARY KEY (");
for (j = 0; j < idx->num_keys; j++) {
if (j)
fprintf(outfile, ", ");
col = g_ptr_array_index(table->columns, idx->key_col_num[j] - 1);
quoted_name = mdb->default_backend->quote_schema_name(NULL, col->name);
quoted_name = mdb_normalise_and_replace(mdb, &quoted_name);
fprintf(outfile, "%s", quoted_name);
if (idx->index_type != 1 && idx->key_col_order[j])
/* no DESC for primary keys */
fprintf(outfile, " DESC");
g_free(quoted_name);
}
fprintf(outfile, ")\n");
}
}
}
/**
* mdb_print_indexes
* @output: Where to print the sql
@ -596,13 +636,16 @@ mdb_print_indexes(FILE* outfile, MdbTableDef *table, char *dbnamespace)
backend = MDB_BACKEND_MYSQL;
} else if (!strcmp(mdb->backend_name, "oracle")) {
backend = MDB_BACKEND_ORACLE;
} else if (!strcmp(mdb->backend_name, "sqlite")) {
backend = MDB_BACKEND_SQLITE;
} else {
fprintf(outfile, "-- Indexes are not implemented for %s\n\n", mdb->backend_name);
return;
}
/* read indexes */
mdb_read_indices(table);
if (table->indices==NULL)
mdb_read_indices(table);
fprintf (outfile, "-- CREATE INDEXES ...\n");
@ -613,6 +656,9 @@ mdb_print_indexes(FILE* outfile, MdbTableDef *table, char *dbnamespace)
idx = g_ptr_array_index (table->indices, i);
if (idx->index_type==2)
continue;
/* Sqlite3 primary keys have to be issued as a table constraint */
if (idx->index_type == 1 && backend == MDB_BACKEND_SQLITE)
continue;
index_name = mdb_get_index_name(backend, table, idx);
switch (backend) {
@ -630,7 +676,10 @@ mdb_print_indexes(FILE* outfile, MdbTableDef *table, char *dbnamespace)
}
quoted_name = mdb_normalise_and_replace(mdb, &quoted_name);
if (idx->num_keys == 0) {
fprintf(outfile, "-- WARNING: found no keys for index %s - ignored\n", quoted_name);
continue;
}
if (idx->index_type==1) {
switch (backend) {
case MDB_BACKEND_ORACLE:
@ -645,6 +694,7 @@ mdb_print_indexes(FILE* outfile, MdbTableDef *table, char *dbnamespace)
switch (backend) {
case MDB_BACKEND_ORACLE:
case MDB_BACKEND_POSTGRES:
case MDB_BACKEND_SQLITE:
fprintf(outfile, "CREATE");
if (idx->flags & MDB_IDX_UNIQUE)
fprintf (outfile, " UNIQUE");
@ -872,6 +922,10 @@ generate_table_schema(FILE *outfile, MdbCatalogEntry *entry, char *dbnamespace,
fprintf (outfile, " (\n");
table = mdb_read_table (entry);
if (!table) {
fprintf(stderr, "Error: Table %s does not exist\n", entry->object_name);
return;
}
/* get the columns */
mdb_read_columns(table);
@ -964,6 +1018,11 @@ generate_table_schema(FILE *outfile, MdbCatalogEntry *entry, char *dbnamespace,
fputs("\n", outfile);
} /* for */
if (export_options & MDB_SHEXP_INDEXES) {
// sqlite does not support ALTER TABLE PRIMARY KEY, so we need to place it directly into CREATE TABLE
mdb_print_pk_if_sqlite(outfile, table);
}
fputs(")", outfile);
if (mdb->default_backend->per_table_comment_statement && export_options & MDB_SHEXP_COMMENTS) {
prop_value = mdb_table_get_prop(table, "Description");

View File

@ -193,7 +193,7 @@ mdb_dump_catalog(MdbHandle *mdb, int obj_type)
entry = g_ptr_array_index(mdb->catalog,i);
if (obj_type==MDB_ANY || entry->object_type==obj_type) {
printf("Type: %-12s Name: %-48s Page: %06lx\n",
mdb_get_objtype_string(entry->object_type),
mdb_get_objtype_string(entry->object_type) ?: "Unknown",
entry->object_name,
entry->table_pg);
}

View File

@ -68,6 +68,11 @@ void mdb_set_shortdate_fmt(MdbHandle *mdb, const char *fmt)
snprintf(mdb->shortdate_fmt, sizeof(mdb->shortdate_fmt), "%s", fmt);
}
void mdb_set_repid_fmt(MdbHandle *mdb, MdbUuidFormat format)
{
mdb->repid_fmt = format;
}
void mdb_set_boolean_fmt_numbers(MdbHandle *mdb)
{
mdb->boolean_false_value = boolean_false_number;
@ -946,15 +951,20 @@ mdb_date_to_string(MdbHandle *mdb, const char *fmt, void *buf, int start)
}
char *mdb_uuid_to_string(const void *buf, int pos)
{
return mdb_uuid_to_string_fmt(buf,pos,MDB_BRACES_4_2_2_8);
}
char *mdb_uuid_to_string_fmt(const void *buf, int pos, MdbUuidFormat format)
{
const unsigned char *kkd = (const unsigned char *)buf;
return g_strdup_printf("{%02X%02X%02X%02X" "-" "%02X%02X" "-" "%02X%02X"
"-" "%02X%02X" "%02X%02X%02X%02X%02X%02X}",
return g_strdup_printf(format == MDB_BRACES_4_2_2_8
? "{%02X%02X%02X%02X" "-" "%02X%02X" "-" "%02X%02X" "-" "%02X%02X%02X%02X%02X%02X%02X%02X}"
: "%02X%02X%02X%02X" "-" "%02X%02X" "-" "%02X%02X" "-" "%02X%02X" "-" "%02X%02X%02X%02X%02X%02X",
kkd[pos+3], kkd[pos+2], kkd[pos+1], kkd[pos], // little-endian
kkd[pos+5], kkd[pos+4], // little-endian
kkd[pos+7], kkd[pos+6], // little-endian
kkd[pos+8], kkd[pos+9], // big-endian
kkd[pos+10], kkd[pos+11],
kkd[pos+12], kkd[pos+13],
kkd[pos+14], kkd[pos+15]); // big-endian
@ -999,7 +1009,7 @@ char *mdb_col_to_string(MdbHandle *mdb, void *buf, int start, int datatype, int
switch (datatype) {
case MDB_BYTE:
text = g_strdup_printf("%hhd", mdb_get_byte(buf, start));
text = g_strdup_printf("%hhu", mdb_get_byte(buf, start));
break;
case MDB_INT:
text = g_strdup_printf("%hd",
@ -1046,7 +1056,7 @@ char *mdb_col_to_string(MdbHandle *mdb, void *buf, int start, int datatype, int
text = mdb_money_to_string(mdb, start);
break;
case MDB_REPID:
text = mdb_uuid_to_string(buf, start);
text = mdb_uuid_to_string_fmt(buf, start, mdb->repid_fmt);
break;
default:
/* shouldn't happen. bools are handled specially

View File

@ -255,7 +255,8 @@ gchar *g_locale_to_utf8(const gchar *opsysstring, size_t len,
mbstowcs(utf16, opsysstring, wlen+1);
gchar *utf8 = malloc(3*len+1);
gchar *dst = utf8;
for (size_t i=0; i<len; i++) {
size_t i;
for (i=0; i<len; i++) {
// u >= 0x10000 requires surrogate pairs, ignore
dst += g_unichar_to_utf8(utf16[i], dst);
}
@ -332,7 +333,8 @@ void g_hash_table_insert(GHashTable *table, void *key, void *value) {
gboolean g_hash_table_remove(GHashTable *table, gconstpointer key) {
int found = 0;
for (guint i=0; i<table->array->len; i++) {
guint i;
for (i=0; i<table->array->len; i++) {
MyNode *node = g_ptr_array_index(table->array, i);
if (found) {
table->array->pdata[i-1] = table->array->pdata[i];
@ -398,7 +400,8 @@ void g_ptr_array_add(GPtrArray *array, void *entry) {
gboolean g_ptr_array_remove(GPtrArray *array, gpointer data) {
int found = 0;
for (guint i=0; i<array->len; i++) {
guint i;
for (i=0; i<array->len; i++) {
if (found) {
array->pdata[i-1] = array->pdata[i];
} else if (!found && array->pdata[i] == data) {

View File

@ -130,6 +130,7 @@ static MdbHandle *mdb_handle_from_stream(FILE *stream, MdbFileFlags flags) {
mdb_set_shortdate_fmt(mdb, "%x");
mdb_set_bind_size(mdb, MDB_BIND_SIZE);
mdb_set_boolean_fmt_numbers(mdb);
mdb_set_repid_fmt(mdb, MDB_BRACES_4_2_2_8);
#ifdef HAVE_ICONV
mdb->iconv_in = (iconv_t)-1;
mdb->iconv_out = (iconv_t)-1;
@ -315,10 +316,11 @@ MdbHandle *mdb_clone_handle(MdbHandle *mdb)
mdb_iconv_init(newmdb);
mdb_set_default_backend(newmdb, mdb->backend_name);
// date formats for the source handle may have been changed from
// formats for the source handle may have been changed from
// the backend's default formats, so we need to explicitly copy them here
mdb_set_date_fmt(newmdb, mdb->date_fmt);
mdb_set_shortdate_fmt(newmdb, mdb->shortdate_fmt);
mdb_set_repid_fmt(newmdb, mdb->repid_fmt);
if (mdb->f) {
mdb->f->refs++;
@ -379,7 +381,7 @@ static ssize_t _mdb_read_pg(MdbHandle *mdb, void *pg_buf, unsigned long pg)
*/
if (pg != 0 && mdb->f->db_key != 0)
{
guint32 tmp_key_i = mdb->f->db_key ^ pg;
uint32_t tmp_key_i = mdb->f->db_key ^ pg;
unsigned char tmp_key[4] = {
tmp_key_i & 0xFF, (tmp_key_i >> 8) & 0xFF,
(tmp_key_i >> 16) & 0xFF, (tmp_key_i >> 24) & 0xFF };
@ -412,7 +414,7 @@ unsigned char mdb_pg_get_byte(MdbHandle *mdb, int offset)
int mdb_get_int16(void *buf, int offset)
{
unsigned char *u8_buf = (unsigned char *)buf + offset;
return u8_buf[0] + (u8_buf[1] << 8);
return ((uint32_t)u8_buf[0] << 0) + ((uint32_t)u8_buf[1] << 8);
}
int mdb_pg_get_int16(MdbHandle *mdb, int offset)
{
@ -424,12 +426,20 @@ int mdb_pg_get_int16(MdbHandle *mdb, int offset)
long mdb_get_int32_msb(void *buf, int offset)
{
unsigned char *u8_buf = (unsigned char *)buf + offset;
return (u8_buf[0] << 24) + (u8_buf[1] << 16) + (u8_buf[2] << 8) + u8_buf[3];
return
((uint32_t)u8_buf[0] << 24) +
((uint32_t)u8_buf[1] << 16) +
((uint32_t)u8_buf[2] << 8) +
((uint32_t)u8_buf[3] << 0);
}
long mdb_get_int32(void *buf, int offset)
{
unsigned char *u8_buf = (unsigned char *)buf + offset;
return u8_buf[0] + (u8_buf[1] << 8) + (u8_buf[2] << 16) + (u8_buf[3] << 24);
return
((uint32_t)u8_buf[0] << 0) +
((uint32_t)u8_buf[1] << 8) +
((uint32_t)u8_buf[2] << 16) +
((uint32_t)u8_buf[3] << 24);
}
long mdb_pg_get_int32(MdbHandle *mdb, int offset)
{
@ -440,9 +450,12 @@ long mdb_pg_get_int32(MdbHandle *mdb, int offset)
float mdb_get_single(void *buf, int offset)
{
union {guint32 g; float f;} f;
union {uint32_t g; float f;} f;
unsigned char *u8_buf = (unsigned char *)buf + offset;
f.g = u8_buf[0] + (u8_buf[1] << 8) + (u8_buf[2] << 16) + (u8_buf[3] << 24);
f.g = ((uint32_t)u8_buf[0] << 0) +
((uint32_t)u8_buf[1] << 8) +
((uint32_t)u8_buf[2] << 16) +
((uint32_t)u8_buf[3] << 24);
return f.f;
}
float mdb_pg_get_single(MdbHandle *mdb, int offset)
@ -454,13 +467,19 @@ float mdb_pg_get_single(MdbHandle *mdb, int offset)
double mdb_get_double(void *buf, int offset)
{
union {guint64 g; double d;} d;
union {uint64_t g; double d;} d;
unsigned char *u8_buf = (unsigned char *)buf + offset;
d.g = u8_buf[0] + (u8_buf[1] << 8) + (u8_buf[2] << 16) + (u8_buf[3] << 24) +
((guint64)u8_buf[4] << 32) + ((guint64)u8_buf[5] << 40) +
((guint64)u8_buf[6] << 48) + ((guint64)u8_buf[7] << 56);
d.g = ((uint64_t)u8_buf[0] << 0) +
((uint64_t)u8_buf[1] << 8) +
((uint64_t)u8_buf[2] << 16) +
((uint64_t)u8_buf[3] << 24) +
((uint64_t)u8_buf[4] << 32) +
((uint64_t)u8_buf[5] << 40) +
((uint64_t)u8_buf[6] << 48) +
((uint64_t)u8_buf[7] << 56);
return d.d;
}
double mdb_pg_get_double(MdbHandle *mdb, int offset)
{
if (offset <0 || offset+8 > mdb->fmt->pg_size) return -1;
@ -468,7 +487,6 @@ double mdb_pg_get_double(MdbHandle *mdb, int offset)
return mdb_get_double(mdb->pg_buf, offset);
}
int
mdb_set_pos(MdbHandle *mdb, int pos)
{

View File

@ -275,6 +275,8 @@ static const char *mdb_iconv_name_from_code_page(int code_page) {
case 860: jet3_iconv_code="IBM860"; break;
case 861: jet3_iconv_code="IBM861"; break;
case 862: jet3_iconv_code="IBM862"; break;
case 863: jet3_iconv_code="IBM863"; break;
case 864: jet3_iconv_code="IBM864"; break;
case 865: jet3_iconv_code="IBM865"; break;
case 866: jet3_iconv_code="IBM866"; break;
case 869: jet3_iconv_code="IBM869"; break;

View File

@ -236,7 +236,7 @@ mdb_read_indices(MdbTableDef *table)
*/
//fprintf(stderr, "num_idxs:%d num_real_idxs:%d\n", table->num_idxs, table->num_real_idxs);
table->num_real_idxs = 0;
unsigned int num_idxs_type_other_than_2 = 0;
tmpbuf = g_malloc(idx2_sz);
for (i=0;i<table->num_idxs;i++) {
if (!read_pg_if_n(mdb, tmpbuf, &cur_pos, idx2_sz)) {
@ -264,8 +264,11 @@ mdb_read_indices(MdbTableDef *table)
fprintf(stderr, "idx #%d: %d %d %d %d %d/%d\n", i, idx_marker, rel_idx_type, rel_idx_number, rel_idx_page, update_action_flags, delete_action_flags);
}*/
if (pidx->index_type!=2)
table->num_real_idxs++;
num_idxs_type_other_than_2++;
}
if (num_idxs_type_other_than_2<table->num_real_idxs)
table->num_real_idxs=num_idxs_type_other_than_2;
//fprintf(stderr, "num_idxs:%d num_real_idxs:%d\n", table->num_idxs, table->num_real_idxs);
g_free(tmpbuf);

View File

@ -24,8 +24,8 @@
#define DEBUG 1
static __thread unsigned long opts;
static __thread int optset;
static TLS unsigned long opts;
static TLS int optset;
static void load_options(void);

View File

@ -78,25 +78,26 @@ int rc;
}
int mdb_test_int(MdbSargNode *node, gint32 i)
{
gint32 val = node->val_type == MDB_INT ? node->value.i : node->value.d;
switch (node->op) {
case MDB_EQUAL:
//fprintf(stderr, "comparing %ld and %ld\n", i, node->value.i);
if (node->value.i == i) return 1;
if (val == i) return 1;
break;
case MDB_GT:
if (node->value.i < i) return 1;
if (val < i) return 1;
break;
case MDB_LT:
if (node->value.i > i) return 1;
if (val > i) return 1;
break;
case MDB_GTEQ:
if (node->value.i <= i) return 1;
if (val <= i) return 1;
break;
case MDB_LTEQ:
if (node->value.i >= i) return 1;
if (val >= i) return 1;
break;
case MDB_NEQ:
if (node->value.i != i) return 1;
if (val != i) return 1;
break;
default:
fprintf(stderr, "Calling mdb_test_sarg on unknown operator. Add code to mdb_test_int() for operator %d\n",node->op);
@ -244,16 +245,17 @@ mdb_test_sarg(MdbHandle *mdb, MdbColumn *col, MdbSargNode *node, MdbField *field
ret = mdb_test_int(node, (gint32)mdb_get_int32(field->value, 0));
break;
case MDB_FLOAT:
ret = mdb_test_double(node->op, node->value.d, mdb_get_single(field->value, 0));
ret = mdb_test_double(node->op, node->val_type == MDB_INT ? node->value.i : node->value.d, mdb_get_single(field->value, 0));
break;
case MDB_DOUBLE:
ret = mdb_test_double(node->op, node->value.d, mdb_get_double(field->value, 0));
ret = mdb_test_double(node->op, node->val_type == MDB_INT ? node->value.i : node->value.d, mdb_get_double(field->value, 0));
break;
case MDB_TEXT:
mdb_unicode2ascii(mdb, field->value, field->siz, tmpbuf, sizeof(tmpbuf));
ret = mdb_test_string(node, tmpbuf);
break;
case MDB_MEMO:
case MDB_REPID:
val = mdb_col_to_string(mdb, mdb->pg_buf, field->start, col->col_type, (gint32)mdb_get_int32(field->value, 0));
//printf("%s\n",val);
ret = mdb_test_string(node, val);

View File

@ -92,6 +92,12 @@ MdbTableDef *mdb_read_table(MdbCatalogEntry *entry)
mdb_free_tabledef(table);
return NULL;
}
/* First byte of usage_map is the map-type and must always be present */
if (table->map_sz < 1) {
fprintf(stderr, "mdb_read_table: invalid map-size: %zu\n", table->map_sz);
mdb_free_tabledef(table);
return NULL;
}
table->usage_map = g_memdup2((char*)buf + row_start, table->map_sz);
if (mdb_get_option(MDB_DEBUG_USAGE))
mdb_buffer_dump(buf, row_start, table->map_sz);
@ -355,6 +361,9 @@ unsigned int i, bitn;
guint32 pgnum;
table = mdb_read_table(entry);
if (!table)
return;
fprintf(stdout,"definition page = %lu\n",entry->table_pg);
fprintf(stdout,"number of datarows = %d\n",table->num_rows);
fprintf(stdout,"number of columns = %d\n",table->num_cols);

View File

@ -5,6 +5,9 @@ lib_LTLIBRARIES = libmdbodbc.la
libdir=@libdir@/odbc
AM_CFLAGS = -I$(top_srcdir)/include $(GLIB_CFLAGS) $(ODBC_CFLAGS)
libmdbodbc_la_SOURCES = odbc.c connectparams.c
if UNIXODBC
libmdbodbc_la_SOURCES += getproperties.c
endif
libmdbodbc_la_LIBADD = ../libmdb/libmdb.la ../sql/libmdbsql.la $(ODBC_LIBS)
libmdbodbc_la_LDFLAGS = -avoid-version -export-symbols-regex '^(SQL|ODBCINST)' $(ODBC_LDFLAGS)
lib_LTLIBRARIES += libmdbodbcW.la

View File

@ -23,11 +23,11 @@
#include <string.h>
#include <sys/stat.h>
#include <ctype.h>
#ifdef UNIXODBC
#include <odbcinstext.h>
#else
#if defined(HAVE_ODBCINST_H)
#include <odbcinst.h>
#endif
#elif defined(HAVE_IODBCINST_H)
#include <iodbcinst.h>
#endif /* HAVE_ODBCINST_H */
#include "connectparams.h"
@ -93,7 +93,7 @@ void FreeConnectParams (ConnectParams* params)
gchar* GetConnectParam (ConnectParams* params, const gchar* paramName)
{
static __thread char tmp[FILENAME_MAX];
static TLS char tmp[FILENAME_MAX];
/* use old servername */
tmp[0] = '\0';
@ -213,7 +213,7 @@ gchar* ExtractDSN (ConnectParams* params, const gchar* connectString)
/*
* Position ourselves to the beginning of "DSN"
*/
p = strstr (connectString, "DSN");
p = strcasestr (connectString, "DSN");
if (!p) return NULL;
/*
* Position ourselves to the "="
@ -243,9 +243,9 @@ gchar* ExtractDBQ (ConnectParams* params, const gchar* connectString)
if (!params)
return NULL;
/*
* Position ourselves to the beginning of "DSN"
* Position ourselves to the beginning of "DBQ"
*/
p = strstr (connectString, "DBQ");
p = strcasestr (connectString, "DBQ");
if (!p) return NULL;
/*
* Position ourselves to the "="
@ -297,24 +297,4 @@ static void cleanup (gpointer key, gpointer value, gpointer user_data)
g_free (value);
}
#ifdef UNIXODBC
int
ODBCINSTGetProperties(HODBCINSTPROPERTY hLastProperty)
{
hLastProperty->pNext = malloc(sizeof(ODBCINSTPROPERTY));
hLastProperty = hLastProperty->pNext;
memset(hLastProperty, 0, sizeof(ODBCINSTPROPERTY));
hLastProperty->nPromptType = ODBCINST_PROMPTTYPE_FILENAME;
strncpy(hLastProperty->szName, "Database", INI_MAX_PROPERTY_NAME);
strncpy(hLastProperty->szValue, "", INI_MAX_PROPERTY_VALUE);
hLastProperty->pszHelp = (char *) g_strdup("Filename and Path of MDB file to connect to.\n"
"Use the full path to the database file.");
return 1;
}
#endif
/** @}*/

38
src/odbc/getproperties.c Normal file
View File

@ -0,0 +1,38 @@
/* MDB Tools - A library for reading MS Access database file
* Copyright (C) 2000-2004 Brian Bruns
*
* portions based on FreeTDS, Copyright (C) 1998-1999 Brian Bruns
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <string.h>
#include <odbcinstext.h>
int
ODBCINSTGetProperties(HODBCINSTPROPERTY hLastProperty)
{
hLastProperty->pNext = malloc(sizeof(ODBCINSTPROPERTY));
hLastProperty = hLastProperty->pNext;
memset(hLastProperty, 0, sizeof(ODBCINSTPROPERTY));
hLastProperty->nPromptType = ODBCINST_PROMPTTYPE_FILENAME;
strncpy(hLastProperty->szName, "Database", INI_MAX_PROPERTY_NAME);
strncpy(hLastProperty->szValue, "", INI_MAX_PROPERTY_VALUE);
hLastProperty->pszHelp = strdup("Filename and Path of MDB file to connect to.\n"
"Use the full path to the database file.");
return 1;
}

View File

@ -21,9 +21,9 @@
#include <sql.h>
#include <sqlext.h>
#if defined(UNIXODBC)
#if defined(HAVE_ODBCINST_H)
# include <odbcinst.h>
#elif defined(IODBC)
#elif defined(HAVE_IODBCINST_H)
# include <iodbcinst.h>
#endif
@ -72,12 +72,16 @@ struct _hstmt {
struct _sql_bind_info {
int column_number;
int column_bindtype; /* type/conversion required */
int column_bindlen; /* size of varaddr buffer */
int *column_lenbind; /* where to store length of varaddr used */
SQLLEN column_bindlen; /* size of varaddr buffer */
SQLLEN *column_lenbind; /* where to store length of varaddr used */
char *varaddr;
struct _sql_bind_info *next;
};
size_t _mdb_odbc_ascii2unicode(struct _hdbc* dbc,
const char *_in, size_t _in_len,
SQLWCHAR *_out, size_t _out_count);
#ifdef __cplusplus
}
#endif

View File

@ -108,12 +108,35 @@ static SQLRETURN do_connect (
// https://docs.microsoft.com/en-us/sql/relational-databases/native-client-odbc-date-time/datetime-data-type-conversions-odbc?view=sql-server-ver15
mdb_set_date_fmt( dbc->sqlconn->mdb, "%F %H:%M:%S" );
mdb_set_shortdate_fmt( dbc->sqlconn->mdb, "%F" );
// Match formatting of REPID type values to MS Access ODBC driver
mdb_set_repid_fmt( dbc->sqlconn->mdb, MDB_NOBRACES_4_2_2_2_6 );
return SQL_SUCCESS;
}
else
return SQL_ERROR;
}
size_t _mdb_odbc_ascii2unicode(struct _hdbc* dbc, const char *_in, size_t _in_len, SQLWCHAR *_out, size_t _out_count){
wchar_t *w = malloc(_out_count * sizeof(wchar_t));
size_t count = 0, i;
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || defined(WINDOWS)
count = _mbstowcs_l(w, _in, _out_count, dbc->locale);
#elif defined(HAVE_MBSTOWCS_L)
count = mbstowcs_l(w, _in, _out_count, dbc->locale);
#else
locale_t oldlocale = uselocale(dbc->locale);
count = mbstowcs(w, _in, _out_count);
uselocale(oldlocale);
#endif
for (i=0; i<count; i++) {
_out[i] = (SQLWCHAR)w[i];
}
free(w);
if (count < _out_count)
_out[count] = '\0';
return count;
}
SQLRETURN SQL_API SQLDriverConnect(
SQLHDBC hdbc,
SQLHWND hwnd,
@ -490,7 +513,7 @@ SQLRETURN SQL_API SQLBindCol(
/* if this is a repeat */
if (cur) {
cur->column_bindtype = fCType;
cur->column_lenbind = (int *)pcbValue;
cur->column_lenbind = pcbValue;
cur->column_bindlen = cbValueMax;
cur->varaddr = (char *) rgbValue;
} else {
@ -499,7 +522,7 @@ SQLRETURN SQL_API SQLBindCol(
newitem->column_number = icol;
newitem->column_bindtype = fCType;
newitem->column_bindlen = cbValueMax;
newitem->column_lenbind = (int *)pcbValue;
newitem->column_lenbind = pcbValue;
newitem->varaddr = (char *) rgbValue;
/* if there's no head yet */
if (! stmt->bind_head) {
@ -833,13 +856,13 @@ unbind_columns(struct _hstmt *stmt)
stmt->bind_head = NULL;
}
SQLRETURN SQL_API SQLFetch(
SQLRETURN SQLFetch(
SQLHSTMT hstmt)
{
struct _hstmt *stmt = (struct _hstmt *) hstmt;
struct _sql_bind_info *cur = stmt->bind_head;
TRACE("SQLFetch");
if ( stmt->sql->limit >= 0 && stmt->rows_affected == stmt->sql->limit ) {
return SQL_NO_DATA_FOUND;
}
@ -1217,13 +1240,15 @@ SQLRETURN SQL_API SQLGetData(
if (col->col_type == MDB_BOOL) {
// bool cannot be null
if (fCType == SQL_C_CHAR) {
if ( col->cur_value_len )
((char *)rgbValue)[0] = '0';
else
((char *)rgbValue)[0] = '1';
((char *)rgbValue)[1] = '\0';
((SQLCHAR *)rgbValue)[0] = col->cur_value_len ? '0' : '1';
((SQLCHAR *)rgbValue)[1] = '\0';
if (pcbValue)
*pcbValue = sizeof(SQLCHAR);
} else if (fCType == SQL_C_WCHAR) {
((SQLWCHAR *)rgbValue)[0] = col->cur_value_len ? '0' : '1';
((SQLWCHAR *)rgbValue)[1] = '\0';
if (pcbValue)
*pcbValue = sizeof(SQLWCHAR);
} else {
*(BOOL*)rgbValue = col->cur_value_len ? 0 : 1;
if (pcbValue)
@ -1257,7 +1282,7 @@ SQLRETURN SQL_API SQLGetData(
found_bound_type:
if (fCType==SQL_C_DEFAULT)
fCType = _odbc_get_client_type(col);
if (fCType == SQL_C_CHAR)
if (fCType == SQL_C_CHAR || fCType == SQL_C_WCHAR)
goto to_c_char;
switch(col->col_type) {
case MDB_BYTE:
@ -1335,14 +1360,85 @@ SQLRETURN SQL_API SQLGetData(
break;
// case MDB_MONEY: TODO
case MDB_FLOAT:
*(float*)rgbValue = mdb_get_single(mdb->pg_buf, col->cur_value_start);
if (pcbValue)
*pcbValue = sizeof(float);
switch (fCType) {
case SQL_C_FLOAT:
*(float*)rgbValue = mdb_get_single(mdb->pg_buf, col->cur_value_start);
if (pcbValue)
*pcbValue = sizeof(float);
break;
case SQL_C_DOUBLE:
*(double*)rgbValue = (double)mdb_get_single(mdb->pg_buf, col->cur_value_start);
if (pcbValue)
*pcbValue = sizeof(double);
break;
case SQL_C_CHAR:
case SQL_C_WCHAR:
case SQL_C_STINYINT:
case SQL_C_UTINYINT:
case SQL_C_TINYINT:
case SQL_C_SBIGINT:
case SQL_C_UBIGINT:
case SQL_C_SSHORT:
case SQL_C_USHORT:
case SQL_C_SHORT:
case SQL_C_SLONG:
case SQL_C_ULONG:
case SQL_C_LONG:
case SQL_C_NUMERIC:
// case SQL_C_FLOAT:
// case SQL_C_DOUBLE:
case SQL_C_BIT:
case SQL_C_BINARY:
case SQL_C_INTERVAL_YEAR_TO_MONTH:
case SQL_C_INTERVAL_DAY_TO_HOUR:
case SQL_C_INTERVAL_DAY_TO_MINUTE:
case SQL_C_INTERVAL_DAY_TO_SECOND:
case SQL_C_INTERVAL_HOUR_TO_MINUTE:
case SQL_C_INTERVAL_HOUR_TO_SECOND:
strcpy(stmt->sqlState, "HYC00"); // Not implemented
return SQL_ERROR;
default:
strcpy(stmt->sqlState, "07006"); // Not allowed
return SQL_ERROR;
}
break;
case MDB_DOUBLE:
*(double*)rgbValue = mdb_get_double(mdb->pg_buf, col->cur_value_start);
if (pcbValue)
*pcbValue = sizeof(double);
switch (fCType) {
case SQL_C_DOUBLE:
*(double*)rgbValue = mdb_get_double(mdb->pg_buf, col->cur_value_start);
if (pcbValue)
*pcbValue = sizeof(double);
break;
case SQL_C_CHAR:
case SQL_C_WCHAR:
case SQL_C_STINYINT:
case SQL_C_UTINYINT:
case SQL_C_TINYINT:
case SQL_C_SBIGINT:
case SQL_C_UBIGINT:
case SQL_C_SSHORT:
case SQL_C_USHORT:
case SQL_C_SHORT:
case SQL_C_SLONG:
case SQL_C_ULONG:
case SQL_C_LONG:
case SQL_C_NUMERIC:
case SQL_C_FLOAT:
// case SQL_C_DOUBLE:
case SQL_C_BIT:
case SQL_C_BINARY:
case SQL_C_INTERVAL_YEAR_TO_MONTH:
case SQL_C_INTERVAL_DAY_TO_HOUR:
case SQL_C_INTERVAL_DAY_TO_MINUTE:
case SQL_C_INTERVAL_DAY_TO_SECOND:
case SQL_C_INTERVAL_HOUR_TO_MINUTE:
case SQL_C_INTERVAL_HOUR_TO_SECOND:
strcpy(stmt->sqlState, "HYC00"); // Not implemented
return SQL_ERROR;
default:
strcpy(stmt->sqlState, "07006"); // Not allowed
return SQL_ERROR;
}
break;
#if ODBCVER >= 0x0300
// returns text if old odbc
@ -1417,7 +1513,7 @@ SQLRETURN SQL_API SQLGetData(
free(stmt->ole_str);
stmt->ole_str = NULL;
break;
default: /* FIXME here we assume fCType == SQL_C_CHAR */
default: /* FIXME here we assume fCType == SQL_C_CHAR || fCType == SQL_C_WCHAR */
to_c_char:
{
if (cbValueMax < 0) {
@ -1425,6 +1521,7 @@ SQLRETURN SQL_API SQLGetData(
return SQL_ERROR;
}
char *str = NULL;
SQLWCHAR *wstr = NULL;
if (col->col_type == MDB_NUMERIC) {
str = mdb_numeric_to_string(mdb, col->cur_value_start,
col->col_scale, col->col_prec);
@ -1433,37 +1530,47 @@ SQLRETURN SQL_API SQLGetData(
col->cur_value_start, col->col_type, col->cur_value_len);
}
size_t len = strlen(str);
size_t charsize = 1;
if (fCType == SQL_C_WCHAR) {
wstr = calloc(len+1, charsize = sizeof(SQLWCHAR));
len = _mdb_odbc_ascii2unicode(((struct _hstmt *)hstmt)->hdbc, str, len, wstr, len+1);
}
if (stmt->pos >= len) {
free(str);
str = NULL;
free(wstr); wstr = NULL;
free(str); str = NULL;
return SQL_NO_DATA;
}
if (pcbValue) {
*pcbValue = len - stmt->pos;
*pcbValue = (len - stmt->pos) * charsize;
}
if (cbValueMax == 0) {
free(str);
str = NULL;
free(wstr); wstr = NULL;
free(str); str = NULL;
return SQL_SUCCESS_WITH_INFO;
}
const int totalSizeRemaining = len - stmt->pos;
const int partsRemain = cbValueMax - 1 < totalSizeRemaining;
const int sizeToReadThisPart = partsRemain ? cbValueMax - 1 : totalSizeRemaining;
memcpy(rgbValue, str + stmt->pos, sizeToReadThisPart);
const int totalCharactersRemaining = len - stmt->pos;
const int partsRemain = cbValueMax/charsize - 1 < totalCharactersRemaining;
const int charactersToReadThisPart = partsRemain ? cbValueMax/charsize - 1 : totalCharactersRemaining;
((char *)rgbValue)[sizeToReadThisPart] = '\0';
if (wstr) {
memcpy(rgbValue, wstr + stmt->pos, charactersToReadThisPart * sizeof(SQLWCHAR));
((SQLWCHAR *)rgbValue)[charactersToReadThisPart] = '\0';
} else {
memcpy(rgbValue, str + stmt->pos, charactersToReadThisPart);
((SQLCHAR *)rgbValue)[charactersToReadThisPart] = '\0';
}
free(wstr); wstr = NULL;
free(str); str = NULL;
if (partsRemain) {
stmt->pos += cbValueMax - 1;
free(str); str = NULL;
stmt->pos += charactersToReadThisPart;
strcpy(stmt->sqlState, "01004"); // truncated
return SQL_SUCCESS_WITH_INFO;
}
stmt->pos = len;
free(str);
str = NULL;
break;
}
}
@ -1948,14 +2055,14 @@ SQLRETURN SQL_API SQLDataSources(
static int _odbc_fix_literals(struct _hstmt *stmt)
{
char tmp[4096],begin_tag[11];
char tmp[4096];
char *s, *d, *p;
int i, quoted = 0, find_end = 0;
char quote_char;
char quote_char = '\0';
s=stmt->query;
d=tmp;
while (*s) {
while (*s && d<tmp+sizeof(tmp)) {
if (!quoted && (*s=='"' || *s=='\'')) {
quoted = 1;
quote_char = *s;
@ -1970,9 +2077,7 @@ static int _odbc_fix_literals(struct _hstmt *stmt)
/* garbage */
*d++=*s++;
} else {
strncpy(begin_tag, s, i);
begin_tag[i] = '\0';
/* printf("begin tag %s\n", begin_tag); */
/* printf("begin tag %.*s\n", i, s); */
s += i;
find_end = 1;
}
@ -1980,8 +2085,8 @@ static int _odbc_fix_literals(struct _hstmt *stmt)
*d++=*s++;
}
}
*d='\0';
strcpy(stmt->query,tmp);
snprintf(stmt->query, sizeof(stmt->query), "%.*s", (int)(d-tmp), tmp);
return 0;
}
@ -2088,7 +2193,7 @@ static const char * _odbc_get_client_type_name(MdbColumn *col)
case MDB_COMPLEX:
return "COMPLEX";
default:
// fprintf(stderr,"Unknown type %d\n",srv_type);
fprintf(stderr,"Unknown type for column %s: %d\n",col->name,col->col_type);
break;
}
return NULL;

View File

@ -16,6 +16,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* For a full list of functions that could be implemented, see:
* https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/unicode-function-arguments?view=sql-server-ver15 */
#define SQL_NOUNICODEMAP
#define UNICODE
@ -61,27 +64,6 @@ static size_t unicode2ascii(struct _hdbc* dbc, const SQLWCHAR *_in, size_t _in_c
return count;
}
static size_t ascii2unicode(struct _hdbc* dbc, const char *_in, size_t _in_len, SQLWCHAR *_out, size_t _out_count){
wchar_t *w = malloc(_out_count * sizeof(wchar_t));
size_t count = 0, i;
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || defined(WINDOWS)
count = _mbstowcs_l(w, _in, _out_count, dbc->locale);
#elif defined(HAVE_MBSTOWCS_L)
count = mbstowcs_l(w, _in, _out_count, dbc->locale);
#else
locale_t oldlocale = uselocale(dbc->locale);
count = mbstowcs(w, _in, _out_count);
uselocale(oldlocale);
#endif
for (i=0; i<count; i++) {
_out[i] = (SQLWCHAR)w[i];
}
free(w);
if (count < _out_count)
_out[count] = '\0';
return count;
}
static int sqlwlen(SQLWCHAR *p){
int r=0;
for(;*p;r++)
@ -161,7 +143,7 @@ SQLRETURN SQL_API SQLDescribeColW(
size_t l=cbColNameMax*4+1;
SQLCHAR *tmp=calloc(l,1);
SQLRETURN ret = SQLDescribeCol(hstmt, icol, tmp, l, (SQLSMALLINT*)&l, pfSqlType, pcbColDef, pibScale, pfNullable);
*pcbColName = ascii2unicode(((struct _hstmt*)hstmt)->hdbc, (char*)tmp, l, szColName, cbColNameMax);
*pcbColName = _mdb_odbc_ascii2unicode(((struct _hstmt*)hstmt)->hdbc, (char*)tmp, l, szColName, cbColNameMax);
free(tmp);
return ret;
}
@ -183,7 +165,7 @@ SQLRETURN SQL_API SQLColAttributesW(
size_t l=cbDescMax*4+1;
SQLCHAR *tmp=calloc(l,1);
SQLRETURN ret=SQLColAttributes(hstmt,icol,fDescType,tmp,l,(SQLSMALLINT*)&l,pfDesc);
*pcbDesc = ascii2unicode(((struct _hstmt *)hstmt)->hdbc, (char*)tmp, l, (SQLWCHAR*)rgbDesc, cbDescMax);
*pcbDesc = _mdb_odbc_ascii2unicode(((struct _hstmt *)hstmt)->hdbc, (char*)tmp, l, (SQLWCHAR*)rgbDesc, cbDescMax);
free(tmp);
return ret;
}
@ -210,8 +192,8 @@ SQLRETURN SQL_API SQLErrorW(
if (result == SQL_SUCCESS) {
struct _hdbc *dbc = hstmt ? ((struct _hstmt *)hstmt)->hdbc : hdbc;
size_t pcb;
ascii2unicode(dbc, (char*)szSqlState8, sizeof(szSqlState8), szSqlState, sizeof(szSqlState8));
pcb = ascii2unicode(dbc, (char*)szErrorMsg8, pcbErrorMsg8, szErrorMsg, cbErrorMsgMax);
_mdb_odbc_ascii2unicode(dbc, (char*)szSqlState8, sizeof(szSqlState8), szSqlState, sizeof(szSqlState8));
pcb = _mdb_odbc_ascii2unicode(dbc, (char*)szErrorMsg8, pcbErrorMsg8, szErrorMsg, cbErrorMsgMax);
if (pcbErrorMsg) *pcbErrorMsg = pcb;
}
return result;
@ -259,24 +241,6 @@ SQLRETURN SQL_API SQLColumnsW(
}
}
SQLRETURN SQL_API SQLGetDataW(
SQLHSTMT hstmt,
SQLUSMALLINT icol,
SQLSMALLINT fCType,
SQLPOINTER rgbValue,
SQLLEN cbValueMax,
SQLLEN *pcbValue)
{
//todo: treat numbers correctly
size_t l=cbValueMax*4+1;
SQLCHAR *tmp=calloc(l,1);
SQLRETURN ret = SQLGetData(hstmt, icol, fCType, tmp, l, (SQLLEN*)&l);
*pcbValue = ascii2unicode(((struct _hstmt *)hstmt)->hdbc, (char*)tmp, l, (SQLWCHAR*)rgbValue, cbValueMax);
free(tmp);
return ret;
}
SQLRETURN SQL_API SQLGetInfoW(
SQLHDBC hdbc,
SQLUSMALLINT fInfoType,
@ -292,7 +256,7 @@ SQLRETURN SQL_API SQLGetInfoW(
size_t l=cbInfoValueMax*4+1;
SQLCHAR *tmp=calloc(l,1);
SQLRETURN ret = SQLGetInfo(hdbc, fInfoType, tmp, l, (SQLSMALLINT*)&l);
size_t pcb = ascii2unicode((struct _hdbc *)hdbc, (char*)tmp, l, (SQLWCHAR*)rgbInfoValue, cbInfoValueMax);
size_t pcb = _mdb_odbc_ascii2unicode((struct _hdbc *)hdbc, (char*)tmp, l, (SQLWCHAR*)rgbInfoValue, cbInfoValueMax);
if(pcbInfoValue)*pcbInfoValue=pcb;
free(tmp);
return ret;

View File

@ -113,7 +113,7 @@ strptime\( { return STRPTIME; }
return STRING;
}
(-?[0-9]+|(-?[0-9]*\.[0-9]+)(e[-+]?[0-9]+)?) {
(-?[0-9]+|(-?[0-9]*\.[0-9]*)(e[-+]?[0-9]+)?) {
yylval->name = g_strdup(yytext); return NUMBER;
}
~?(\/?[a-z0-9\.\-\_\!\~\'\(\)\%\xa0-\xff]+)+ {

View File

@ -1,4 +1,7 @@
if ENABLE_BASH_COMPLETION
bashcompletiondir = $(BASH_COMPLETION_DIR)
dist_bashcompletion_DATA = mdb-count mdb-export mdb-hexdump mdb-import mdb-json mdb-parsecsv mdb-prop mdb-queries mdb-schema mdb-sql mdb-tables mdb-ver
dist_bashcompletion_DATA = mdb-count mdb-export mdb-hexdump mdb-import mdb-json mdb-parsecsv mdb-prop mdb-queries mdb-schema mdb-tables mdb-ver
if SQL
dist_bashcompletion_DATA += mdb-sql
endif
endif

View File

@ -35,17 +35,17 @@ char quote_text = 1;
int count = 0;
int started;
fputs("mdb-array is deprecated and will disappear in a future version of mdbtools.\n", stderr);
fputs("Please drop us a line if you have any use of it.\n", stderr);
fputs("See https://github.com/mdbtools/mdbtools/issues/197\n", stderr);
fputs("\n", stderr);
if (argc < 3)
{
fprintf (stderr, "Usage: %s <file> <table>\n", argv [0]);
exit (1);
}
fputs("mdb-array is deprecated and will disappear in a future version of mdbtools.\n", stderr);
fputs("Please drop us a line if you have any use of it.\n", stderr);
fputs("See https://github.com/mdbtools/mdbtools/issues/197\n", stderr);
fputs("\n", stderr);
mdb = mdb_open (argv [1], MDB_NOFLAGS);
if (!mdb)
exit(1);

View File

@ -42,16 +42,16 @@ FILE *typesfile;
FILE *headerfile;
FILE *cfile;
if (argc < 2) {
fprintf (stderr, "Usage: %s <file>\n",argv[0]);
exit (1);
}
fputs("mdb-header is deprecated and will disappear in a future version of mdbtools.\n", stderr);
fputs("Please drop us a line if you have any use of it.\n", stderr);
fputs("See https://github.com/mdbtools/mdbtools/issues/197\n", stderr);
fputs("\n", stderr);
if (argc < 2) {
fprintf (stderr, "Usage: %s <file>\n",argv[0]);
exit (1);
}
/* open the database */
mdb = mdb_open (argv[1], MDB_NOFLAGS);
@ -92,6 +92,11 @@ FILE *cfile;
entry->object_name, entry->object_name);
fprintf (cfile, "\tfprintf (stdout, \"**************** %s ****************\\n\");\n", entry->object_name);
table = mdb_read_table (entry);
if (!table) {
fprintf(stderr, "Error: Table %s does not exist in this database.\n", entry->object_name);
/* Don't bother clean up memory before exit */
exit(1);
}
/* get the columns */
mdb_read_columns (table);

View File

@ -53,17 +53,17 @@ main (int argc, char **argv)
int lastcomma;
int i;
fputs("mdb-parsecsv is deprecated and will disappear in a future version of mdbtools.\n", stderr);
fputs("Please drop us a line if you have any use of it.\n", stderr);
fputs("See https://github.com/mdbtools/mdbtools/issues/197\n", stderr);
fputs("\n", stderr);
if (argc < 2)
{
fprintf (stderr, "Usage: %s <file> (assumed extension .txt)\n",argv[0]);
exit (1);
}
fputs("mdb-parsecsv is deprecated and will disappear in a future version of mdbtools.\n", stderr);
fputs("Please drop us a line if you have any use of it.\n", stderr);
fputs("See https://github.com/mdbtools/mdbtools/issues/197\n", stderr);
fputs("\n", stderr);
strcpy (txt_filename, argv [1]);
txtfile = fopen (txt_filename, "r");
if (!txtfile) {

View File

@ -97,9 +97,9 @@ main(int argc, char **argv)
g_free(buf);
mdb_free_tabledef(table);
g_free(table_name);
g_free(propColName);
mdb_close(mdb);
printf("Column %s not found in MSysObjects!\n", propColName);
g_free(propColName);
return 1;
}

View File

@ -304,7 +304,7 @@ find_sql_terminator(char *s)
}
sp = &s[len-1];
while (sp > s && isspace(*sp)) {
while (sp > s && isspace((int)*sp)) {
sp--;
}
@ -322,7 +322,7 @@ main(int argc, char **argv)
char prompt[20];
int line = 0;
char *mybuf;
unsigned int bufsz;
size_t bufsz;
MdbSQL *sql;
FILE *in = NULL, *out = NULL;
char *filename_in=NULL, *filename_out=NULL;
@ -408,7 +408,7 @@ main(int argc, char **argv)
/* give the buffer an initial size */
bufsz = 4096;
mybuf = g_malloc(bufsz);
mybuf = malloc(bufsz);
mybuf[0]='\0';
while (1) {
@ -420,7 +420,7 @@ main(int argc, char **argv)
if (in) {
s=calloc(bufsz, 1);
if (!fgets(s, bufsz, in)) {
if (!fgets(s, (int)bufsz, in)) {
// Backwards compatibility with older MDBTools
// Files read from the command line had an
// implicit "go" at the end
@ -464,7 +464,7 @@ main(int argc, char **argv)
if (in) {
fprintf(stderr, "Can not handle nested opens\n");
} else {
while (*fname && isspace(*fname))
while (*fname && isspace((int)*fname))
fname++;
if (!(in = fopen(fname, "r"))) {
fprintf(stderr,"Unable to open file %s\n", fname);
@ -478,7 +478,7 @@ main(int argc, char **argv)
while (strlen(mybuf) + strlen(s) > bufsz) {
bufsz *= 2;
mybuf = (char *) g_realloc(mybuf, bufsz);
mybuf = realloc(mybuf, bufsz);
}
#ifdef HAVE_READLINE_HISTORY
/* don't record blank lines, or lines read from files
@ -500,7 +500,7 @@ main(int argc, char **argv)
}
mdb_sql_exit(sql);
g_free(mybuf);
free(mybuf);
if (s) free(s);
if (out) fclose(out);
if ((in) && (in != stdin)) fclose(in);

View File

@ -1,18 +1,131 @@
#!/bin/bash
#!/bin/sh
# Simple test script; run after performing
# git clone https://github.com/mdbtools/mdbtestdata.git test
./src/util/mdb-json test/data/ASampleDatabase.accdb "Asset Items"
./src/util/mdb-json test/data/nwind.mdb "Umsätze"
./src/util/mdb-count test/data/ASampleDatabase.accdb "Asset Items"
./src/util/mdb-count test/data/nwind.mdb "Umsätze"
./src/util/mdb-prop test/data/ASampleDatabase.accdb "Asset Items"
./src/util/mdb-prop test/data/nwind.mdb "Umsätze"
./src/util/mdb-schema test/data/ASampleDatabase.accdb
./src/util/mdb-schema test/data/nwind.mdb
./src/util/mdb-schema test/data/nwind.mdb -T "Umsätze" postgres
./src/util/mdb-tables test/data/ASampleDatabase.accdb
./src/util/mdb-tables test/data/nwind.mdb
./src/util/mdb-ver test/data/ASampleDatabase.accdb
./src/util/mdb-ver test/data/nwind.mdb
./src/util/mdb-queries test/data/ASampleDatabase.accdb qryCostsSummedByOwner
set -o errexit
set -o nounset
LANG=C.UTF-8
CDPATH= cd -- "$(dirname -- "$0")"
parseArgs() {
MT_OUTPUT_KIND=verbose
while :; do
if test $# -lt 1; then
break
fi
case "$1" in
-q | --quiet)
MT_OUTPUT_KIND=quiet
;;
-g | --github)
MT_OUTPUT_KIND=github
;;
-h | --help)
printf 'Syntax:\n%s [-q|--quiet|-g|--github] [-h|--help]\n' "$0"
exit 0
;;
*)
printf 'Unrecognized option: "%s"\n' "$1"
exit 1
;;
esac
shift
done
}
testCommand() {
testCommand_name="$1"
shift
case $MT_OUTPUT_KIND in
verbose)
printf '# Running %s (%s)\n' "$testCommand_name" "$*"
if "./src/util/$testCommand_name" "$@"; then
return 0
fi
return 1
;;
quiet)
printf 'Testing %s (%s)... ' "$testCommand_name" "$*"
if "./src/util/$testCommand_name" "$@" >/dev/null; then
printf 'passed.\n'
return 0
fi
return 1
;;
github)
testCommand_tempFile="$(mktemp)"
printf 'Testing %s (%s)... ' "$testCommand_name" "$*"
if "./src/util/$testCommand_name" "$@" 2>&1 >"$testCommand_tempFile"; then
printf 'passed.\n'
testCommand_rc=0
else
printf 'failed.\n'
testCommand_rc=1
fi
echo '::group::Output'
cat "$testCommand_tempFile"
echo '::endgroup::'
unlink "$testCommand_tempFile"
return $testCommand_rc
;;
*)
printf 'Unrecognized MT_OUTPUT_KIND (%s)\n' "$MT_OUTPUT_KIND"
exit 1
;;
esac
}
parseArgs "$@"
rc=0
if ! testCommand mdb-json test/data/ASampleDatabase.accdb "Asset Items"; then
rc=1
fi
if ! testCommand mdb-json test/data/nwind.mdb "Umsätze"; then
rc=1
fi
if ! testCommand mdb-count test/data/ASampleDatabase.accdb "Asset Items"; then
rc=1
fi
if ! testCommand mdb-count test/data/nwind.mdb "Umsätze"; then
rc=1
fi
if ! testCommand mdb-prop test/data/ASampleDatabase.accdb "Asset Items"; then
rc=1
fi
if ! testCommand mdb-prop test/data/nwind.mdb "Umsätze"; then
rc=1
fi
if ! testCommand mdb-schema test/data/ASampleDatabase.accdb; then
rc=1
fi
if ! testCommand mdb-schema test/data/nwind.mdb; then
rc=1
fi
if ! testCommand mdb-schema test/data/nwind.mdb -T "Umsätze" postgres; then
rc=1
fi
if ! testCommand mdb-tables test/data/ASampleDatabase.accdb; then
rc=1
fi
if ! testCommand mdb-tables test/data/nwind.mdb; then
rc=1
fi
if ! testCommand mdb-ver test/data/ASampleDatabase.accdb; then
rc=1
fi
if ! testCommand mdb-ver test/data/nwind.mdb; then
rc=1
fi
if ! testCommand mdb-queries test/data/ASampleDatabase.accdb qryCostsSummedByOwner; then
rc=1
fi
if [ $rc = 0 ]; then
printf -- '\n%s passed.\n' "$0"
else
printf -- '\n%s failed!\n' "$0"
fi
exit $rc