Merge branch 'dev'

This commit is contained in:
Evan Miller 2021-10-24 09:17:04 -04:00
commit ab9e4088a9
45 changed files with 1065 additions and 618 deletions

View File

@ -7,6 +7,7 @@ jobs:
fail-fast: false
matrix:
compiler: [ clang, gcc, gcc-9, gcc-10 ]
iconv: [ enable-iconv, disable-iconv]
glib: [ enable-glib, disable-glib ]
steps:
- name: Install packages
@ -17,7 +18,7 @@ jobs:
- name: Autoconf
run: autoreconf -i -f
- name: Configure
run: ./configure --disable-silent-rules --${{ matrix.glib }} --with-unixodbc=/usr
run: ./configure --disable-silent-rules --${{ matrix.glib }} --${{ matrix.iconv }} --with-unixodbc=/usr
env:
CC: ${{ matrix.compiler }}
- name: Make
@ -44,6 +45,7 @@ jobs:
fail-fast: false
matrix:
compiler: [ clang, gcc ]
iconv: [ enable-iconv, disable-iconv]
glib: [ enable-glib, disable-glib ]
steps:
- name: Install packages
@ -54,7 +56,7 @@ jobs:
- name: Autoconf
run: autoreconf -i -f
- name: Configure
run: ./configure --disable-silent-rules --${{ matrix.glib }} --with-unixodbc=/usr/local/opt
run: ./configure --disable-silent-rules --${{ matrix.glib }} --${{ matrix.iconv }} --with-unixodbc=/usr/local/opt
env:
CC: ${{ matrix.compiler }}
YACC: /usr/local/opt/bison/bin/bison

3
.gitignore vendored
View File

@ -3,12 +3,14 @@
*.la
*.out
.deps/
.idea/
.libs/
aclocal.m4
autom4te.cache/
build-aux/*
!build-aux/config.rpath
m4/
!m4/ax_tls.m4
!m4/ccalias.m4
!m4/iconv.m4
!m4/readline.m4
@ -20,6 +22,7 @@ Makefile
doc/*.1
INSTALL
include/mdbver.h
include/mdbtools.h
libmdb.pc
libmdbsql.pc
libtool

View File

@ -6,4 +6,7 @@ DEFDIR = $(prefix)
EXTRA_DIST = HACKING HACKING.md libmdb.pc.in libmdbsql.pc.in README.md
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libmdb.pc libmdbsql.pc
pkgconfig_DATA = libmdb.pc
if SQL
pkgconfig_DATA += libmdbsql.pc
endif

61
NEWS
View File

@ -1,3 +1,64 @@
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
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
`pkg-config`:
* Simplify `--cflags` for libmdb
* Provide correct `--cflags` for libmdbsql
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`:
* Deprecate tool
Version 0.9.4
=============

View File

@ -12,11 +12,11 @@ The major pieces of MDB Tools are:
### libmdb
The core library that allows access to MDB files programatically.
The core library that allows access to MDB files programatically. See [mdbtools.h](./include/mdbtools.h.in) for the complete API.
### libmdbsql
Builds on libmdb to provide a SQL engine (aka Jet)
Builds on libmdb to provide a SQL engine (aka Jet). See [mdbsql.h](./include/mdbsql.h) for the complete API.
### utils
@ -32,17 +32,26 @@ Provides command line utilities, including:
| `mdb-count` | A simple count of number of rows in a table, to be used in shell scripts and ETL pipelines. |
| `mdb-sql` | A simple SQL engine (also used by ODBC and gmdb). |
| `mdb-queries` | List and print queries stored in the database. |
| `mdb-hexdump`\* | (in [src/extras](./src/extras)) Simple hex dump utility to look at mdb files. |
| `mdb-array`\* | Export data in an MDB database table to a C array. |
| `mdb-header`\* | Generates a C header to be used in exporting mdb data to a C prog. |
| `mdb-parsecsv`\* | Generates a C program given a CSV file made with mdb-export. |
\* Deprecated
See the man page of each program for usage instructions.
The [src/util](./src/util) directory also contains a number of debugging tools, intended for developers. They are:
| Command | Description |
| ------- | ----------- |
| `prcat` | Prints the catalog table from an mdb file. |
| `prkkd` | Dump of information about design view data given the offset to it. |
| `prtable` | Dump of a table definition. |
| `prdata` | Dump of the data given a table name. |
| `prole` | Dump of ole columns given a table name and sargs. |
| `mdb-hexdump` | (in src/extras) Simple hex dump utility that I've been using to look at mdb files. |
| `mdb-array` | Export data in an MDB database table to a C array.\* |
| `mdb-header` | Generates a C header to be used in exporting mdb data to a C prog.\* |
| `mdb-parsecsv` | Generates a C program given a CSV file made with mdb-export.\* |
\* Deprecated
These tools are not installed on the host system.
### odbc
@ -50,7 +59,7 @@ An ODBC driver for use with unixODBC or iODBC driver manager. Allows one to use
### gmdb2
The Gnome MDB File Viewer and debugger. Alpha quality, moved to [mdbtools/gmdb2](https://github.com/mdbtools/gmdb2).
The Gnome MDB File Viewer and debugger. Recently ported to GTK+3 and moved to [mdbtools/gmdb2](https://github.com/mdbtools/gmdb2).
## License
@ -65,7 +74,7 @@ First, you must have reasonably current installations of:
* [libtool](https://www.gnu.org/software/libtool/)
* [automake](https://www.gnu.org/software/automake/)
* [autoconf](https://www.gnu.org/software/autoconf/) (version >= 2.58)
* [autoconf](https://www.gnu.org/software/autoconf/) (version >= 2.64)
If you want to build the SQL engine, you'll need
[bison](https://www.gnu.org/software/bison/) (version >= 3.0) or
@ -95,6 +104,12 @@ apt install mdbtools
brew install mdbtools
```
### MacPorts
```bash
port install mdbtools
```
### From source
If you have cloned the Git repository, you will first need to generate the
@ -134,6 +149,9 @@ mutually exclusive.
causes the iODBC driver to be built.
```
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.

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).

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,30 +1,32 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT([mdbtools],[0.9.4],[https://github.com/mdbtools/mdbtools/issues],[],[https://github.com/mdbtools/mdbtools])
AC_INIT([mdbtools],[1.0.0],[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)
AM_INIT_AUTOMAKE([foreign dist-zip])
MDBTOOLS_VERSION_MAJOR=0
MDBTOOLS_VERSION_MINOR=9
MDBTOOLS_VERSION_MICRO=4
MDBTOOLS_VERSION_MAJOR=1
MDBTOOLS_VERSION_MINOR=0
MDBTOOLS_VERSION_MICRO=0
# Update these numbers with every release
# See https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
VERSION_INFO=3:4:0
VERSION_INFO=4:0:1
AC_SUBST(VERSION_INFO)
AC_SUBST(MDBTOOLS_CFLAGS)
AM_MAINTAINER_MODE([enable])
AM_SILENT_RULES([yes])
AC_USE_SYSTEM_EXTENSIONS
AC_PROG_CC(gcc)
AC_PROG_CXX
AX_TLS([FOO=bar], AC_MSG_ERROR([$CC does not support thread-local storage. A newer compiler is required.]))
dnl Checks for programs.
AC_PROG_MAKE_SET
m4_pattern_allow([AM_PROG_AR], [AM_PROG_AR])
LT_INIT([win32-dll])
AC_PROG_LEX
AC_PROG_LEX([noyywrap])
AC_PROG_YACC
dnl Checks for header files.
@ -36,13 +38,8 @@ AC_CHECK_DECLS([program_invocation_short_name], [], [], [[
dnl Checks for library functions.
VL_LIB_READLINE
AC_CHECK_FUNCS(strptime fmemopen gmtime_r reallocf wcstombs_l vasprintf vasnprintf)
AC_CHECK_FUNCS(strptime fmemopen gmtime_r reallocf wcstombs_l mbstowcs_l vasprintf vasnprintf)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_SIZE_T
AM_ICONV
AM_GCC_ATTRIBUTE_ALIAS
dnl Enable large files on 32-bit systems
@ -87,12 +84,30 @@ AC_SUBST(SQL)
AC_SUBST(LFLAGS)
CFLAGS="$CFLAGS -Wall -Werror"
LOCALE_T=locale_t
AS_CASE([$host],
[*mingw*|*cygwin*], [LDFLAGS="$LDFLAGS -no-undefined"], [])
[*mingw*], [LDFLAGS="$LDFLAGS -no-undefined" LOCALE_T=_locale_t], [])
AC_SUBST(LOCALE_T)
dnl See if iconv is present and wanted
AC_ARG_ENABLE(iconv,
AS_HELP_STRING([--disable-iconv], [do not use iconv for character conversions (use locale.h where possible)]),
[enable_iconv=$enableval], [enable_iconv=yes])
HAVE_ICONV_H=0
if test "$enable_iconv" = "yes"; then
AM_ICONV
# Use the "working iconv" test instead of the "iconv" ($am_cv_func_iconv) test
# so that our HAVE_ICONV_H substitution variable has the same value as the HAVE_ICONV
# C macro
if test "$am_func_iconv" = "yes"; then
HAVE_ICONV_H=1
fi
fi
AC_SUBST(HAVE_ICONV_H)
dnl Fuzz testing
AC_ARG_ENABLE([fuzz-testing], AS_HELP_STRING([--enable-fuzz-testing], ["Enable fuzz testing (requires Clang 6 or later)"]), [
AC_ARG_ENABLE([fuzz-testing], AS_HELP_STRING([--enable-fuzz-testing], [enable fuzz testing (requires Clang 6 or later)]), [
AC_MSG_CHECKING([whether $CC accepts -fsanitize=fuzzer])
tmp_saved_flags=$[]_AC_LANG_PREFIX[]FLAGS
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS -fsanitize=fuzzer"
@ -138,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"
@ -154,7 +168,6 @@ if test "$with_unixodbc"; then
HAVE_ODBC=true
ODBC_CFLAGS="-I$with_unixodbc/include"
ODBC_LIBS="-L$with_unixodbc/$libdir"
CFLAGS="$CFLAGS -DUNIXODBC"
dnl SIZEOF_LONG_INT and HAVE_LONG_LONG are required by some versions of unixODBC
dnl https://github.com/lurcher/unixODBC/issues/40
@ -177,21 +190,24 @@ 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)
OPTDIRS="$OPTDIRS odbc"
fi
dnl Conditionally build odbc wide version
AM_CONDITIONAL(ICONV, test "$am_cv_func_iconv" = "yes")
dnl Testing presence of pkg-config
AC_MSG_CHECKING([pkg-config m4 macros])
if test m4_ifdef([PKG_CHECK_MODULES], [yes], [no]) = yes; then
@ -221,8 +237,23 @@ if test "$enable_glib" = "yes"; then
fi
AM_CONDITIONAL(FAKE_GLIB, test "x$enable_glib" != "xyes")
dnl Set up substitution variables
if test "$ac_cv_header_xlocale_h" = "yes"; then
HAVE_XLOCALE_H=1
else
HAVE_XLOCALE_H=0
fi
AC_SUBST(HAVE_XLOCALE_H)
if test "$enable_glib" = "yes"; then
GLIB_INCLUDE_HEADER=glib.h
else
GLIB_INCLUDE_HEADER=mdbfakeglib.h
fi
AC_SUBST(GLIB_INCLUDE_HEADER)
AC_SUBST([OPTDIRS])
AC_CONFIG_FILES([src/Makefile])
AC_CONFIG_FILES([src/Makefile include/mdbtools.h])
##################################################
# Check for txt2man
@ -293,6 +324,8 @@ if test x$HAVE_ODBC = xtrue; then summary=${bold_green}enabled; else summary=${b
AC_MSG_NOTICE([ ODBC : ${summary}${reset}])
if test x$enable_glib = xyes; then summary=${bold_green}enabled; else summary=${bold_red}disabled; fi
AC_MSG_NOTICE([ GLib : ${summary}${reset}])
if test x$enable_iconv = xyes; then summary=${bold_green}enabled; else summary=${bold_red}disabled; fi
AC_MSG_NOTICE([ iconv : ${summary}${reset}])
if test x$enable_man = xyes; then summary=${bold_green}enabled; else summary=${bold_red}disabled; fi
AC_MSG_NOTICE([ man pages : ${summary}${reset}])
if test "x$with_bash_completion_dir" != "xno"; then summary=${bold_green}enabled; else summary=${bold_red}disabled; fi

View File

@ -4,15 +4,21 @@ PRODUCT = MDBTools
dist_man_MANS =
if ENABLE_MAN
dist_man_MANS += mdb-tables.1 mdb-ver.1 mdb-export.1 mdb-schema.1 mdb-sql.1 \
dist_man_MANS += mdb-tables.1 mdb-ver.1 mdb-export.1 mdb-schema.1 \
mdb-array.1 mdb-header.1 mdb-hexdump.1 mdb-parsecsv.1 mdb-prop.1 mdb-import.1 \
mdb-count.1 mdb-json.1 mdb-queries.1
if SQL
dist_man_MANS += mdb-sql.1
endif
endif
CLEANFILES = ${dist_man_MANS}
EXTRA_DIST = mdb-tables.txt mdb-ver.txt mdb-export.txt mdb-schema.txt mdb-sql.txt \
EXTRA_DIST = mdb-tables.txt mdb-ver.txt mdb-export.txt mdb-schema.txt \
mdb-array.txt mdb-header.txt mdb-hexdump.txt mdb-parsecsv.txt mdb-prop.txt mdb-import.txt \
mdb-count.txt mdb-json.txt mdb-queries.txt \
txt2man
if SQL
EXTRA_DIST += mdb-sql.txt
endif
.txt.1:
$(TXT2MAN) -t $* -r "$(PRODUCT) $(VERSION)" -s 1 -v "Executable programs or shell commands" $(srcdir)/$< > $@

View File

@ -50,7 +50,7 @@ SQL LANGUAGE
limit clause: LIMIT <integer>
operator: =, =>, =<, <>, like, <, >
operator: =, =>, =<, <>, like, ilike, <, >
literal: integers, floating point numbers, or string literal in single quotes
@ -63,6 +63,10 @@ NOTES
The -i command can be passed the string 'stdin' to test entering text as if using a pipe.
The 'like' operator performs a case-sensitive pattern match, with ANSI-style wildcards. An underscore in the pattern will match any single character, and a percent sign will match any run of characters.
The 'ilike' operator is similar, but performs a case-insensitive pattern match.
ENVIRONMENT
LC_COLLATE Defines the locale for string-comparison operations. See locale(1).
MDB_JET3_CHARSET Defines the charset of the input JET3 (access 97) file. Default is CP1252. See iconv(1).

View File

@ -1,4 +1,8 @@
include_HEADERS = mdbtools.h mdbsql.h
EXTRA_DIST = mdbtools.h.in
include_HEADERS = mdbtools.h
if SQL
include_HEADERS += mdbsql.h
endif
if FAKE_GLIB
include_HEADERS += mdbfakeglib.h
endif

View File

@ -39,6 +39,7 @@ typedef const void * gconstpointer;
typedef uint8_t guint8;
typedef guint32 GQuark;
typedef guint32 gunichar;
typedef signed long gssize;
typedef guint (*GHashFunc)(gconstpointer);
typedef int (*GCompareFunc)(gconstpointer, gconstpointer);
@ -143,6 +144,8 @@ void g_printerr(const gchar *format, ...);
gint g_unichar_to_utf8(gunichar c, gchar *dst);
gchar *g_locale_to_utf8(const gchar *opsysstring, size_t len,
size_t *bytes_read, size_t *bytes_written, GError **error);
gchar *g_utf8_casefold(const gchar *str, gssize len);
gchar *g_utf8_strdown(const gchar *str, gssize len);
/* GString */
GString *g_string_new(const gchar *init);

View File

@ -35,6 +35,18 @@
#endif
void mdbi_rc4(unsigned char *key, guint32 key_len, unsigned char *buf, guint32 buf_len);
MdbBackend *mdbi_register_backend2(MdbHandle *mdb, char *backend_name, guint32 capabilities,
const MdbBackendType *backend_type,
const MdbBackendType *type_shortdate,
const MdbBackendType *type_autonum,
const char *short_now, const char *long_now,
const char *date_fmt, const char *shortdate_fmt,
const char *charset_statement, const char *create_table_statement,
const char *drop_statement, const char *constaint_not_empty_statement,
const char *column_comment_statement, const char *per_column_comment_statement,
const char *table_comment_statement, const char *per_table_comment_statement,
gchar* (*quote_schema_name)(const gchar*, const gchar*),
gchar* (*normalise_case)(const gchar*));
#ifdef __cplusplus
}

View File

@ -25,11 +25,6 @@
#include <stdio.h>
#include <string.h>
#ifdef HAVE_GLIB
#include <glib.h>
#else
#include <mdbfakeglib.h>
#endif
#include <mdbtools.h>
typedef struct MdbSQL

View File

@ -18,6 +18,9 @@
#ifndef _mdbtools_h_
#define _mdbtools_h_
#define MDBTOOLS_H_HAVE_ICONV_H @HAVE_ICONV_H@
#define MDBTOOLS_H_HAVE_XLOCALE_H @HAVE_XLOCALE_H@
#ifdef __cplusplus
extern "C" {
#endif
@ -31,16 +34,13 @@
#include <ctype.h>
#include <string.h>
#include <locale.h>
#include <@GLIB_INCLUDE_HEADER@>
#ifdef HAVE_GLIB
#include <glib.h>
#else
#include <mdbfakeglib.h>
#if MDBTOOLS_H_HAVE_ICONV_H
#include <iconv.h>
#endif
#if defined(HAVE_ICONV)
#include <iconv.h>
#elif defined(HAVE_XLOCALE_H)
#if MDBTOOLS_H_HAVE_XLOCALE_H
#include <xlocale.h>
#endif
@ -67,6 +67,8 @@
// M$VC see http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc
#define MDB_DEPRECATED(type, funcname) type __attribute__((deprecated)) funcname
typedef @LOCALE_T@ mdb_locale_t;
enum {
MDB_PAGE_DB = 0,
MDB_PAGE_DATA,
@ -129,7 +131,9 @@ enum {
MDB_LTEQ,
MDB_LIKE,
MDB_ISNULL,
MDB_NOTNULL
MDB_NOTNULL,
MDB_ILIKE,
MDB_NEQ,
};
typedef enum {
@ -154,6 +158,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 )
@ -163,7 +172,9 @@ enum {
x == MDB_LT || \
x == MDB_GTEQ || \
x == MDB_LTEQ || \
x == MDB_NEQ || \
x == MDB_LIKE || \
x == MDB_ILIKE || \
x == MDB_ISNULL || \
x == MDB_NOTNULL )
@ -234,6 +245,8 @@ typedef struct {
const char *table_comment_statement;
const char *per_table_comment_statement;
gchar* (*quote_schema_name)(const gchar*, const gchar*);
const char *create_table_statement;
gchar* (*normalise_case)(const gchar*);
} MdbBackend;
typedef struct {
@ -292,6 +305,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;
@ -304,13 +318,11 @@ typedef struct {
char *relationships_values[5];
MdbStatistics *stats;
GHashTable *backends;
#ifdef HAVE_ICONV
iconv_t iconv_in;
iconv_t iconv_out;
#elif defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || defined(WINDOWS)
_locale_t locale;
#if MDBTOOLS_H_HAVE_ICONV_H
iconv_t iconv_in;
iconv_t iconv_out;
#else
locale_t locale;
mdb_locale_t locale;
#endif
} MdbHandle;
@ -524,7 +536,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);
@ -541,9 +554,11 @@ 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);
int mdb_read_next_dpg(MdbTableDef *table);
/* money.c */
char *mdb_money_to_string(MdbHandle *mdb, int start);
@ -571,6 +586,7 @@ void mdb_register_backend(MdbHandle *mdb, char *backend_name, guint32 capabiliti
int mdb_set_default_backend(MdbHandle *mdb, const char *backend_name);
int mdb_print_schema(MdbHandle *mdb, FILE *outfile, char *tabname, char *dbnamespace, guint32 export_options);
void mdb_print_col(FILE *outfile, gchar *col_val, int quote_text, int col_type, int bin_len, char *quote_char, char *escape_char, int flags);
gchar *mdb_normalise_and_replace(MdbHandle *mdb, gchar **str);
/* sargs.c */
int mdb_test_sargs(MdbTableDef *table, MdbField *fields, int num_fields);
@ -605,6 +621,7 @@ void mdb_dump_stats(MdbHandle *mdb);
/* like.c */
int mdb_like_cmp(char *s, char *r);
int mdb_ilike_cmp(char *s, char *r);
/* write.c */
void mdb_put_int16(void *buf, guint32 offset, guint32 value);

View File

@ -12,4 +12,4 @@ Description: core MDB file support library
Requires: @GLIB_PACKAGE@
Version: @VERSION@
Libs: -L${libdir} -lmdb
Cflags: @MDBTOOLS_CFLAGS@
Cflags: -I${includedir}

View File

@ -12,5 +12,4 @@ Description: libmdb based SQL engine
Requires: libmdb
Version: @VERSION@
Libs: -L${libdir} -lmdbsql
Cflags:
Cflags: -I${includedir}

71
m4/ax_tls.m4 Normal file
View File

@ -0,0 +1,71 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_tls.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_TLS([action-if-found], [action-if-not-found])
#
# DESCRIPTION
#
# Provides a test for the compiler support of thread local storage (TLS)
# extensions. Defines TLS if it is found. Currently knows about C++11,
# GCC/ICC, and MSVC. I think SunPro uses the same as GCC, and Borland
# apparently supports either.
#
# LICENSE
#
# Copyright (c) 2008 Alan Woodland <ajw05@aber.ac.uk>
# Copyright (c) 2010 Diego Elio Petteno` <flameeyes@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program 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 General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 15
AC_DEFUN([AX_TLS], [
AC_MSG_CHECKING([for thread local storage (TLS) class])
AC_CACHE_VAL([ac_cv_tls],
[for ax_tls_keyword in thread_local _Thread_local __thread '__declspec(thread)' none; do
AS_CASE([$ax_tls_keyword],
[none], [ac_cv_tls=none ; break],
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
[#include <stdlib.h>],
[static $ax_tls_keyword int bar;]
)],
[ac_cv_tls=$ax_tls_keyword ; break],
[ac_cv_tls=none]
)]
)
done ]
)
AC_MSG_RESULT([$ac_cv_tls])
AS_IF([test "$ac_cv_tls" != "none"],
[AC_DEFINE_UNQUOTED([TLS],[$ac_cv_tls],[If the compiler supports a TLS storage class, define it to that here])
m4_ifnblank([$1],[$1],[[:]])],
[m4_ifnblank([$2],[$2],[[:]])])
])

View File

@ -1,11 +1,18 @@
# iconv.m4 serial 19 (gettext-0.18.2)
dnl Copyright (C) 2000-2002, 2007-2014, 2016 Free Software Foundation, Inc.
# iconv.m4 serial 24
dnl Copyright (C) 2000-2002, 2007-2014, 2016-2021 Free Software Foundation,
dnl Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl From Bruno Haible.
AC_PREREQ([2.64])
dnl Note: AM_ICONV is documented in the GNU gettext manual
dnl <https://www.gnu.org/software/gettext/manual/html_node/AM_005fICONV.html>.
dnl Don't make changes that are incompatible with that documentation!
AC_DEFUN([AM_ICONV_LINKFLAGS_BODY],
[
dnl Prerequisites of AC_LIB_LINKFLAGS_BODY.
@ -85,8 +92,9 @@ AC_DEFUN([AM_ICONV_LINK],
#endif
]],
[[int result = 0;
/* Test against AIX 5.1 bug: Failures are not distinguishable from successful
returns. */
/* Test against AIX 5.1...7.2 bug: Failures are not distinguishable from
successful returns. This is even documented in
<https://www.ibm.com/support/knowledgecenter/ssw_aix_72/i_bostechref/iconv.html> */
{
iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8");
if (cd_utf8_to_88591 != (iconv_t)(-1))
@ -167,15 +175,27 @@ AC_DEFUN([AM_ICONV_LINK],
#endif
/* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is
provided. */
if (/* Try standardized names. */
iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1)
/* Try IRIX, OSF/1 names. */
&& iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1)
/* Try AIX names. */
&& iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1)
/* Try HP-UX names. */
&& iconv_open ("utf8", "eucJP") == (iconv_t)(-1))
result |= 16;
{
/* Try standardized names. */
iconv_t cd1 = iconv_open ("UTF-8", "EUC-JP");
/* Try IRIX, OSF/1 names. */
iconv_t cd2 = iconv_open ("UTF-8", "eucJP");
/* Try AIX names. */
iconv_t cd3 = iconv_open ("UTF-8", "IBM-eucJP");
/* Try HP-UX names. */
iconv_t cd4 = iconv_open ("utf8", "eucJP");
if (cd1 == (iconv_t)(-1) && cd2 == (iconv_t)(-1)
&& cd3 == (iconv_t)(-1) && cd4 == (iconv_t)(-1))
result |= 16;
if (cd1 != (iconv_t)(-1))
iconv_close (cd1);
if (cd2 != (iconv_t)(-1))
iconv_close (cd2);
if (cd3 != (iconv_t)(-1))
iconv_close (cd3);
if (cd4 != (iconv_t)(-1))
iconv_close (cd4);
}
return result;
]])],
[am_cv_func_iconv_works=yes], ,
@ -212,8 +232,7 @@ AC_DEFUN([AM_ICONV_LINK],
AC_SUBST([LTLIBICONV])
])
dnl Define AM_ICONV using AC_DEFUN_ONCE for Autoconf >= 2.64, in order to
dnl avoid warnings like
dnl Define AM_ICONV using AC_DEFUN_ONCE, in order to avoid warnings like
dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required".
dnl This is tricky because of the way 'aclocal' is implemented:
dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN.
@ -221,51 +240,44 @@ dnl Otherwise aclocal's initial scan pass would miss the macro definition.
dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions.
dnl Otherwise aclocal would emit many "Use of uninitialized value $1"
dnl warnings.
m4_define([gl_iconv_AC_DEFUN],
m4_version_prereq([2.64],
[[AC_DEFUN_ONCE(
[$1], [$2])]],
[m4_ifdef([gl_00GNULIB],
[[AC_DEFUN_ONCE(
[$1], [$2])]],
[[AC_DEFUN(
[$1], [$2])]])]))
gl_iconv_AC_DEFUN([AM_ICONV],
AC_DEFUN_ONCE([AM_ICONV],
[
AM_ICONV_LINK
if test "$am_cv_func_iconv" = yes; then
AC_MSG_CHECKING([for iconv declaration])
AC_CACHE_VAL([am_cv_proto_iconv], [
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[
AC_CACHE_CHECK([whether iconv is compatible with its POSIX signature],
[gl_cv_iconv_nonconst],
[AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[
#include <stdlib.h>
#include <iconv.h>
extern
#ifdef __cplusplus
"C"
#endif
#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus)
size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
#else
size_t iconv();
#endif
]],
[[]])],
[am_cv_proto_iconv_arg1=""],
[am_cv_proto_iconv_arg1="const"])
am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
AC_MSG_RESULT([
$am_cv_proto_iconv])
AC_DEFINE_UNQUOTED([ICONV_CONST], [$am_cv_proto_iconv_arg1],
[Define as const if the declaration of iconv() needs const.])
dnl Also substitute ICONV_CONST in the gnulib generated <iconv.h>.
m4_ifdef([gl_ICONV_H_DEFAULTS],
[AC_REQUIRE([gl_ICONV_H_DEFAULTS])
if test -n "$am_cv_proto_iconv_arg1"; then
ICONV_CONST="const"
fi
]],
[[]])],
[gl_cv_iconv_nonconst=yes],
[gl_cv_iconv_nonconst=no])
])
else
dnl When compiling GNU libiconv on a system that does not have iconv yet,
dnl pick the POSIX compliant declaration without 'const'.
gl_cv_iconv_nonconst=yes
fi
if test $gl_cv_iconv_nonconst = yes; then
iconv_arg1=""
else
iconv_arg1="const"
fi
AC_DEFINE_UNQUOTED([ICONV_CONST], [$iconv_arg1],
[Define as const if the declaration of iconv() needs const.])
dnl Also substitute ICONV_CONST in the gnulib generated <iconv.h>.
m4_ifdef([gl_ICONV_H_DEFAULTS],
[AC_REQUIRE([gl_ICONV_H_DEFAULTS])
if test $gl_cv_iconv_nonconst != yes; then
ICONV_CONST="const"
fi
])
])

View File

@ -33,6 +33,10 @@ int main(int argc, char **argv)
fprintf(stderr, "Usage: mdb-dump <filename> [<page number>]\n\n");
exit(1);
}
fputs("mdb-hexdump 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) {
if (!strncmp(argv[2],"0x",2)) {
for (i=2;i<strlen(argv[2]);i++) {
@ -89,4 +93,4 @@ int main(int argc, char **argv)
exit(0);
}
/** @}*/
/** @}*/

View File

@ -21,6 +21,7 @@
*/
#include "mdbtools.h"
#include "mdbprivate.h"
/* Access data types */
static const MdbBackendType mdb_access_types[] = {
@ -82,7 +83,7 @@ static const MdbBackendType mdb_sybase_shortdate_type =
/* Postgres data types */
static const MdbBackendType mdb_postgres_types[] = {
[MDB_BOOL] = { .name = "BOOL" },
[MDB_BOOL] = { .name = "BOOLEAN" },
[MDB_BYTE] = { .name = "SMALLINT" },
[MDB_INT] = { .name = "INTEGER" },
[MDB_LONGINT] = { .name = "INTEGER" }, /* bigint */
@ -155,6 +156,37 @@ enum {
static void mdb_drop_backend(gpointer key, gpointer value, gpointer data);
static gchar *passthrough_unchanged(const gchar *str) {
return (gchar *)str;
}
static gchar *to_lower_case(const gchar *str) {
return g_utf8_strdown(str, -1);
}
/**
* Convenience function to replace an input string with its database specific normalised version.
*
* This function throws away the input string after normalisation, freeing its memory, and replaces it with a new
* normalised version allocated on the stack.
*
* @param mdb Database specific MDB handle containing pointers to utility methods
* @param str string to normalise
* @return a pointer to the normalised version of the input string
*/
gchar *mdb_normalise_and_replace(MdbHandle *mdb, gchar **str) {
gchar *normalised_str = mdb->default_backend->normalise_case(*str);
if (normalised_str != *str) {
/* Free and replace the old string only and only if a new string was created at a different memory location
* so that we can account for the case where strings a just passed through unchanged.
*/
free(*str);
*str = normalised_str;
}
return *str;
}
static gchar*
quote_generic(const gchar *value, gchar quote_char, gchar escape_char) {
gchar *result, *pr;
@ -262,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;
}
@ -338,20 +370,22 @@ void mdb_init_backends(MdbHandle *mdb)
"COMMENT ON TABLE %s IS %s;\n",
NULL,
quote_schema_name_dquote);
mdb_register_backend(mdb, "postgres",
mdbi_register_backend2(mdb, "postgres",
MDB_SHEXP_DROPTABLE|MDB_SHEXP_CST_NOTNULL|MDB_SHEXP_CST_NOTEMPTY|MDB_SHEXP_COMMENTS|MDB_SHEXP_INDEXES|MDB_SHEXP_RELATIONS|MDB_SHEXP_DEFVALUES|MDB_SHEXP_BULK_INSERT,
mdb_postgres_types, &mdb_postgres_shortdate_type, &mdb_postgres_serial_type,
"current_date", "now()",
"%Y-%m-%d %H:%M:%S",
"%Y-%m-%d",
"SET client_encoding = '%s';\n",
"CREATE TABLE IF NOT EXISTS %s\n",
"DROP TABLE IF EXISTS %s;\n",
"ALTER TABLE %s ADD CHECK (%s <>'');\n",
"COMMENT ON COLUMN %s.%s IS %s;\n",
NULL,
"COMMENT ON TABLE %s IS %s;\n",
NULL,
quote_schema_name_dquote);
quote_schema_name_dquote,
to_lower_case);
mdb_register_backend(mdb, "mysql",
MDB_SHEXP_DROPTABLE|MDB_SHEXP_CST_NOTNULL|MDB_SHEXP_CST_NOTEMPTY|MDB_SHEXP_INDEXES|MDB_SHEXP_RELATIONS|MDB_SHEXP_DEFVALUES|MDB_SHEXP_BULK_INSERT,
mdb_mysql_types, &mdb_mysql_shortdate_type, &mdb_mysql_serial_type,
@ -382,18 +416,20 @@ void mdb_init_backends(MdbHandle *mdb)
quote_schema_name_rquotes_merge);
}
void mdb_register_backend(MdbHandle *mdb, char *backend_name, guint32 capabilities,
MdbBackend *mdbi_register_backend2(MdbHandle *mdb, char *backend_name, guint32 capabilities,
const MdbBackendType *backend_type, const MdbBackendType *type_shortdate, const MdbBackendType *type_autonum,
const char *short_now, const char *long_now,
const char *date_fmt, const char *shortdate_fmt,
const char *charset_statement, const char *drop_statement,
const char *constaint_not_empty_statement,
const char *charset_statement,
const char *create_table_statement,
const char *drop_statement,
const char *constraint_not_empty_statement,
const char *column_comment_statement,
const char *per_column_comment_statement,
const char *per_column_comment_statement,
const char *table_comment_statement,
const char *per_table_comment_statement,
gchar* (*quote_schema_name)(const gchar*, const gchar*))
{
gchar* (*quote_schema_name)(const gchar*, const gchar*),
gchar* (*normalise_case)(const gchar*)) {
MdbBackend *backend = g_malloc0(sizeof(MdbBackend));
backend->capabilities = capabilities;
backend->types_table = backend_type;
@ -404,14 +440,46 @@ void mdb_register_backend(MdbHandle *mdb, char *backend_name, guint32 capabiliti
backend->date_fmt = date_fmt;
backend->shortdate_fmt = shortdate_fmt;
backend->charset_statement = charset_statement;
backend->create_table_statement = create_table_statement;
backend->drop_statement = drop_statement;
backend->constaint_not_empty_statement = constaint_not_empty_statement;
backend->constaint_not_empty_statement = constraint_not_empty_statement;
backend->column_comment_statement = column_comment_statement;
backend->per_column_comment_statement = per_column_comment_statement;
backend->table_comment_statement = table_comment_statement;
backend->per_table_comment_statement = per_table_comment_statement;
backend->quote_schema_name = quote_schema_name;
backend->normalise_case = normalise_case;
g_hash_table_insert(mdb->backends, backend_name, backend);
return backend;
}
void mdb_register_backend(MdbHandle *mdb, char *backend_name, guint32 capabilities,
const MdbBackendType *backend_type, const MdbBackendType *type_shortdate, const MdbBackendType *type_autonum,
const char *short_now, const char *long_now,
const char *date_fmt, const char *shortdate_fmt,
const char *charset_statement,
const char *drop_statement,
const char *constraint_not_empty_statement,
const char *column_comment_statement,
const char *per_column_comment_statement,
const char *table_comment_statement,
const char *per_table_comment_statement,
gchar* (*quote_schema_name)(const gchar*, const gchar*))
{
mdbi_register_backend2(mdb, backend_name, capabilities,
backend_type, type_shortdate, type_autonum,
short_now, long_now,
date_fmt, shortdate_fmt,
charset_statement,
"CREATE TABLE %s\n",
drop_statement,
constraint_not_empty_statement,
column_comment_statement,
per_column_comment_statement,
table_comment_statement,
per_table_comment_statement,
quote_schema_name,
passthrough_unchanged);
}
/**
@ -539,6 +607,7 @@ mdb_print_indexes(FILE* outfile, MdbTableDef *table, char *dbnamespace)
fprintf (outfile, "-- CREATE INDEXES ...\n");
quoted_table_name = mdb->default_backend->quote_schema_name(dbnamespace, table->name);
quoted_table_name = mdb->default_backend->normalise_case(quoted_table_name);
for (i=0;i<table->num_idxs;i++) {
idx = g_ptr_array_index (table->indices, i);
@ -560,6 +629,8 @@ mdb_print_indexes(FILE* outfile, MdbTableDef *table, char *dbnamespace)
quoted_name = mdb->default_backend->quote_schema_name(dbnamespace, index_name);
}
quoted_name = mdb_normalise_and_replace(mdb, &quoted_name);
if (idx->index_type==1) {
switch (backend) {
case MDB_BACKEND_ORACLE:
@ -595,6 +666,7 @@ mdb_print_indexes(FILE* outfile, MdbTableDef *table, char *dbnamespace)
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 */
@ -702,8 +774,11 @@ mdb_get_relationships(MdbHandle *mdb, const gchar *dbnamespace, const char* tabl
* be namespaced.
*/
quoted_constraint_name = mdb->default_backend->quote_schema_name(NULL, constraint_name);
quoted_constraint_name = mdb_normalise_and_replace(mdb, &quoted_constraint_name);
quoted_column_1 = mdb->default_backend->quote_schema_name(NULL, bound[0]);
quoted_column_1 = mdb_normalise_and_replace(mdb, &quoted_column_1);
quoted_column_2 = mdb->default_backend->quote_schema_name(NULL, bound[2]);
quoted_column_2 = mdb_normalise_and_replace(mdb, &quoted_column_2);
break;
default:
@ -786,13 +861,14 @@ generate_table_schema(FILE *outfile, MdbCatalogEntry *entry, char *dbnamespace,
const char *prop_value;
quoted_table_name = mdb->default_backend->quote_schema_name(dbnamespace, entry->object_name);
quoted_table_name = mdb_normalise_and_replace(mdb, &quoted_table_name);
/* drop the table if it exists */
if (export_options & MDB_SHEXP_DROPTABLE)
fprintf (outfile, mdb->default_backend->drop_statement, quoted_table_name);
/* create the table */
fprintf (outfile, "CREATE TABLE %s\n", quoted_table_name);
fprintf (outfile, mdb->default_backend->create_table_statement, quoted_table_name);
fprintf (outfile, " (\n");
table = mdb_read_table (entry);
@ -805,6 +881,7 @@ generate_table_schema(FILE *outfile, MdbCatalogEntry *entry, char *dbnamespace,
col = g_ptr_array_index (table->columns, i);
quoted_name = mdb->default_backend->quote_schema_name(NULL, col->name);
quoted_name = mdb_normalise_and_replace(mdb, &quoted_name);
fprintf (outfile, "\t%s\t\t\t%s", quoted_name,
mdb_get_colbacktype_string (col));
g_free(quoted_name);
@ -907,6 +984,7 @@ generate_table_schema(FILE *outfile, MdbCatalogEntry *entry, char *dbnamespace,
continue;
quoted_name = mdb->default_backend->quote_schema_name(NULL, col->name);
quoted_name = mdb_normalise_and_replace(mdb, &quoted_name);
if (export_options & MDB_SHEXP_CST_NOTEMPTY) {
prop_value = mdb_col_get_prop(col, "AllowZeroLength");

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

@ -18,7 +18,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define _GNU_SOURCE
#include "mdbfakeglib.h"
#include <stddef.h>
@ -28,6 +27,7 @@
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <wctype.h>
#ifdef HAVE_ICONV
#include <iconv.h>
#endif
@ -243,11 +243,16 @@ gchar *g_locale_to_utf8(const gchar *opsysstring, size_t len,
size_t *bytes_read, size_t *bytes_written, GError **error) {
if (len == (size_t)-1)
len = strlen(opsysstring);
wchar_t *utf16 = malloc(sizeof(wchar_t)*(len+1));
if (mbstowcs(utf16, opsysstring, len+1) == (size_t)-1) {
free(utf16);
return g_strndup(opsysstring, len);
size_t wlen = mbstowcs(NULL, opsysstring, 0);
if (wlen == (size_t)-1) {
if (error) {
*error = malloc(sizeof(GError));
(*error)->message = g_strdup_printf("Invalid multibyte string: %s\n", opsysstring);
}
return NULL;
}
wchar_t *utf16 = malloc(sizeof(wchar_t)*(wlen+1));
mbstowcs(utf16, opsysstring, wlen+1);
gchar *utf8 = malloc(3*len+1);
gchar *dst = utf8;
for (size_t i=0; i<len; i++) {
@ -259,6 +264,34 @@ gchar *g_locale_to_utf8(const gchar *opsysstring, size_t len,
return utf8;
}
gchar *g_utf8_casefold(const gchar *str, gssize len) {
return g_utf8_strdown(str, len);
}
gchar *g_utf8_strdown(const gchar *str, gssize len) {
gssize i = 0;
if (len == -1)
len = strlen(str);
gchar *lower = malloc(len+1);
while (i<len) {
wchar_t u = 0;
uint8_t c = str[i];
if ((c & 0xF0) == 0xE0) {
u = (c & 0x0F) << 12;
u += (str[i+1] & 0x3F) << 6;
u += (str[i+2] & 0x3F);
} else if ((c & 0xE0) == 0xC0) {
u = (c & 0x1F) << 6;
u += (str[i+1] & 0x3F);
} else {
u = (c & 0x7F);
}
i += g_unichar_to_utf8(towlower(u), &lower[i]);
}
lower[len] = '\0';
return lower;
}
/* GHashTable */
typedef struct MyNode {
@ -522,11 +555,10 @@ gboolean g_option_context_parse(GOptionContext *context,
while ((c = getopt_long(*argc, *argv, short_opts, long_opts, &longindex)) != -1) {
if (c == '?') {
*error = malloc(sizeof(GError));
(*error)->message = malloc(100);
if (optopt) {
snprintf((*error)->message, 100, "Unrecognized option: -%c", optopt);
(*error)->message = g_strdup_printf("Unrecognized option: -%c", optopt);
} else {
snprintf((*error)->message, 100, "Unrecognized option: %s", (*argv)[optind-1]);
(*error)->message = g_strdup_printf("Unrecognized option: %s", (*argv)[optind-1]);
}
free(short_opts);
free(long_opts);

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,6 +316,12 @@ MdbHandle *mdb_clone_handle(MdbHandle *mdb)
mdb_iconv_init(newmdb);
mdb_set_default_backend(newmdb, mdb->backend_name);
// 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++;
}
@ -374,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 };
@ -407,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)
{
@ -419,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)
{
@ -435,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)
@ -449,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;
@ -463,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

@ -46,7 +46,7 @@ static size_t decompress_unicode(const char *src, size_t slen, char *dst, size_t
return tlen;
}
#if HAVE_ICONV
#ifdef HAVE_ICONV
static size_t decompressed_to_utf8_with_iconv(MdbHandle *mdb, const char *in_ptr, size_t len_in, char *dest, size_t dlen) {
char *out_ptr = dest;
size_t len_out = dlen - 1;
@ -88,15 +88,7 @@ static size_t latin1_to_utf8_without_iconv(const char *in_ptr, size_t len_in, ch
return out - dest;
}
static size_t decompressed_to_utf8_without_iconv(MdbHandle *mdb, const char *in_ptr, size_t len_in, char *dest, size_t dlen) {
if (IS_JET3(mdb)) {
if (mdb->f->code_page == 1252) {
return latin1_to_utf8_without_iconv(in_ptr, len_in, dest, dlen);
}
int count = 0;
snprintf(dest, dlen, "%.*s%n", (int)len_in, in_ptr, &count);
return count;
}
static size_t unicode2ascii_locale(mdb_locale_t locale, const char *in_ptr, size_t len_in, char *dest, size_t dlen) {
size_t i;
size_t count = 0;
size_t len_out = dlen - 1;
@ -109,11 +101,11 @@ static size_t decompressed_to_utf8_without_iconv(MdbHandle *mdb, const char *in_
w[len_in/2] = '\0';
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || defined(WINDOWS)
count = _wcstombs_l(dest, w, len_out, mdb->locale);
count = _wcstombs_l(dest, w, len_out, locale);
#elif defined(HAVE_WCSTOMBS_L)
count = wcstombs_l(dest, w, len_out, mdb->locale);
count = wcstombs_l(dest, w, len_out, locale);
#else
locale_t oldlocale = uselocale(mdb->locale);
locale_t oldlocale = uselocale(locale);
count = wcstombs(dest, w, len_out);
uselocale(oldlocale);
#endif
@ -124,6 +116,18 @@ static size_t decompressed_to_utf8_without_iconv(MdbHandle *mdb, const char *in_
dest[count] = '\0';
return count;
}
static size_t decompressed_to_utf8_without_iconv(MdbHandle *mdb, const char *in_ptr, size_t len_in, char *dest, size_t dlen) {
if (IS_JET3(mdb)) {
if (mdb->f->code_page == 1252) {
return latin1_to_utf8_without_iconv(in_ptr, len_in, dest, dlen);
}
int count = 0;
snprintf(dest, dlen, "%.*s%n", (int)len_in, in_ptr, &count);
return count;
}
return unicode2ascii_locale(mdb->locale, in_ptr, len_in, dest, dlen);
}
#endif
/*
@ -153,7 +157,7 @@ mdb_unicode2ascii(MdbHandle *mdb, const char *src, size_t slen, char *dest, size
in_ptr = src;
}
#if HAVE_ICONV
#ifdef HAVE_ICONV
dlen = decompressed_to_utf8_with_iconv(mdb, in_ptr, len_in, dest, dlen);
#else
dlen = decompressed_to_utf8_without_iconv(mdb, in_ptr, len_in, dest, dlen);

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);
@ -1014,7 +1017,7 @@ int mdb_index_compute_cost(MdbTableDef *table, MdbIndex *idx)
/*
* a like with a wild card first is useless as a sarg */
if (sarg->op == MDB_LIKE && sarg->value.s[0]=='%')
if ((sarg->op == MDB_LIKE || sarg->op == MDB_ILIKE) && sarg->value.s[0]=='%')
return 0;
/*
@ -1027,6 +1030,7 @@ int mdb_index_compute_cost(MdbTableDef *table, MdbIndex *idx)
case MDB_EQUAL:
return 1; break;
case MDB_LIKE:
case MDB_ILIKE:
return 4; break;
case MDB_ISNULL:
return 12; break;
@ -1040,6 +1044,7 @@ int mdb_index_compute_cost(MdbTableDef *table, MdbIndex *idx)
else return 1;
break;
case MDB_LIKE:
case MDB_ILIKE:
return 6; break;
case MDB_ISNULL:
return 12; break;
@ -1053,6 +1058,7 @@ int mdb_index_compute_cost(MdbTableDef *table, MdbIndex *idx)
case MDB_EQUAL:
return 2; break;
case MDB_LIKE:
case MDB_ILIKE:
return 5; break;
case MDB_ISNULL:
return 12; break;
@ -1066,6 +1072,7 @@ int mdb_index_compute_cost(MdbTableDef *table, MdbIndex *idx)
else return 2;
break;
case MDB_LIKE:
case MDB_ILIKE:
return 7; break;
case MDB_ISNULL:
return 12; break;

View File

@ -39,11 +39,7 @@ int mdb_like_cmp(char *s, char *r)
mdb_debug(MDB_DEBUG_LIKE, "comparing %s and %s", s, r);
switch (r[0]) {
case '\0':
if (s[0]=='\0') {
return 1;
} else {
return 0;
}
return (s[0]=='\0');
case '_':
/* skip one character */
return mdb_like_cmp(&s[1],&r[1]);
@ -71,3 +67,25 @@ int mdb_like_cmp(char *s, char *r)
}
}
}
/**
*
* @param s: String to search within.
* @param r: Case-insensitive search pattern.
*
* Tests the string @s to see if it matches the search pattern @r without
* regard to case; this mimics the behavior of the Access LIKE operator. In the
* search pattern, a percent sign indicates matching on any number of
* characters, and an underscore indicates matching any single character.
*
* @Returns: 1 if the string matches, 0 if the string does not match.
*/
int mdb_ilike_cmp(char *s, char *r) {
char *s1 = g_utf8_casefold(s, -1);
char *r1 = g_utf8_casefold(r, -1);
int result = mdb_like_cmp(s1, r1);
g_free(s1);
g_free(r1);
return result;
}

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

@ -47,6 +47,9 @@ int rc;
if (node->op == MDB_LIKE) {
return mdb_like_cmp(s,node->value.s);
}
if (node->op == MDB_ILIKE) {
return mdb_ilike_cmp(s,node->value.s);
}
rc = strcoll(node->value.s, s);
switch (node->op) {
case MDB_EQUAL:
@ -64,6 +67,9 @@ int rc;
case MDB_LTEQ:
if (rc>=0) return 1;
break;
case MDB_NEQ:
if (rc!=0) return 1;
break;
default:
fprintf(stderr, "Calling mdb_test_sarg on unknown operator. Add code to mdb_test_string() for operator %d\n",node->op);
break;
@ -72,22 +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 (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);
@ -126,6 +136,9 @@ int mdb_test_double(int op, double vd, double d)
case MDB_LTEQ:
ret = (vd >= d);
break;
case MDB_NEQ:
ret = (vd != d);
break;
default:
fprintf(stderr, "Calling mdb_test_sarg on unknown operator. Add code to mdb_test_double() for operator %d\n",op);
break;
@ -232,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

@ -2,16 +2,17 @@ AUTOMAKE_OPTIONS = subdir-objects
noinst_PROGRAMS = unittest
noinst_HEADERS = connectparams.h mdbodbc.h
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)
if ICONV
lib_LTLIBRARIES += libmdbodbcW.la
libmdbodbcW_la_SOURCES = $(libmdbodbc_la_SOURCES)
libmdbodbcW_la_LIBADD = $(libmdbodbc_la_LIBADD) @LIBICONV@
libmdbodbcW_la_SOURCES = $(libmdbodbc_la_SOURCES) odbcw.c
libmdbodbcW_la_LIBADD = $(libmdbodbc_la_LIBADD)
libmdbodbcW_la_LDFLAGS = $(libmdbodbc_la_LDFLAGS)
libmdbodbcW_la_CFLAGS = $(AM_CFLAGS) -D ENABLE_ODBC_W=1
endif
LIBS = $(GLIB_LIBS)
unittest_LDADD = libmdbodbc.la ../libmdb/libmdb.la ../sql/libmdbsql.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';
@ -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
@ -50,10 +50,7 @@ struct _hdbc {
GPtrArray *statements;
char lastError[256];
char sqlState[6];
#ifdef ENABLE_ODBC_W
iconv_t iconv_in;
iconv_t iconv_out;
#endif
mdb_locale_t locale;
};
struct _hstmt {
MdbSQL *sql;
@ -81,8 +78,12 @@ struct _sql_bind_info {
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
#endif
/** @}*/
/** @}*/

View File

@ -16,11 +16,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef ENABLE_ODBC_W
#define SQL_NOUNICODEMAP
#define UNICODE
#endif //ENABLE_ODBC_W
#include <sql.h>
#include <sqlext.h>
#include <string.h>
@ -85,64 +80,6 @@ TypeInfo type_info[] = {
#define NUM_TYPE_INFO_COLS 19
#define MAX_TYPE_INFO 11
#ifdef ENABLE_ODBC_W
static void _init_iconv(struct _hdbc* dbc)
{
TRACE("_init_iconv");
int endian = 1;
const char* wcharset;
if (sizeof(SQLWCHAR) == 2)
if (*(char*)&endian == 1)
wcharset = "UCS-2LE";
else
wcharset = "UCS-2BE";
else if (sizeof(SQLWCHAR) == 4)
if (*(char*)&endian == 1)
wcharset = "UCS-4LE";
else
wcharset = "UCS-4BE";
else
fprintf(stderr, "Unsupported SQLWCHAR width %zd\n", sizeof(SQLWCHAR));
dbc->iconv_out = iconv_open(wcharset, "UTF-8");
dbc->iconv_in = iconv_open("UTF-8", wcharset);
}
static void _free_iconv(struct _hdbc *dbc)
{
TRACE("_free_iconv");
if(dbc->iconv_out != (iconv_t)-1)iconv_close(dbc->iconv_out);
if(dbc->iconv_in != (iconv_t)-1)iconv_close(dbc->iconv_in);
}
static int unicode2ascii(struct _hdbc* dbc, char *_in, size_t *_lin, char *_out, size_t *_lout){
char *in=_in, *out=_out;
size_t lin=*_lin, lout=*_lout;
int ret = iconv(dbc->iconv_in, &in, &lin, &out, &lout);
*_lin -= lin;
*_lout -= lout;
return ret;
}
static int ascii2unicode(struct _hdbc* dbc, char *_in, size_t *_lin, char *_out, size_t *_lout){
//fprintf(stderr,"ascii2unicode %08x %08x %08x %08x\n",_in,_lin,_out,_lout);
char *in=_in, *out=_out;
size_t lin=*_lin, lout=*_lout;
//fprintf(stderr,"ascii2unicode %zd %zd\n",lin,lout);
int ret = iconv(dbc->iconv_out, &in, &lin, &out, &lout);
*_lin -= lin;
*_lout -= lout;
return ret;
}
static int sqlwlen(SQLWCHAR *p){
int r=0;
for(;*p;r++)
p++;
return r;
}
#endif // ENABLE_ODBC_W
static void LogHandleError(struct _hdbc* dbc, const char* format, ...)
{
va_list argp;
@ -171,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,
@ -213,36 +173,6 @@ SQLRETURN SQL_API SQLDriverConnect(
return SQL_ERROR;
}
#ifdef ENABLE_ODBC_W
SQLRETURN SQL_API SQLDriverConnectW(
SQLHDBC hdbc,
SQLHWND hwnd,
SQLWCHAR *szConnStrIn,
SQLSMALLINT cbConnStrIn,
SQLWCHAR *szConnStrOut,
SQLSMALLINT cbConnStrOutMax,
SQLSMALLINT *pcbConnStrOut,
SQLUSMALLINT fDriverCompletion)
{
TRACE("SQLDriverConnectW");
if(cbConnStrIn==SQL_NTS)cbConnStrIn=sqlwlen(szConnStrIn);
{
size_t l = cbConnStrIn*sizeof(SQLWCHAR), z = (cbConnStrIn+1)*3;
SQLCHAR *tmp = malloc(z);
SQLRETURN ret;
unicode2ascii((struct _hdbc *)hdbc, (char*)szConnStrIn, &l, (char*)tmp, &z);
tmp[z] = 0;
ret = SQLDriverConnect(hdbc,hwnd,tmp,SQL_NTS,NULL,0,pcbConnStrOut,fDriverCompletion);
free(tmp);
if (szConnStrOut && cbConnStrOutMax>0)
szConnStrOut[0] = 0;
if (pcbConnStrOut)
*pcbConnStrOut = 0;
return ret;
}
}
#endif // ENABLE_ODBC_W
SQLRETURN SQL_API SQLBrowseConnect(
SQLHDBC hdbc,
SQLCHAR *szConnStrIn,
@ -498,8 +428,10 @@ struct _hdbc* dbc;
dbc->params = NewConnectParams ();
dbc->statements = g_ptr_array_new();
dbc->sqlconn = mdb_sql_init();
#ifdef ENABLE_ODBC_W
_init_iconv(dbc);
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || defined(WINDOWS)
dbc->locale = _create_locale(LC_CTYPE, ".65001");
#else
dbc->locale = newlocale(LC_CTYPE_MASK, "C.UTF-8", NULL);
#endif
*phdbc=dbc;
@ -645,36 +577,6 @@ SQLRETURN SQL_API SQLConnect(
return ret;
}
#ifdef ENABLE_ODBC_W
SQLRETURN SQL_API SQLConnectW(
SQLHDBC hdbc,
SQLWCHAR *szDSN,
SQLSMALLINT cbDSN,
SQLWCHAR *szUID,
SQLSMALLINT cbUID,
SQLWCHAR *szAuthStr,
SQLSMALLINT cbAuthStr)
{
TRACE("SQLConnectW");
if(cbDSN==SQL_NTS)cbDSN=sqlwlen(szDSN);
if(cbUID==SQL_NTS)cbUID=sqlwlen(szUID);
if(cbAuthStr==SQL_NTS)cbAuthStr=sqlwlen(szAuthStr);
{
SQLCHAR *tmp1=calloc(cbDSN*4,1),*tmp2=calloc(cbUID*4,1),*tmp3=calloc(cbAuthStr*4,1);
size_t l1=cbDSN*4,z1=cbDSN*2;
size_t l2=cbUID*4,z2=cbUID*2;
size_t l3=cbAuthStr*4,z3=cbAuthStr*2;
SQLRETURN ret;
unicode2ascii((struct _hdbc *)hdbc, (char*)szDSN, &z1, (char*)tmp1, &l1);
unicode2ascii((struct _hdbc *)hdbc, (char*)szUID, &z2, (char*)tmp2, &l2);
unicode2ascii((struct _hdbc *)hdbc, (char*)szAuthStr, &z3, (char*)tmp3, &l3);
ret = SQLConnect(hdbc, tmp1, l1, tmp2, l2, tmp3, l3);
free(tmp1),free(tmp2),free(tmp3);
return ret;
}
}
#endif //ENABLE_ODBC_W
SQLRETURN SQL_API SQLDescribeCol(
SQLHSTMT hstmt,
SQLUSMALLINT icol,
@ -743,32 +645,6 @@ SQLRETURN SQL_API SQLDescribeCol(
return ret;
}
#ifdef ENABLE_ODBC_W
SQLRETURN SQL_API SQLDescribeColW(
SQLHSTMT hstmt,
SQLUSMALLINT icol,
SQLWCHAR *szColName,
SQLSMALLINT cbColNameMax,
SQLSMALLINT *pcbColName,
SQLSMALLINT *pfSqlType,
SQLULEN *pcbColDef, /* precision */
SQLSMALLINT *pibScale,
SQLSMALLINT *pfNullable)
{
TRACE("SQLDescribeColW");
if(cbColNameMax==SQL_NTS)cbColNameMax=sqlwlen(szColName);
{
SQLCHAR *tmp=calloc(cbColNameMax*4,1);
size_t l=cbColNameMax*4;
SQLRETURN ret = SQLDescribeCol(hstmt, icol, tmp, cbColNameMax*4, (SQLSMALLINT*)&l, pfSqlType, pcbColDef, pibScale, pfNullable);
ascii2unicode(((struct _hstmt*)hstmt)->hdbc, (char*)tmp, &l, (char*)szColName, (size_t*)pcbColName);
*pcbColName/=sizeof(SQLWCHAR);
free(tmp);
return ret;
}
}
#endif //ENABLE_ODBC_W
SQLRETURN SQL_API SQLColAttributes(
SQLHSTMT hstmt,
SQLUSMALLINT icol,
@ -874,31 +750,6 @@ SQLRETURN SQL_API SQLColAttributes(
return ret;
}
#ifdef ENABLE_ODBC_W
SQLRETURN SQL_API SQLColAttributesW(
SQLHSTMT hstmt,
SQLUSMALLINT icol,
SQLUSMALLINT fDescType,
SQLPOINTER rgbDesc,
SQLSMALLINT cbDescMax,
SQLSMALLINT *pcbDesc,
SQLLEN *pfDesc)
{
TRACE("SQLColAttributesW");
if (fDescType!=SQL_COLUMN_NAME && fDescType!=SQL_COLUMN_LABEL)
return SQLColAttributes(hstmt,icol,fDescType,rgbDesc,cbDescMax,pcbDesc,pfDesc);
else{
SQLCHAR *tmp=calloc(cbDescMax*4,1);
size_t l=cbDescMax*4;
SQLRETURN ret=SQLColAttributes(hstmt,icol,fDescType,tmp,cbDescMax*4,(SQLSMALLINT*)&l,pfDesc);
ascii2unicode(((struct _hstmt *)hstmt)->hdbc, (char*)tmp, &l, (char*)rgbDesc, (size_t*)pcbDesc);
*pcbDesc/=sizeof(SQLWCHAR);
free(tmp);
return ret;
}
}
#endif //ENABLE_ODBC_W
SQLRETURN SQL_API SQLDisconnect(
SQLHDBC hdbc)
{
@ -958,39 +809,6 @@ SQLRETURN SQL_API SQLError(
return result;
}
#ifdef ENABLE_ODBC_W
SQLRETURN SQL_API SQLErrorW(
SQLHENV henv,
SQLHDBC hdbc,
SQLHSTMT hstmt,
SQLWCHAR *szSqlState,
SQLINTEGER *pfNativeError,
SQLWCHAR *szErrorMsg,
SQLSMALLINT cbErrorMsgMax,
SQLSMALLINT *pcbErrorMsg)
{
SQLCHAR szSqlState8[6];
SQLCHAR szErrorMsg8[3*cbErrorMsgMax+1];
SQLSMALLINT pcbErrorMsg8;
SQLRETURN result;
TRACE("SQLErrorW");
result = SQLError(henv, hdbc, hstmt, szSqlState8, pfNativeError, szErrorMsg8, 3*cbErrorMsgMax+1, &pcbErrorMsg8);
if (result == SQL_SUCCESS) {
struct _hdbc *dbc = hstmt ? ((struct _hstmt *)hstmt)->hdbc : hdbc;
size_t lin=6, lout=6*sizeof(SQLWCHAR);
ascii2unicode(dbc, (char*)szSqlState8, &lin, (char*)szSqlState, &lout);
lin = pcbErrorMsg8;
lout = cbErrorMsgMax;
ascii2unicode(dbc, (char*)szErrorMsg8, &lin, (char*)szErrorMsg, &lout);
if (pcbErrorMsg)
*pcbErrorMsg = lout;
}
return result;
}
#endif // ENABLE_ODBC_W
SQLRETURN SQL_API SQLExecute(SQLHSTMT hstmt)
{
struct _hstmt *stmt = (struct _hstmt *) hstmt;
@ -1021,27 +839,6 @@ SQLRETURN SQL_API SQLExecDirect(
return SQLExecute(hstmt);
}
#ifdef ENABLE_ODBC_W
SQLRETURN SQL_API SQLExecDirectW(
SQLHSTMT hstmt,
SQLWCHAR *szSqlStr,
SQLINTEGER cbSqlStr)
{
TRACE("SQLExecDirectW");
if(cbSqlStr==SQL_NTS)cbSqlStr=sqlwlen(szSqlStr);
{
SQLCHAR *tmp=calloc(cbSqlStr*4,1);
size_t l=cbSqlStr*4,z=cbSqlStr*2;
SQLRETURN ret;
unicode2ascii(((struct _hstmt *)hstmt)->hdbc, (char*)szSqlStr, &z, (char*)tmp, &l);
ret = SQLExecDirect(hstmt, tmp, l);
TRACE("SQLExecDirectW end");
free(tmp);
return ret;
}
}
#endif // ENABLE_ODBC_W
static void
unbind_columns(struct _hstmt *stmt)
{
@ -1059,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;
}
@ -1111,8 +908,10 @@ SQLRETURN SQL_API SQLFreeConnect(
FreeConnectParams(dbc->params);
g_ptr_array_free(dbc->statements, TRUE);
mdb_sql_exit(dbc->sqlconn);
#ifdef ENABLE_ODBC_W
_free_iconv(dbc);
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || defined(WINDOWS)
if (dbc->locale) _free_locale(dbc->locale);
#else
if (dbc->locale) freelocale(dbc->locale);
#endif
g_free(dbc);
@ -1382,31 +1181,6 @@ SQLRETURN SQL_API SQLColumns(
return SQL_SUCCESS;
}
#ifdef ENABLE_ODBC_W
SQLRETURN SQL_API SQLColumnsW(
SQLHSTMT hstmt,
SQLWCHAR *szCatalogName,
SQLSMALLINT cbCatalogName,
SQLWCHAR *szSchemaName,
SQLSMALLINT cbSchemaName,
SQLWCHAR *szTableName,
SQLSMALLINT cbTableName,
SQLWCHAR *szColumnName,
SQLSMALLINT cbColumnName)
{
if(cbTableName==SQL_NTS)cbTableName=sqlwlen(szTableName);
{
SQLCHAR *tmp=calloc(cbTableName*4,1);
size_t l=cbTableName*4,z=cbTableName*2;
SQLRETURN ret;
unicode2ascii(((struct _hstmt* )hstmt)->hdbc, (char*)szTableName, &z, (char*)tmp, &l);
ret = SQLColumns(hstmt, NULL, 0, NULL, 0, tmp, l, NULL, 0);
free(tmp);
return ret;
}
}
#endif //ENABLE_ODBC_W
SQLRETURN SQL_API SQLGetConnectOption(
SQLHDBC hdbc,
SQLUSMALLINT fOption,
@ -1465,9 +1239,21 @@ SQLRETURN SQL_API SQLGetData(
if (col->col_type == MDB_BOOL) {
// bool cannot be null
*(BOOL*)rgbValue = col->cur_value_len ? 0 : 1;
if (pcbValue)
*pcbValue = 1;
if (fCType == SQL_C_CHAR) {
((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)
*pcbValue = 1;
}
return SQL_SUCCESS;
}
if (col->cur_value_len == 0) {
@ -1496,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:
@ -1656,7 +1442,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) {
@ -1664,6 +1450,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);
@ -1672,64 +1459,53 @@ 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;
}
}
return SQL_SUCCESS;
}
#ifdef ENABLE_ODBC_W
SQLRETURN SQL_API SQLGetDataW(
SQLHSTMT hstmt,
SQLUSMALLINT icol,
SQLSMALLINT fCType,
SQLPOINTER rgbValue,
SQLLEN cbValueMax,
SQLLEN *pcbValue)
{
//todo: treat numbers correctly
SQLCHAR *tmp=calloc(cbValueMax*4,1);
size_t l=cbValueMax*4;
SQLRETURN ret = SQLGetData(hstmt, icol, fCType, tmp, cbValueMax*4, (SQLLEN*)&l);
ascii2unicode(((struct _hstmt *)hstmt)->hdbc, (char*)tmp, &l, (char*)rgbValue, (size_t*)pcbValue);
*pcbValue/=sizeof(SQLWCHAR);
free(tmp);
return ret;
}
#endif //ENABLE_ODBC_W
static void _set_func_exists(SQLUSMALLINT *pfExists, SQLUSMALLINT fFunction)
{
SQLUSMALLINT *mod;
@ -1964,31 +1740,6 @@ SQLRETURN SQL_API SQLGetInfo(
return SQL_SUCCESS;
}
#ifdef ENABLE_ODBC_W
SQLRETURN SQL_API SQLGetInfoW(
SQLHDBC hdbc,
SQLUSMALLINT fInfoType,
SQLPOINTER rgbInfoValue,
SQLSMALLINT cbInfoValueMax,
SQLSMALLINT *pcbInfoValue)
{
TRACE("SQLGetInfoW");
if(fInfoType==SQL_MAX_STATEMENT_LEN||fInfoType==SQL_SCHEMA_USAGE||fInfoType==SQL_CATALOG_LOCATION)
return SQLGetInfo(hdbc,fInfoType,rgbInfoValue,cbInfoValueMax,pcbInfoValue);
SQLCHAR *tmp=calloc(cbInfoValueMax*4,1);
size_t l=cbInfoValueMax*4;
SQLRETURN ret = SQLGetInfo(hdbc, fInfoType, tmp, cbInfoValueMax*4,(SQLSMALLINT*)&l);
size_t pcb=cbInfoValueMax;
ascii2unicode((struct _hdbc *)hdbc, (char*)tmp, &l, (char*)rgbInfoValue, &pcb);
pcb/=sizeof(SQLWCHAR);
if(pcbInfoValue)*pcbInfoValue=pcb;
free(tmp);
return ret;
}
#endif //ENABLE_ODBC_W
SQLRETURN SQL_API SQLGetStmtOption(
SQLHSTMT hstmt,
SQLUSMALLINT fOption,
@ -2233,14 +1984,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;
s=stmt->query;
d=tmp;
while (*s) {
while (*s && d<tmp+sizeof(tmp)) {
if (!quoted && (*s=='"' || *s=='\'')) {
quoted = 1;
quote_char = *s;
@ -2255,9 +2006,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;
}
@ -2265,8 +2014,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;
}
@ -2373,7 +2122,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;

265
src/odbc/odbcw.c Normal file
View File

@ -0,0 +1,265 @@
/* MDB Tools - A library for reading MS Access database file
* Copyright (C) 2000-2021 Brian Bruns and others
*
* 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
*/
/* 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
#include <sql.h>
#include <sqlext.h>
#include <string.h>
#include <stdio.h>
#include <limits.h>
#include "mdbodbc.h"
/** \addtogroup odbc
* @{
*/
//#define TRACE(x) fprintf(stderr,"Function %s\n", x);
#define TRACE(x)
static size_t unicode2ascii(struct _hdbc* dbc, const SQLWCHAR *_in, size_t _in_count, SQLCHAR *_out, size_t _out_len){
wchar_t *w = malloc((_in_count + 1) * sizeof(wchar_t));
size_t i;
size_t count = 0;
for (i=0; i<_in_count; i++) {
w[i] = _in[i]; // wchar_t might be larger than SQLWCHAR
}
w[_in_count] = '\0';
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || defined(WINDOWS)
count = _wcstombs_l((char *)_out, w, _out_len, dbc->locale);
#elif defined(HAVE_WCSTOMBS_L)
count = wcstombs_l((char *)_out, w, _out_len, dbc->locale);
#else
locale_t oldlocale = uselocale(dbc->locale);
count = wcstombs((char *)_out, w, _out_len);
uselocale(oldlocale);
#endif
free(w);
if (count == (size_t)-1)
return 0;
if (count < _out_len)
_out[count] = '\0';
return count;
}
static int sqlwlen(SQLWCHAR *p){
int r=0;
for(;*p;r++)
p++;
return r;
}
SQLRETURN SQL_API SQLDriverConnectW(
SQLHDBC hdbc,
SQLHWND hwnd,
SQLWCHAR *szConnStrIn,
SQLSMALLINT cbConnStrIn,
SQLWCHAR *szConnStrOut,
SQLSMALLINT cbConnStrOutMax,
SQLSMALLINT *pcbConnStrOut,
SQLUSMALLINT fDriverCompletion)
{
TRACE("SQLDriverConnectW");
if(cbConnStrIn==SQL_NTS)cbConnStrIn=sqlwlen(szConnStrIn);
{
size_t l = cbConnStrIn*4;
SQLCHAR *tmp = malloc(l+1);
SQLRETURN ret;
l = unicode2ascii((struct _hdbc *)hdbc, szConnStrIn, cbConnStrIn, tmp, l);
ret = SQLDriverConnect(hdbc,hwnd,tmp,SQL_NTS,NULL,0,pcbConnStrOut,fDriverCompletion);
free(tmp);
if (szConnStrOut && cbConnStrOutMax>0)
szConnStrOut[0] = 0;
if (pcbConnStrOut)
*pcbConnStrOut = 0;
return ret;
}
}
SQLRETURN SQL_API SQLConnectW(
SQLHDBC hdbc,
SQLWCHAR *szDSN,
SQLSMALLINT cbDSN,
SQLWCHAR *szUID,
SQLSMALLINT cbUID,
SQLWCHAR *szAuthStr,
SQLSMALLINT cbAuthStr)
{
TRACE("SQLConnectW");
if(cbDSN==SQL_NTS)cbDSN=sqlwlen(szDSN);
if(cbUID==SQL_NTS)cbUID=sqlwlen(szUID);
if(cbAuthStr==SQL_NTS)cbAuthStr=sqlwlen(szAuthStr);
{
size_t l1=cbDSN*4;
size_t l2=cbUID*4;
size_t l3=cbAuthStr*4;
SQLCHAR *tmp1=calloc(l1,1),*tmp2=calloc(l2,1),*tmp3=calloc(l3,1);
SQLRETURN ret;
l1 = unicode2ascii((struct _hdbc *)hdbc, szDSN, cbDSN, tmp1, l1);
l2 = unicode2ascii((struct _hdbc *)hdbc, szUID, cbUID, tmp2, l2);
l3 = unicode2ascii((struct _hdbc *)hdbc, szAuthStr, cbAuthStr, tmp3, l3);
ret = SQLConnect(hdbc, tmp1, l1, tmp2, l2, tmp3, l3);
free(tmp1),free(tmp2),free(tmp3);
return ret;
}
}
SQLRETURN SQL_API SQLDescribeColW(
SQLHSTMT hstmt,
SQLUSMALLINT icol,
SQLWCHAR *szColName,
SQLSMALLINT cbColNameMax,
SQLSMALLINT *pcbColName,
SQLSMALLINT *pfSqlType,
SQLULEN *pcbColDef, /* precision */
SQLSMALLINT *pibScale,
SQLSMALLINT *pfNullable)
{
TRACE("SQLDescribeColW");
if(cbColNameMax==SQL_NTS)cbColNameMax=sqlwlen(szColName);
{
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 = _mdb_odbc_ascii2unicode(((struct _hstmt*)hstmt)->hdbc, (char*)tmp, l, szColName, cbColNameMax);
free(tmp);
return ret;
}
}
SQLRETURN SQL_API SQLColAttributesW(
SQLHSTMT hstmt,
SQLUSMALLINT icol,
SQLUSMALLINT fDescType,
SQLPOINTER rgbDesc,
SQLSMALLINT cbDescMax,
SQLSMALLINT *pcbDesc,
SQLLEN *pfDesc)
{
TRACE("SQLColAttributesW");
if (fDescType!=SQL_COLUMN_NAME && fDescType!=SQL_COLUMN_LABEL)
return SQLColAttributes(hstmt,icol,fDescType,rgbDesc,cbDescMax,pcbDesc,pfDesc);
else{
size_t l=cbDescMax*4+1;
SQLCHAR *tmp=calloc(l,1);
SQLRETURN ret=SQLColAttributes(hstmt,icol,fDescType,tmp,l,(SQLSMALLINT*)&l,pfDesc);
*pcbDesc = _mdb_odbc_ascii2unicode(((struct _hstmt *)hstmt)->hdbc, (char*)tmp, l, (SQLWCHAR*)rgbDesc, cbDescMax);
free(tmp);
return ret;
}
}
SQLRETURN SQL_API SQLErrorW(
SQLHENV henv,
SQLHDBC hdbc,
SQLHSTMT hstmt,
SQLWCHAR *szSqlState,
SQLINTEGER *pfNativeError,
SQLWCHAR *szErrorMsg,
SQLSMALLINT cbErrorMsgMax,
SQLSMALLINT *pcbErrorMsg)
{
SQLCHAR szSqlState8[6];
SQLCHAR szErrorMsg8[3*cbErrorMsgMax+1];
SQLSMALLINT pcbErrorMsg8;
SQLRETURN result;
TRACE("SQLErrorW");
result = SQLError(henv, hdbc, hstmt, szSqlState8, pfNativeError, szErrorMsg8, 3*cbErrorMsgMax+1, &pcbErrorMsg8);
if (result == SQL_SUCCESS) {
struct _hdbc *dbc = hstmt ? ((struct _hstmt *)hstmt)->hdbc : hdbc;
size_t pcb;
_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;
}
SQLRETURN SQL_API SQLExecDirectW(
SQLHSTMT hstmt,
SQLWCHAR *szSqlStr,
SQLINTEGER cbSqlStr)
{
TRACE("SQLExecDirectW");
if(cbSqlStr==SQL_NTS)cbSqlStr=sqlwlen(szSqlStr);
{
size_t l=cbSqlStr*4;
SQLCHAR *tmp=calloc(l,1);
SQLRETURN ret;
l = unicode2ascii(((struct _hstmt *)hstmt)->hdbc, szSqlStr, cbSqlStr, tmp, l);
ret = SQLExecDirect(hstmt, tmp, l);
TRACE("SQLExecDirectW end");
free(tmp);
return ret;
}
}
SQLRETURN SQL_API SQLColumnsW(
SQLHSTMT hstmt,
SQLWCHAR *szCatalogName,
SQLSMALLINT cbCatalogName,
SQLWCHAR *szSchemaName,
SQLSMALLINT cbSchemaName,
SQLWCHAR *szTableName,
SQLSMALLINT cbTableName,
SQLWCHAR *szColumnName,
SQLSMALLINT cbColumnName)
{
if(cbTableName==SQL_NTS)cbTableName=sqlwlen(szTableName);
{
size_t l=cbTableName*4;
SQLCHAR *tmp=calloc(l,1);
SQLRETURN ret;
l = unicode2ascii(((struct _hstmt* )hstmt)->hdbc, szTableName, cbTableName, tmp, l);
ret = SQLColumns(hstmt, NULL, 0, NULL, 0, tmp, l, NULL, 0);
free(tmp);
return ret;
}
}
SQLRETURN SQL_API SQLGetInfoW(
SQLHDBC hdbc,
SQLUSMALLINT fInfoType,
SQLPOINTER rgbInfoValue,
SQLSMALLINT cbInfoValueMax,
SQLSMALLINT *pcbInfoValue)
{
TRACE("SQLGetInfoW");
if(fInfoType==SQL_MAX_STATEMENT_LEN||fInfoType==SQL_SCHEMA_USAGE||fInfoType==SQL_CATALOG_LOCATION)
return SQLGetInfo(hdbc,fInfoType,rgbInfoValue,cbInfoValueMax,pcbInfoValue);
size_t l=cbInfoValueMax*4+1;
SQLCHAR *tmp=calloc(l,1);
SQLRETURN ret = SQLGetInfo(hdbc, fInfoType, tmp, l, (SQLSMALLINT*)&l);
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

@ -68,9 +68,11 @@ null { return NUL; }
"=" { return EQ; }
(<=) { return LTEQ; }
(>=) { return GTEQ; }
(<>) { return NEQ; }
"<" { return LT; }
">" { return GT; }
like { return LIKE; }
ilike { return ILIKE; }
limit { return LIMIT; }
top { return TOP; }
percent { return PERCENT; }
@ -111,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

@ -17,9 +17,6 @@
*/
#include <stdarg.h>
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 600
#endif
#include "mdbsql.h"
#ifdef HAVE_STRPTIME
@ -324,6 +321,9 @@ mdb_sql_dump_node(MdbSargNode *node, int level)
case MDB_LIKE:
printf(" like %s\n", node->value.s);
break;
case MDB_ILIKE:
printf(" ilike %s\n", node->value.s);
break;
case MDB_EQUAL:
printf(" = %d\n", node->value.i);
break;
@ -398,6 +398,8 @@ mdb_sql_eval_expr(MdbSQL *sql, char *const1, int op, char *const2)
case MDB_LT: compar = (value < 0); break;
case MDB_LTEQ: compar = (value <= 0); break;
case MDB_LIKE: compar = mdb_like_cmp(const1,const2); break;
case MDB_ILIKE: compar = mdb_ilike_cmp(const1,const2); break;
case MDB_NEQ: compar = (value ? 1 : 0); break;
default: illop = 1;
}
} else if (const1[0]!='\'' && const2[0]!='\'') {
@ -409,6 +411,7 @@ mdb_sql_eval_expr(MdbSQL *sql, char *const1, int op, char *const2)
case MDB_GTEQ: compar = (val1 >= val2); break;
case MDB_LT: compar = (val1 < val2); break;
case MDB_LTEQ: compar = (val1 <= val2); break;
case MDB_NEQ: compar = (val1 != val2); break;
default: illop = 1;
}
} else {

View File

@ -63,7 +63,7 @@ typedef struct sql_context
%token <name> IDENT NAME PATH STRING NUMBER OPENING CLOSING
%token SELECT FROM WHERE CONNECT DISCONNECT TO LIST TABLES AND OR NOT LIMIT COUNT STRPTIME
%token DESCRIBE TABLE TOP PERCENT
%token LTEQ GTEQ LIKE IS NUL
%token LTEQ GTEQ NEQ LIKE ILIKE IS NUL
%type <name> database
%type <name> constant
@ -81,7 +81,7 @@ typedef struct sql_context
%left OR
%left AND
%right NOT
%left EQ LTEQ GTEQ LT GT LIKE IS
%left EQ LTEQ GTEQ NEQ LT GT LIKE ILIKE IS
%%
@ -192,7 +192,9 @@ operator:
| LT { $$ = MDB_LT; }
| LTEQ { $$ = MDB_LTEQ; }
| GTEQ { $$ = MDB_GTEQ; }
| NEQ { $$ = MDB_NEQ; }
| LIKE { $$ = MDB_LIKE; }
| ILIKE { $$ = MDB_ILIKE; }
;
nulloperator:

View File

@ -1,6 +1,6 @@
AUTOMAKE_OPTIONS = subdir-objects
SUBDIRS = bash-completion
bin_PROGRAMS = mdb-export mdb-array mdb-schema mdb-tables mdb-parsecsv mdb-header mdb-sql mdb-ver mdb-prop mdb-count mdb-queries mdb-json
bin_PROGRAMS = mdb-export mdb-array mdb-schema mdb-tables mdb-parsecsv mdb-header mdb-ver mdb-prop mdb-count mdb-queries mdb-json
noinst_PROGRAMS = mdb-import prtable prcat prdata prkkd prdump prole updrow prindex
noinst_HEADERS = base64.h
LIBS = $(GLIB_LIBS) @LIBS@
@ -8,5 +8,6 @@ DEFS = @DEFS@ -DLOCALEDIR=\"$(localedir)\"
AM_CFLAGS = -I$(top_srcdir)/include $(GLIB_CFLAGS) -Wsign-compare
LDADD = ../libmdb/libmdb.la
if SQL
bin_PROGRAMS += mdb-sql
mdb_sql_LDADD = ../libmdb/libmdb.la ../sql/libmdbsql.la $(LIBREADLINE)
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

@ -226,12 +226,14 @@ main(int argc, char **argv)
counter = 0; // reset to 0, prevent overflow on extremely large data sets.
char *quoted_name;
quoted_name = mdb->default_backend->quote_schema_name(namespace, table_name);
quoted_name = mdb_normalise_and_replace(mdb, &quoted_name);
fprintf(outfile, "INSERT INTO %s (", quoted_name);
free(quoted_name);
for (i = 0; i < table->num_cols; i++) {
if (i > 0) fputs(", ", outfile);
col = g_ptr_array_index(table->columns, i);
quoted_name = mdb->default_backend->quote_schema_name(NULL, col->name);
quoted_name = mdb_normalise_and_replace(mdb, &quoted_name);
fputs(quoted_name, outfile);
free(quoted_name);
}
@ -284,12 +286,14 @@ main(int argc, char **argv)
if (insert_dialect) {
char *quoted_name;
quoted_name = mdb->default_backend->quote_schema_name(namespace, table_name);
quoted_name = mdb_normalise_and_replace(mdb, &quoted_name);
fprintf(outfile, "INSERT INTO %s (", quoted_name);
free(quoted_name);
for (i = 0; i < table->num_cols; i++) {
if (i > 0) fputs(", ", outfile);
col = g_ptr_array_index(table->columns, i);
quoted_name = mdb->default_backend->quote_schema_name(NULL, col->name);
quoted_name = mdb_normalise_and_replace(mdb, &quoted_name);
fputs(quoted_name, outfile);
free(quoted_name);
}

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);

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

@ -51,8 +51,6 @@ extern void clear_history ();
void dump_results(FILE *out, MdbSQL *sql, char *delimiter);
void dump_results_pp(FILE *out, MdbSQL *sql);
#if SQL
int headers = 1;
int footers = 1;
int pretty_print = 1;
@ -415,7 +413,10 @@ main(int argc, char **argv)
while (1) {
line ++;
if (s) free(s);
if (s) {
free(s);
s = NULL;
}
if (in) {
s=calloc(bufsz, 1);
@ -436,9 +437,13 @@ main(int argc, char **argv)
s[strlen(s)-1]=0;
} else {
snprintf(prompt, sizeof(prompt), "%d => ", line);
s=readline(prompt);
if (!s)
locale = setlocale(LC_CTYPE, "");
char *l = readline(prompt);
setlocale(LC_CTYPE, locale);
if (!l)
break;
s=g_locale_to_utf8(l, -1, NULL, NULL, NULL);
free(l);
}
if (!strcmp(s,"exit") || !strcmp(s,"quit") || !strcmp(s,"bye"))
@ -516,11 +521,3 @@ main(int argc, char **argv)
return 0;
}
#else
int main(int argc, char **argv)
{
fprintf(stderr,"You must configure using --enable-sql to get SQL support\n");
return -1;
}
#endif