[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kexi] src/migration/mdb: MDB Import: Update to mdbtools from June 2014
From:       Jaroslaw Staniek <staniek () kde ! org>
Date:       2016-02-29 23:12:19
Message-ID: E1aaWzD-0000sv-UI () scm ! kde ! org
[Download RAW message or body]

Git commit 5a2ab83ab935d3710ea9daa924427e75a833f247 by Jaroslaw Staniek.
Committed on 29/02/2016 at 23:07.
Pushed by staniek into branch 'master'.

MDB Import: Update to mdbtools from June 2014

BUG:277583

This also fixes primary keys import

BUG:336560

FIXED-IN:2.9.11

Test Plan: Northwind database imports properly with keys, try e.g. from \
http://www.2013.net/courses/access/

Differential Revision: https://phabricator.kde.org/D855

(from calligra.git)

M  +92   -38   src/migration/mdb/3rdparty/mdbtools/include/mdbtools.h
M  +53   -18   src/migration/mdb/3rdparty/mdbtools/libmdb/catalog.c
M  +201  -131  src/migration/mdb/3rdparty/mdbtools/libmdb/data.c
M  +19   -1    src/migration/mdb/3rdparty/mdbtools/libmdb/dump.c
M  +132  -12   src/migration/mdb/3rdparty/mdbtools/libmdb/file.c
M  +41   -21   src/migration/mdb/3rdparty/mdbtools/libmdb/iconv.c
M  +122  -78   src/migration/mdb/3rdparty/mdbtools/libmdb/index.c
M  +3    -4    src/migration/mdb/3rdparty/mdbtools/libmdb/like.c
M  +13   -8    src/migration/mdb/3rdparty/mdbtools/libmdb/map.c
M  +9    -34   src/migration/mdb/3rdparty/mdbtools/libmdb/mem.c
M  +53   -24   src/migration/mdb/3rdparty/mdbtools/libmdb/money.c
M  +22   -22   src/migration/mdb/3rdparty/mdbtools/libmdb/options.c
A  +215  -0    src/migration/mdb/3rdparty/mdbtools/libmdb/props.c     [License: LGPL \
(v2+)] M  +53   -8    src/migration/mdb/3rdparty/mdbtools/libmdb/sargs.c
A  +77   -0    src/migration/mdb/3rdparty/mdbtools/libmdb/stats.c     [License: LGPL \
(v2+)] M  +86   -39   src/migration/mdb/3rdparty/mdbtools/libmdb/table.c
M  +3    -3    src/migration/mdb/3rdparty/mdbtools/libmdb/worktable.c
M  +113  -78   src/migration/mdb/3rdparty/mdbtools/libmdb/write.c
D  +0    -7    src/migration/mdb/3rdparty/mdbtools/update_diffs.sh
M  +4    -0    src/migration/mdb/ChangeLog
M  +6    -1    src/migration/mdb/src/CMakeLists.txt
M  +6    -21   src/migration/mdb/src/keximdb/mdbmigrate.cpp
M  +1    -4    src/migration/mdb/src/keximdb/mdbmigrate.h

http://commits.kde.org/kexi/5a2ab83ab935d3710ea9daa924427e75a833f247

diff --git a/src/migration/mdb/3rdparty/mdbtools/include/mdbtools.h \
b/src/migration/mdb/3rdparty/mdbtools/include/mdbtools.h index 0c69c18..68b326f \
                100644
--- a/src/migration/mdb/3rdparty/mdbtools/include/mdbtools.h
+++ b/src/migration/mdb/3rdparty/mdbtools/include/mdbtools.h
@@ -12,9 +12,8 @@
  * 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.
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #ifndef _mdbtools_h_
 #define _mdbtools_h_
@@ -33,14 +32,18 @@
 #include <string.h>
 #include <glib.h>
 
-
 #ifdef HAVE_ICONV
 #include <iconv.h>
 #endif
 
+#ifdef _WIN32
+#include <io.h>
+#endif
+
 #define MDB_DEBUG 0
 
 #define MDB_PGSIZE 4096
+//#define MDB_MAX_OBJ_NAME (256*3) /* unicode 16 -> utf-8 worst case */
 #define MDB_MAX_OBJ_NAME 256
 #define MDB_MAX_COLS 256
 #define MDB_MAX_IDX_COLS 10
@@ -51,6 +54,11 @@
 #define MDB_NO_BACKENDS 1
 #define MDB_NO_STATS 1
 
+// Theses 2 atrbutes are not supported by all compilers:
+// M$VC see http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc
 +#define MDB_DEPRECATED(type, funcname) type __attribute__((deprecated)) funcname
+#define MDB_CONSTRUCTOR(funcname) void __attribute__((constructor)) funcname()
+
 enum {
 	MDB_PAGE_DB = 0,
 	MDB_PAGE_DATA,
@@ -61,7 +69,9 @@ enum {
 };
 enum {
 	MDB_VER_JET3 = 0,
-	MDB_VER_JET4 = 1
+	MDB_VER_JET4 = 1,
+	MDB_VER_ACCDB_2007 = 0x02,
+	MDB_VER_ACCDB_2010 = 0x0103
 };
 enum {
 	MDB_FORM = 0,
@@ -74,7 +84,7 @@ enum {
 	MDB_MODULE,
 	MDB_RELATIONSHIP,
 	MDB_UNKNOWN_09,
-	MDB_UNKNOWN_0A,
+	MDB_UNKNOWN_0A, /* User access */
 	MDB_DATABASE_PROPERTY,
 	MDB_ANY = -1
 };
@@ -86,12 +96,14 @@ enum {
 	MDB_MONEY = 0x05,
 	MDB_FLOAT = 0x06,
 	MDB_DOUBLE = 0x07,
-	MDB_SDATETIME = 0x08,
+	MDB_DATETIME = 0x08,
+	MDB_BINARY = 0x09,
 	MDB_TEXT = 0x0a,
 	MDB_OLE = 0x0b,
 	MDB_MEMO = 0x0c,
 	MDB_REPID = 0x0f,
-	MDB_NUMERIC = 0x10
+	MDB_NUMERIC = 0x10,
+	MDB_COMPLEX = 0x12
 };
 
 /* SARG operators */
@@ -126,8 +138,9 @@ enum {
 	MDB_DEBUG_USAGE = 0x0004,
 	MDB_DEBUG_OLE = 0x0008,
 	MDB_DEBUG_ROW = 0x0010,
-	MDB_USE_INDEX = 0x0020,
-	MDB_NO_MEMO = 0x0040 /* don't follow memo fields */
+	MDB_DEBUG_PROPS = 0x0020,
+	MDB_USE_INDEX = 0x0040,
+	MDB_NO_MEMO = 0x0080, /* don't follow memo fields */
 };
 
 #define mdb_is_logical_op(x) (x == MDB_OR || \
@@ -154,13 +167,27 @@ enum {
 	MDB_IDX_REQUIRED = 0x08
 };
 
-#define IS_JET4(mdb) (mdb->f->jet_version==MDB_VER_JET4)
-#define IS_JET3(mdb) (mdb->f->jet_version==MDB_VER_JET3)
+/* export schema options */
+enum {
+	MDB_SHEXP_DROPTABLE = 1<<0, /* issue drop table during export */
+	MDB_SHEXP_CST_NOTNULL = 1<<1, /* generate NOT NULL constraints */
+	MDB_SHEXP_CST_NOTEMPTY = 1<<2, /* <>'' constraints */
+	MDB_SHEXP_COMMENTS = 1<<3, /* export comments on columns & tables */
+	MDB_SHEXP_DEFVALUES = 1<<4, /* export default values */
+	MDB_SHEXP_INDEXES = 1<<5, /* export indices */
+	MDB_SHEXP_RELATIONS = 1<<6 /* export relation (foreign keys) */
+};
+#define MDB_SHEXP_DEFAULT (MDB_SHEXP_CST_NOTNULL | MDB_SHEXP_COMMENTS | \
MDB_SHEXP_INDEXES | MDB_SHEXP_RELATIONS)  
-#if !MDB_NO_BACKENDS
-/* hash to store registered backends */
-extern GHashTable	*mdb_backends;
-#endif
+/* csv export binary options */
+enum {
+	MDB_BINEXPORT_STRIP,
+	MDB_BINEXPORT_RAW,
+	MDB_BINEXPORT_OCTAL
+};
+
+#define IS_JET4(mdb) (mdb->f->jet_version==MDB_VER_JET4) /* obsolete */
+#define IS_JET3(mdb) (mdb->f->jet_version==MDB_VER_JET3)
 
 /* forward declarations */
 typedef struct mdbindex MdbIndex;
@@ -175,7 +202,18 @@ typedef struct {
 } MdbBackendType;
 
 typedef struct {
-	 MdbBackendType *types_table;
+	guint32 capabilities; /* see MDB_SHEXP_* */
+	MdbBackendType *types_table;
+	MdbBackendType *type_shortdate;
+	MdbBackendType *type_autonum;
+	const char *short_now;
+	const char *long_now;
+	const char *charset_statement;
+	const char *drop_statement;
+	const char *constaint_not_empty_statement;
+	const char *column_comment_statement;
+	const char *table_comment_statement;
+	gchar* (*quote_schema_name)(const gchar*, const gchar*);
 } MdbBackend;
 #endif
 
@@ -219,7 +257,7 @@ typedef struct {
 	guint16		tab_first_dpg_offset;
 	guint16		tab_cols_start_offset;
 	guint16		tab_ridx_entry_size;
-	guint16		col_fixed_offset;
+	guint16		col_flags_offset;
 	guint16		col_size_offset;
 	guint16		col_num_offset;
 	guint16		tab_col_entry_size;
@@ -258,10 +296,8 @@ typedef struct {
 	char           object_name[MDB_MAX_OBJ_NAME+1];
 	int            object_type;
 	unsigned long  table_pg; /* misnomer since object may not be a table */
-	unsigned long  kkd_pg;
-	unsigned int   kkd_rowid;
-	int			num_props;
-	GArray		*props;
+	//int			num_props; please use props->len
+	GArray		*props; /* GArray of MdbProperties */
 	GArray		*columns;
 	int		flags;
 } MdbCatalogEntry;
@@ -277,7 +313,9 @@ typedef union {
 	char	s[256];
 } MdbAny;
 
+struct S_MdbTableDef; /* forward definition */
 typedef struct {
+	struct S_MdbTableDef *table;
 	char		name[MDB_MAX_OBJ_NAME+1];
 	int		col_type;
 	int		col_size;
@@ -300,6 +338,8 @@ typedef struct {
 	/* numerics only */
 	int		col_prec;
 	int		col_scale;
+	unsigned char     is_long_auto;
+	unsigned char     is_uuid_auto;
 	MdbProperties	*props;
 	/* info needed for handling deleted/added columns */
 	int 		fixed_offset;
@@ -338,7 +378,7 @@ typedef struct {
 	MdbIndexPage pages[MDB_MAX_INDEX_DEPTH];
 } MdbIndexChain;
 
-typedef struct {
+typedef struct S_MdbTableDef {
 	MdbCatalogEntry *entry;
 	char	name[MDB_MAX_OBJ_NAME+1];
 	unsigned int    num_cols;
@@ -407,8 +447,8 @@ typedef struct {
 } MdbSarg;
 
 /* mem.c */
-extern void mdb_init();
-extern void mdb_exit();
+extern MDB_DEPRECATED(void, mdb_init());
+extern MDB_DEPRECATED(void, mdb_exit());
 
 /* file.c */
 extern ssize_t mdb_read_pg(MdbHandle *mdb, unsigned long pg);
@@ -433,8 +473,9 @@ extern void mdb_swap_pgbuf(MdbHandle *mdb);
 /* catalog.c */
 extern void mdb_free_catalog(MdbHandle *mdb);
 extern GPtrArray *mdb_read_catalog(MdbHandle *mdb, int obj_type);
+MdbCatalogEntry *mdb_get_catalogentry_by_name(MdbHandle *mdb, const gchar* name);
 extern void mdb_dump_catalog(MdbHandle *mdb, int obj_type);
-extern char *mdb_get_objtype_string(int obj_type);
+extern const char *mdb_get_objtype_string(int obj_type);
 
 /* table.c */
 extern MdbTableDef *mdb_alloc_tabledef(MdbCatalogEntry *entry);
@@ -451,10 +492,13 @@ extern guint32 read_pg_if_32(MdbHandle *mdb, int *cur_pos);
 extern void *read_pg_if_n(MdbHandle *mdb, void *buf, int *cur_pos, size_t len);
 extern int mdb_is_user_table(MdbCatalogEntry *entry);
 extern int mdb_is_system_table(MdbCatalogEntry *entry);
+extern const char *mdb_table_get_prop(const MdbTableDef *table, const gchar *key);
+extern const char *mdb_col_get_prop(const MdbColumn *col, const gchar *key);
 
 /* data.c */
-extern int mdb_bind_column_by_name(MdbTableDef *table, gchar *col_name, void \
*bind_ptr, int *len_ptr); +extern int mdb_bind_column_by_name(MdbTableDef *table, \
const gchar *col_name, void *bind_ptr, int *len_ptr);  extern void \
mdb_data_dump(MdbTableDef *table); +extern void mdb_date_to_tm(double td, struct tm \
*t);  extern void mdb_bind_column(MdbTableDef *table, int col_num, void *bind_ptr, \
int *len_ptr);  extern int mdb_rewind_table(MdbTableDef *table);
 extern int mdb_fetch_row(MdbTableDef *table);
@@ -467,21 +511,25 @@ extern int mdb_col_fixed_size(MdbColumn *col);
 extern int mdb_col_disp_size(MdbColumn *col);
 extern size_t mdb_ole_read_next(MdbHandle *mdb, MdbColumn *col, void *ole_ptr);
 extern size_t mdb_ole_read(MdbHandle *mdb, MdbColumn *col, void *ole_ptr, int \
chunk_size); +extern void* mdb_ole_read_full(MdbHandle *mdb, MdbColumn *col, size_t \
*size);  extern void mdb_set_date_fmt(const char *);
 extern int mdb_read_row(MdbTableDef *table, unsigned int row);
 
 /* dump.c */
-extern void buffer_dump(const void *buf, int start, size_t len);
+extern void mdb_buffer_dump(const void *buf, int start, size_t len);
 
 #if !MDB_NO_BACKENDS
 /* backend.c */
-extern char *mdb_get_coltype_string(MdbBackend *backend, int col_type);
-extern int  mdb_coltype_takes_length(MdbBackend *backend, int col_type);
-extern void mdb_init_backends();
-extern void mdb_register_backend(MdbBackendType *backend, char *backend_name);
-extern void mdb_remove_backends();
+extern MDB_DEPRECATED(char*, mdb_get_coltype_string(MdbBackend *backend, int \
col_type)); +extern MDB_DEPRECATED(int, mdb_coltype_takes_length(MdbBackend *backend, \
int col_type)); +extern const MdbBackendType* mdb_get_colbacktype(const MdbColumn \
*col); +extern const char* mdb_get_colbacktype_string(const MdbColumn *col);
+extern int mdb_colbacktype_takes_length(const MdbColumn *col);
+extern MDB_DEPRECATED(void, mdb_init_backends());
+extern void mdb_register_backend(char *backend_name, guint32 capabilities, \
MdbBackendType *backend_type, MdbBackendType *type_shortdate, MdbBackendType \
*type_autonum, const char *short_now, const char *long_now, const char \
*charset_statement, const char *drop_statement, const char \
*constaint_not_empty_statement, const char *column_comment_statement, const char \
*table_comment_statement, gchar* (*quote_schema_name)(const gchar*, const gchar*)); \
+extern MDB_DEPRECATED(void, mdb_remove_backends());  extern int  \
                mdb_set_default_backend(MdbHandle *mdb, const char *backend_name);
-extern char *mdb_get_relationships(MdbHandle *mdb);
+extern void mdb_print_schema(MdbHandle *mdb, FILE *outfile, char *tabname, char \
*dbnamespace, guint32 export_options);  #endif
 
 /* sargs.c */
@@ -521,9 +569,13 @@ extern void mdb_dump_stats(MdbHandle *mdb);
 extern int mdb_like_cmp(char *s, char *r);
 
 /* write.c */
+extern void mdb_put_int16(void *buf, guint32 offset, guint32 value);
+extern void mdb_put_int32(void *buf, guint32 offset, guint32 value);
+extern void mdb_put_int32_msb(void *buf, guint32 offset, guint32 value);
 extern int mdb_crack_row(MdbTableDef *table, int row_start, int row_end, MdbField \
*fields);  extern guint16 mdb_add_row_to_pg(MdbTableDef *table, unsigned char \
*row_buffer, int new_row_size);  extern int mdb_update_index(MdbTableDef *table, \
MdbIndex *idx, unsigned int num_fields, MdbField *fields, guint32 pgnum, guint16 \
rownum); +extern int mdb_insert_row(MdbTableDef *table, int num_fields, MdbField \
*fields);  extern int mdb_pack_row(MdbTableDef *table, unsigned char *row_buffer, \
unsigned int num_fields, MdbField *fields);  extern int mdb_replace_row(MdbTableDef \
*table, int row, void *new_row, int new_row_size);  extern int \
mdb_pg_get_freespace(MdbHandle *mdb); @@ -532,12 +584,13 @@ extern void \
*mdb_new_data_pg(MdbCatalogEntry *entry);  
 /* map.c */
 extern guint32 mdb_map_find_next_freepage(MdbTableDef *table, int row_size);
-extern guint32 mdb_map_find_next(MdbHandle *mdb, unsigned char *map, unsigned int \
map_sz, guint32 start_pg); +extern gint32 mdb_map_find_next(MdbHandle *mdb, unsigned \
char *map, unsigned int map_sz, guint32 start_pg);  
 /* props.c */
-extern GPtrArray *mdb_read_props_list(gchar *kkd, int len);
 extern void mdb_free_props(MdbProperties *props);
-extern MdbProperties *mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, \
int len); +extern void mdb_dump_props(MdbProperties *props, FILE *outfile, int \
show_name); +extern GArray* mdb_kkd_to_props(MdbHandle *mdb, void *kkd, size_t len);
+
 
 /* worktable.c */
 extern MdbTableDef *mdb_create_temp_table(MdbHandle *mdb, char *name);
@@ -548,13 +601,14 @@ extern void mdb_temp_columns_end(MdbTableDef *table);
 
 /* options.c */
 extern int mdb_get_option(unsigned long optnum);
-extern void mdb_debug(int klass, char *fmt, ...);
+extern void mdb_debug(int klass, const char *fmt, ...);
 
 /* iconv.c */
 extern int mdb_unicode2ascii(MdbHandle *mdb, char *src, size_t slen, char *dest, \
size_t dlen);  extern int mdb_ascii2unicode(MdbHandle *mdb, char *src, size_t slen, \
char *dest, size_t dlen);  extern void mdb_iconv_init(MdbHandle *mdb);
 extern void mdb_iconv_close(MdbHandle *mdb);
+extern const char* mdb_target_charset(MdbHandle *mdb);
 
 #ifdef __cplusplus
   }
diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/catalog.c \
b/src/migration/mdb/3rdparty/mdbtools/libmdb/catalog.c index a857ccf..4736652 100644
--- a/src/migration/mdb/3rdparty/mdbtools/libmdb/catalog.c
+++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/catalog.c
@@ -12,9 +12,8 @@
  * 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.
+ * 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 "mdbtools.h"
@@ -23,10 +22,10 @@
 #include "dmalloc.h"
 #endif
 
-char *
+const char *
 mdb_get_objtype_string(int obj_type)
 {
-static char *type_name[] = {"Form",
+static const char *type_name[] = {"Form",
 			"Table",
 			"Macro",
 			"System Table",
@@ -36,7 +35,7 @@ static char *type_name[] = {"Form",
 			"Module",
 			"Relationship",
 			"Unknown 0x09",
-			"Unknown 0x0a",
+			"User Info",
 			"Database"
 		};
 
@@ -49,11 +48,21 @@ static char *type_name[] = {"Form",
 
 void mdb_free_catalog(MdbHandle *mdb)
 {
-	unsigned int i;
+	unsigned int i, j;
+	MdbCatalogEntry *entry;
 
 	if ((!mdb) || (!mdb->catalog)) return;
-	for (i=0; i<mdb->catalog->len; i++)
-		g_free (g_ptr_array_index(mdb->catalog, i));
+	for (i=0; i<mdb->catalog->len; i++) {
+		entry = (MdbCatalogEntry *)g_ptr_array_index(mdb->catalog, i);
+		if (entry) {
+			if (entry->props) {
+				for (j=0; j<entry->props->len; j++)
+					mdb_free_props(g_array_index(entry->props, MdbProperties*, j));
+				g_array_free(entry->props, TRUE);
+			}
+			g_free(entry);
+		}
+	}
 	g_ptr_array_free(mdb->catalog, TRUE);
 	mdb->catalog = NULL;
 }
@@ -63,10 +72,14 @@ GPtrArray *mdb_read_catalog (MdbHandle *mdb, int objtype)
 	MdbCatalogEntry *entry, msysobj;
 	MdbTableDef *table;
 	char obj_id[256];
-	char obj_name[256];
+	char obj_name[MDB_MAX_OBJ_NAME];
 	char obj_type[256];
 	char obj_flags[256];
+	char obj_props[MDB_BIND_SIZE];
 	int type;
+	unsigned int i;
+	MdbColumn *col_props;
+	int kkd_size_ole;
 
 	if (!mdb) return NULL;
 	if (mdb->catalog) mdb_free_catalog(mdb);
@@ -91,14 +104,16 @@ GPtrArray *mdb_read_catalog (MdbHandle *mdb, int objtype)
 	mdb_bind_column_by_name(table, "Name", obj_name, NULL);
 	mdb_bind_column_by_name(table, "Type", obj_type, NULL);
 	mdb_bind_column_by_name(table, "Flags", obj_flags, NULL);
+	i = mdb_bind_column_by_name(table, "LvProp", obj_props, &kkd_size_ole);
+	col_props = g_ptr_array_index(table->columns, i-1);
 
 	mdb_rewind_table(table);
 
 	while (mdb_fetch_row(table)) {
 		type = atoi(obj_type);
 		if (objtype==MDB_ANY || type == objtype) {
-
-
+			//fprintf(stderr, "obj_id: %10ld objtype: %-3d (0x%04x) obj_name: %s\n",
+			//	(atol(obj_id) & 0x00FFFFFF), type, type, obj_name);
 			entry = (MdbCatalogEntry *) g_malloc0(sizeof(MdbCatalogEntry));
 			entry->mdb = mdb;
 			strcpy(entry->object_name, obj_name);
@@ -107,15 +122,37 @@ GPtrArray *mdb_read_catalog (MdbHandle *mdb, int objtype)
 			entry->flags = atol(obj_flags);
 			mdb->num_catalog++;
 			g_ptr_array_add(mdb->catalog, entry);
+			if (kkd_size_ole) {
+				size_t kkd_len;
+				void *kkd = mdb_ole_read_full(mdb, col_props, &kkd_len);
+				//mdb_buffer_dump(kkd, 0, kkd_len);
+				entry->props = mdb_kkd_to_props(mdb, kkd, kkd_len);
+				free(kkd);
+			}
 		}
 	}
-
+	//mdb_dump_catalog(mdb, MDB_TABLE);
 
 	mdb_free_tabledef(table);
 
 	return mdb->catalog;
 }
 
+
+MdbCatalogEntry *
+mdb_get_catalogentry_by_name(MdbHandle *mdb, const gchar* name)
+{
+	unsigned int i;
+	MdbCatalogEntry *entry;
+
+	for (i=0; i<mdb->num_catalog; i++) {
+		entry = g_ptr_array_index(mdb->catalog, i);
+		if (!strcasecmp(entry->object_name, name))
+			return entry;
+	}
+	return NULL;
+}
+
 void
 mdb_dump_catalog(MdbHandle *mdb, int obj_type)
 {
@@ -126,14 +163,12 @@ mdb_dump_catalog(MdbHandle *mdb, int obj_type)
 	for (i=0;i<mdb->num_catalog;i++) {
                 entry = g_ptr_array_index(mdb->catalog,i);
 		if (obj_type==MDB_ANY || entry->object_type==obj_type) {
-			fprintf(stdout,"Type: %-10s Name: %-18s T pg: %04x KKD pg: %04x row: %2d\n",
+			printf("Type: %-12s Name: %-48s Page: %06lx\n",
 			mdb_get_objtype_string(entry->object_type),
 			entry->object_name,
-			(unsigned int) entry->table_pg,
-			(unsigned int) entry->kkd_pg,
-			entry->kkd_rowid);
+			entry->table_pg);
 		}
-        }
+	}
 	return;
 }
 
diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/data.c \
b/src/migration/mdb/3rdparty/mdbtools/libmdb/data.c index 1e03418..756aefb 100644
--- a/src/migration/mdb/3rdparty/mdbtools/libmdb/data.c
+++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/data.c
@@ -12,14 +12,13 @@
  * 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.
+ * 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 <time.h>
+#include <math.h>
 #include "mdbtools.h"
-#include "time.h"
-#include "math.h"
 
 #ifdef DMALLOC
 #include "dmalloc.h"
@@ -28,9 +27,10 @@
 #define OFFSET_MASK 0x1fff
 
 char *mdb_money_to_string(MdbHandle *mdb, int start);
+char *mdb_numeric_to_string(MdbHandle *mdb, int start, int prec, int scale);
+
 static int _mdb_attempt_bind(MdbHandle *mdb,
 	MdbColumn *col, unsigned char isnull, int offset, int len);
-static char *mdb_num_to_string(MdbHandle *mdb, int start, int datatype, int prec, \
int scale);  static char *mdb_date_to_string(MdbHandle *mdb, int start);
 #ifdef MDB_COPY_OLE
 static size_t mdb_copy_ole(MdbHandle *mdb, void *dest, int start, int size);
@@ -59,7 +59,7 @@ void mdb_bind_column(MdbTableDef *table, int col_num, void \
*bind_ptr, int *len_p  col->len_ptr = len_ptr;
 }
 int
-mdb_bind_column_by_name(MdbTableDef *table, gchar *col_name, void *bind_ptr, int \
*len_ptr) +mdb_bind_column_by_name(MdbTableDef *table, const gchar *col_name, void \
*bind_ptr, int *len_ptr)  {
 	unsigned int i;
 	int col_num = -1;
@@ -139,12 +139,12 @@ mdb_find_end_of_row(MdbHandle *mdb, int row)
 	if (row > 1000) return -1;
 
 	/* if lookupflag is not set, it's good (deleteflag is ok) */
-        for (i = row; i > 0; i--) {
-                row_start = mdb_get_int16(mdb->pg_buf, (rco + i*2));
-                if (!(row_start & 0x8000)) {
-                        break;
-                }
-        }
+	for (i = row; i > 0; i--) {
+		row_start = mdb_get_int16(mdb->pg_buf, (rco + i*2));
+		if (!(row_start & 0x8000)) {
+			break;
+		}
+	}
 
 	row_end = (i == 0) ? mdb->fmt->pg_size : row_start & OFFSET_MASK;
 #endif
@@ -206,9 +206,9 @@ static size_t
 mdb_xfer_bound_data(MdbHandle *mdb, int start, MdbColumn *col, int len)
 {
 int ret;
-
-
-
+	//if (!strcmp("Name",col->name)) {
+		//printf("start %d %d\n",start, len);
+	//}
 	if (len) {
 		col->cur_value_start = start;
 		col->cur_value_len = len;
@@ -220,22 +220,12 @@ int ret;
 		if (!len) {
 			strcpy(col->bind_ptr, "");
 		} else {
-
+			//fprintf(stdout,"len %d size %d\n",len, col->col_size);
 			char *str;
 			if (col->col_type == MDB_NUMERIC) {
-                /*fprintf(stdout,"MDB_NUMERIC\n");*/
-				str = mdb_num_to_string(mdb, start,
-					col->col_type, col->col_prec,
-					col->col_scale);
-                /*fprintf(stdout,"mdb_num_to_string()=%d '%s'\n", strlen(str), \
str);*/ +				str = mdb_numeric_to_string(mdb, start, col->col_prec, col->col_scale);
 			} else {
-                /*fprintf(stdout,"!MDB_NUMERIC : %d len=%d\n", col->col_type, \
                len);*/
-				str = mdb_col_to_string(mdb, mdb->pg_buf, start,
-					col->col_type, len);
-                /*if (strlen(str) > MDB_BIND_SIZE) {
-                    fprintf(stdout, "!!!!!!\n");
-                }
-                fprintf(stdout,"mdb_col_to_string()=%d '%s'\n", strlen(str), str);*/
+				str = mdb_col_to_string(mdb, mdb->pg_buf, start, col->col_type, len);
 			}
 			strcpy(col->bind_ptr, str);
 			g_free(str);
@@ -253,7 +243,6 @@ int mdb_read_row(MdbTableDef *table, unsigned int row)
 	MdbHandle *mdb = table->entry->mdb;
 	MdbColumn *col;
 	unsigned int i;
-	int rc;
 	int row_start;
 	size_t row_size;
 	int delflag, lookupflag;
@@ -263,7 +252,10 @@ int mdb_read_row(MdbTableDef *table, unsigned int row)
 	if (table->num_rows == 0)
 		return 0;
 
-	mdb_find_row(mdb, row, &row_start, &row_size);
+	if (mdb_find_row(mdb, row, &row_start, &row_size)) {
+		fprintf(stderr, "warning: mdb_find_row failed.");
+		return 0;
+	}
 
 	delflag = lookupflag = 0;
 	if (row_start & 0x8000) lookupflag++;
@@ -289,14 +281,14 @@ int mdb_read_row(MdbTableDef *table, unsigned int row)
 #endif
 
 #if MDB_DEBUG
-	buffer_dump(mdb->pg_buf, row_start, row_size);
+	mdb_buffer_dump(mdb->pg_buf, row_start, row_size);
 #endif
 
 	/* take advantage of mdb_crack_row() to clean up binding */
 	/* use num_cols instead of num_fields -- bsb 03/04/02 */
 	for (i = 0; i < table->num_cols; i++) {
 		col = g_ptr_array_index(table->columns,fields[i].colnum);
-		rc = _mdb_attempt_bind(mdb, col, fields[i].is_null,
+		_mdb_attempt_bind(mdb, col, fields[i].is_null,
 			fields[i].start, fields[i].siz);
 	}
 
@@ -315,13 +307,15 @@ static int _mdb_attempt_bind(MdbHandle *mdb,
 	} else if (col->col_type == MDB_OLE) {
 		mdb_xfer_bound_ole(mdb, offset, col, len);
 	} else {
-
-
-
+		//if (!mdb_test_sargs(mdb, col, offset, len)) {
+			//return 0;
+		//}
 		mdb_xfer_bound_data(mdb, offset, col, len);
 	}
 	return 1;
 }
+
+/* Read next data page into mdb->pg_buf */
 int mdb_read_next_dpg(MdbTableDef *table)
 {
 	MdbCatalogEntry *entry = table->entry;
@@ -329,16 +323,28 @@ int mdb_read_next_dpg(MdbTableDef *table)
 	int next_pg;
 
 #ifndef SLOW_READ
-	next_pg = mdb_map_find_next(mdb, table->usage_map,
-		table->map_sz, table->cur_phys_pg);
+	while (1) {
+		next_pg = mdb_map_find_next(mdb, table->usage_map,
+			table->map_sz, table->cur_phys_pg);
+		if (next_pg < 0)
+			break; /* unknow map type: goto fallback */
+		if (!next_pg)
+			return 0;
 
-	if (next_pg >= 0) {
-		if (mdb_read_pg(mdb, next_pg)) {
-			table->cur_phys_pg = next_pg;
-			return table->cur_phys_pg;
-		} else {
+		if (!mdb_read_pg(mdb, next_pg)) {
+			fprintf(stderr, "error: reading page %d failed.\n", next_pg);
 			return 0;
 		}
+
+		table->cur_phys_pg = next_pg;
+		if (mdb->pg_buf[0]==MDB_PAGE_DATA && mdb_get_int32(mdb->pg_buf, \
4)==entry->table_pg) +			return table->cur_phys_pg;
+
+		/* On rare occasion, mdb_map_find_next will return a wrong page */
+		/* Found in a big file, over 4,000,000 records */
+		fprintf(stderr,
+			"warning: page %d from map doesn't match: Type=%d, buf[4..7]=%ld Expected \
table_pg=%ld\n", +			next_pg, mdb->pg_buf[0], mdb_get_int32(mdb->pg_buf, 4), \
entry->table_pg);  }
 	fprintf(stderr, "Warning: defaulting to brute force read\n");
 #endif
@@ -346,7 +352,7 @@ int mdb_read_next_dpg(MdbTableDef *table)
 	do {
 		if (!mdb_read_pg(mdb, table->cur_phys_pg++))
 			return 0;
-	} while (mdb->pg_buf[0]!=0x01 || mdb_get_int32(mdb->pg_buf, 4)!=entry->table_pg);
+	} while (mdb->pg_buf[0]!=MDB_PAGE_DATA || mdb_get_int32(mdb->pg_buf, \
4)!=entry->table_pg);  /* fprintf(stderr,"returning new page %ld\n", \
table->cur_phys_pg); */  return table->cur_phys_pg;
 }
@@ -403,7 +409,7 @@ mdb_fetch_row(MdbTableDef *table)
 		} else {
 			rows = mdb_get_int16(mdb->pg_buf,fmt->row_count_offset);
 
-			/* if at end of page, find a new page */
+			/* if at end of page, find a new data page */
 			if (table->cur_row >= rows) {
 				table->cur_row=0;
 
@@ -457,6 +463,12 @@ int i;
 	return text;
 }
 #endif
+/*
+ * ole_ptr should point to the original blob value of the field.
+ * If omited, there will be no multi-page check to that the caller is
+ * responsible for not calling this function. Then, it doesn't have to
+ * preserve the original value.
+ */
 size_t
 mdb_ole_read_next(MdbHandle *mdb, MdbColumn *col, void *ole_ptr)
 {
@@ -465,24 +477,30 @@ mdb_ole_read_next(MdbHandle *mdb, MdbColumn *col, void \
*ole_ptr)  int row_start;
 	size_t len;
 
-	ole_len = mdb_get_int32(ole_ptr, 0);
+	if (ole_ptr) {
+		ole_len = mdb_get_int32(ole_ptr, 0);
+		mdb_debug(MDB_DEBUG_OLE,"ole len = %d ole flags = %02x",
+		    ole_len & 0x00ffffff, ole_len >> 24);
 
-	if ((ole_len & 0x80000000)
-	 || (ole_len & 0x40000000)) {
-		/* inline or single-page fields don't have a next */
-		return 0;
-	} else {
-		if (mdb_find_pg_row(mdb, col->cur_blob_pg_row,
-			&buf, &row_start, &len)) {
+		if ((ole_len & 0x80000000)
+		 || (ole_len & 0x40000000))
+			/* inline or single-page fields don't have a next */
 			return 0;
-		}
-		if (col->bind_ptr)
-			memcpy(col->bind_ptr, (char*)buf + row_start + 4, len - 4);
-		col->cur_blob_pg_row = mdb_get_int32(buf, row_start);
-
-		return len;
 	}
-	return 0;
+	mdb_debug(MDB_DEBUG_OLE, "pg_row %d", col->cur_blob_pg_row);
+	if (!col->cur_blob_pg_row)
+		return 0; /* we are done */
+	if (mdb_find_pg_row(mdb, col->cur_blob_pg_row,
+		&buf, &row_start, &len)) {
+		return 0;
+	}
+	mdb_debug(MDB_DEBUG_OLE,"start %d len %d", row_start, len);
+
+	if (col->bind_ptr)
+		memcpy(col->bind_ptr, (char*)buf + row_start + 4, len - 4);
+	col->cur_blob_pg_row = mdb_get_int32(buf, row_start);
+
+	return len - 4;
 }
 size_t
 mdb_ole_read(MdbHandle *mdb, MdbColumn *col, void *ole_ptr, int chunk_size)
@@ -526,26 +544,64 @@ mdb_ole_read(MdbHandle *mdb, MdbColumn *col, void *ole_ptr, int \
chunk_size)  if (col->bind_ptr) {
 			memcpy(col->bind_ptr, (char*)buf + row_start, len);
 			if (mdb_get_option(MDB_DEBUG_OLE))
-				buffer_dump(col->bind_ptr, 0, 16);
+				mdb_buffer_dump(col->bind_ptr, 0, 16);
 		}
 		return len;
 	} else if ((ole_len & 0xff000000) == 0) {
 		col->cur_blob_pg_row = mdb_get_int32(ole_ptr, 4);
+		mdb_debug(MDB_DEBUG_OLE,"ole row = %d ole pg = %ld",
+			col->cur_blob_pg_row & 0xff,
+			col->cur_blob_pg_row >> 8);
 
 		if (mdb_find_pg_row(mdb, col->cur_blob_pg_row,
 			&buf, &row_start, &len)) {
 			return 0;
 		}
+		mdb_debug(MDB_DEBUG_OLE,"start %d len %d", row_start, len);
+
 		if (col->bind_ptr)
 			memcpy(col->bind_ptr, (char*)buf + row_start + 4, len - 4);
 		col->cur_blob_pg_row = mdb_get_int32(buf, row_start);
+		mdb_debug(MDB_DEBUG_OLE, "next pg_row %d", col->cur_blob_pg_row);
 
-		return len;
+		return len - 4;
 	} else {
 		fprintf(stderr,"Unhandled ole field flags = %02x\n", ole_len >> 24);
 		return 0;
 	}
 }
+/*
+ * mdb_ole_read_full calls mdb_ole_read then loop over mdb_ole_read_next as much as \
necessary. + * returns the result in a big buffer.
+ * The call must free it.
+ * Note that this function is not indempotent: It may be called only once per column \
after each bind. + */
+void*
+mdb_ole_read_full(MdbHandle *mdb, MdbColumn *col, size_t *size)
+{
+	char ole_ptr[MDB_MEMO_OVERHEAD];
+	char *result = malloc(MDB_BIND_SIZE);
+	size_t result_buffer_size = MDB_BIND_SIZE;
+	size_t len, pos;
+
+	memcpy(ole_ptr, col->bind_ptr, MDB_MEMO_OVERHEAD);
+
+	len = mdb_ole_read(mdb, col, ole_ptr, MDB_BIND_SIZE);
+	memcpy(result, col->bind_ptr, len);
+	pos = len;
+	while ((len = mdb_ole_read_next(mdb, col, ole_ptr))) {
+		if (pos+len >= result_buffer_size) {
+			result_buffer_size += MDB_BIND_SIZE;
+			result = realloc(result, result_buffer_size);
+		}
+		memcpy(result + pos, col->bind_ptr, len);
+		pos += len;
+	}
+	if (size)
+		*size = pos;
+	return result;
+}
+
 #ifdef MDB_COPY_OLE
 static size_t mdb_copy_ole(MdbHandle *mdb, void *dest, int start, int size)
 {
@@ -617,17 +673,15 @@ static char *mdb_memo_to_string(MdbHandle *mdb, int start, int \
size)  gint32 row_start, pg_row;
 	size_t len;
 	void *buf, *pg_buf = mdb->pg_buf;
-	char *text = 0;
+	char *text = (char *) g_malloc(MDB_BIND_SIZE);
 
-    /*printf("mdb_memo_to_string: size=%d\n", size);*/
 	if (size<MDB_MEMO_OVERHEAD) {
-		text = (char *) g_malloc(MDB_BIND_SIZE);
 		strcpy(text, "");
 		return text;
 	}
 
 #if MDB_DEBUG
-	buffer_dump(pg_buf, start, MDB_MEMO_OVERHEAD);
+	mdb_buffer_dump(pg_buf, start, MDB_MEMO_OVERHEAD);
 #endif
 
 	/* The 32 bit integer at offset 0 is the length of the memo field
@@ -635,18 +689,13 @@ static char *mdb_memo_to_string(MdbHandle *mdb, int start, int \
                size)
 	 * The 32 bit integer at offset 4 contains page and row information.
 	 */
 	memo_len = mdb_get_int32(pg_buf, start);
-    /*printf("memo_len=%d\n", memo_len);*/
 
 	if (memo_len & 0x80000000) {
-		text = (char *) g_malloc(MDB_BIND_SIZE);
-        /*printf("INLINE MEMO\n");*/
 		/* inline memo field */
 		mdb_unicode2ascii(mdb, (char*)pg_buf + start + MDB_MEMO_OVERHEAD,
 			size - MDB_MEMO_OVERHEAD, text, MDB_BIND_SIZE);
 		return text;
 	} else if (memo_len & 0x40000000) {
-		text = (char *) g_malloc(MDB_BIND_SIZE);
-        /*printf("SINGLE-PAGE MEMO\n");*/
 		/* single-page memo field */
 		pg_row = mdb_get_int32(pg_buf, start+4);
 #if MDB_DEBUG
@@ -659,12 +708,11 @@ static char *mdb_memo_to_string(MdbHandle *mdb, int start, int \
size)  #if MDB_DEBUG
 		printf("row num %d start %d len %d\n",
 			pg_row & 0xff, row_start, len);
-		buffer_dump(buf, row_start, len);
+		mdb_buffer_dump(buf, row_start, len);
 #endif
 		mdb_unicode2ascii(mdb, (char*)buf + row_start, len, text, MDB_BIND_SIZE);
 		return text;
-	} else if ((memo_len & 0xff000000) == 0) { /* assume all flags in MSB */
-        /*printf("MULTI-PAGE MEMO\n");*/
+	} else if ((memo_len & 0xff000000) == 0) { // assume all flags in MSB
 		/* multi-page memo field */
 		guint32 tmpoff = 0;
 		char *tmp;
@@ -693,9 +741,7 @@ static char *mdb_memo_to_string(MdbHandle *mdb, int start, int \
size)  if (tmpoff < memo_len) {
 			fprintf(stderr, "Warning: incorrect memo length\n");
 		}
-        /*printf("ALLOCATING tmpoff *2: %d\n", tmpoff * 2);*/
-		text = (char *) g_malloc(tmpoff);
-		mdb_unicode2ascii(mdb, tmp, tmpoff, text, tmpoff);
+		mdb_unicode2ascii(mdb, tmp, tmpoff, text, MDB_BIND_SIZE);
 		g_free(tmp);
 		return text;
 	} else {
@@ -704,28 +750,8 @@ static char *mdb_memo_to_string(MdbHandle *mdb, int start, int \
size)  return text;
 	}
 }
-static char *
-mdb_num_to_string(MdbHandle *mdb, int start, int datatype, int prec, int scale)
-{
-	char *text;
-	int negative;
-	gint32 l;
-
-	memcpy(&l, mdb->pg_buf+start+13, 4);
-	negative = (*(mdb->pg_buf+start) & 0x80) ? 1 : 0;
-	text = (char *) g_malloc(prec+2+negative);
-	if (negative) {
-		sprintf(text, "-%0*" G_GINT32_FORMAT, prec, GINT32_FROM_LE(l));
-	} else {
-		sprintf(text, "%0*" G_GINT32_FORMAT, prec, GINT32_FROM_LE(l));
-	}
-	if (scale) {
-		memmove(text+prec-scale+1+negative, text+prec-scale+negative, scale+1);
-		text[prec-scale+negative] = '.';
-	}
-	return text;
-}
 
+#if 0
 static int trim_trailing_zeros(char * buff)
 {
 	char *p;
@@ -746,66 +772,96 @@ static int trim_trailing_zeros(char * buff)
 
 	return 0;
 }
+#endif
 
 /* Date/Time is stored as a double, where the whole
    part is the days from 12/30/1899 and the fractional
    part is the fractional part of one day. */
-static char *
-mdb_date_to_string(MdbHandle *mdb, int start)
+
+void
+mdb_date_to_tm(double td, struct tm *t)
 {
-	struct tm t;
 	long int day, time;
 	int yr, q;
 	int *cal;
 	int noleap_cal[] = {0,31,59,90,120,151,181,212,243,273,304,334,365};
 	int leap_cal[]   = {0,31,60,91,121,152,182,213,244,274,305,335,366};
 
-	char *text = (char *) g_malloc(MDB_BIND_SIZE);
-	double td = mdb_get_double(mdb->pg_buf, start);
-
 	day = (long int)(td);
 	time = (long int)(fabs(td - day) * 86400.0 + 0.5);
-	t.tm_hour = time / 3600;
-	t.tm_min = (time / 60) % 60;
-	t.tm_sec = time % 60;
-	t.tm_year = 1 - 1900;
+	t->tm_hour = time / 3600;
+	t->tm_min = (time / 60) % 60;
+	t->tm_sec = time % 60;
+	t->tm_year = 1 - 1900;
 
 	day += 693593; /* Days from 1/1/1 to 12/31/1899 */
-	t.tm_wday = (day+1) % 7;
+	t->tm_wday = (day+1) % 7;
 
 	q = day / 146097;  /* 146097 days in 400 years */
-	t.tm_year += 400 * q;
+	t->tm_year += 400 * q;
 	day -= q * 146097;
 
 	q = day / 36524;  /* 36524 days in 100 years */
 	if (q > 3) q = 3;
-	t.tm_year += 100 * q;
+	t->tm_year += 100 * q;
 	day -= q * 36524;
 
 	q = day / 1461;  /* 1461 days in 4 years */
-	t.tm_year += 4 * q;
+	t->tm_year += 4 * q;
 	day -= q * 1461;
 
 	q = day / 365;  /* 365 days in 1 year */
 	if (q > 3) q = 3;
-	t.tm_year += q;
+	t->tm_year += q;
 	day -= q * 365;
 
-	yr = t.tm_year + 1900;
+	yr = t->tm_year + 1900;
 	cal = ((yr)%4==0 && ((yr)%100!=0 || (yr)%400==0)) ?
 		leap_cal : noleap_cal;
-	for (t.tm_mon=0; t.tm_mon<12; t.tm_mon++) {
-		if (day < cal[t.tm_mon+1]) break;
+	for (t->tm_mon=0; t->tm_mon<12; t->tm_mon++) {
+		if (day < cal[t->tm_mon+1]) break;
 	}
-	t.tm_mday = day - cal[t.tm_mon] + 1;
-	t.tm_yday = day;
-	t.tm_isdst = -1;
+	t->tm_mday = day - cal[t->tm_mon] + 1;
+	t->tm_yday = day;
+	t->tm_isdst = -1;
+}
+
+static char *
+mdb_date_to_string(MdbHandle *mdb, int start)
+{
+	struct tm t;
+	char *text = (char *) g_malloc(MDB_BIND_SIZE);
+	double td = mdb_get_double(mdb->pg_buf, start);
+
+	mdb_date_to_tm(td, &t);
 
 	strftime(text, MDB_BIND_SIZE, date_fmt, &t);
 
 	return text;
 }
 
+static char *
+mdb_uuid_to_string(MdbHandle *mdb, int start)
+{
+	char *text = NULL;
+  unsigned short uuid1, uuid2, uuid3, uuid4, uuid5, uuid6, uuid7, uuid8;
+
+  uuid1 = mdb_get_int16(mdb->pg_buf, start);
+  uuid2 = mdb_get_int16(mdb->pg_buf, start + 2);
+  uuid3 = mdb_get_int16(mdb->pg_buf, start + 4);
+  uuid4 = mdb_get_int16(mdb->pg_buf, start + 6);
+  uuid5 = mdb_get_int16(mdb->pg_buf, start + 8);
+  uuid6 = mdb_get_int16(mdb->pg_buf, start + 10);
+  uuid7 = mdb_get_int16(mdb->pg_buf, start + 12);
+  uuid8 = mdb_get_int16(mdb->pg_buf, start + 14);
+
+  text = g_strdup_printf("{%04x%04x-%04x-%04x-%04x-%04x%04x%04x}",
+    uuid1, uuid2, uuid3, uuid4, uuid5, uuid6, uuid7, uuid8);
+
+	return text;
+}
+
+#if 0
 int floor_log10(double f, int is_single)
 {
 	unsigned int i;
@@ -814,7 +870,7 @@ int floor_log10(double f, int is_single)
 	if (f < 0.0)
 		f = -f;
 
-	if ((f == 0.0) || (f == 1.0)) {
+	if ((f == 0.0) || (f == 1.0) || isinf(f)) {
 		return 0;
 	} else if (f < 1.0) {
 		if (is_single) {
@@ -834,6 +890,7 @@ int floor_log10(double f, int is_single)
 		return (int)i;
 	}
 }
+#endif
 
 char *mdb_col_to_string(MdbHandle *mdb, void *buf, int start, int datatype, int \
size)  {
@@ -850,24 +907,29 @@ char *mdb_col_to_string(MdbHandle *mdb, void *buf, int start, \
int datatype, int  text = g_strdup_printf("%d", mdb_get_byte(buf, start));
 		break;
 		case MDB_INT:
-			text = g_strdup_printf("%ld",
-				(long)mdb_get_int16(buf, start));
+			text = g_strdup_printf("%hd",
+				(short)mdb_get_int16(buf, start));
 		break;
 		case MDB_LONGINT:
+		case MDB_COMPLEX:
 			text = g_strdup_printf("%ld",
 				mdb_get_int32(buf, start));
 		break;
 		case MDB_FLOAT:
 			tf = mdb_get_single(buf, start);
-			text = g_strdup_printf("%.*f",
-				FLT_DIG - floor_log10(tf,1) - 1, tf);
-			trim_trailing_zeros(text);
+			text = g_strdup_printf("%.8e", tf);
 		break;
 		case MDB_DOUBLE:
 			td = mdb_get_double(buf, start);
-			text = g_strdup_printf("%.*f",
-				DBL_DIG - floor_log10(td,0) - 1, td);
-			trim_trailing_zeros(text);
+			text = g_strdup_printf("%.16e", td);
+		break;
+		case MDB_BINARY:
+			if (size<0) {
+				text = g_strdup("");
+			} else {
+				text = g_malloc(size);
+				memcpy((char*)buf+start, text, size);
+			}
 		break;
 		case MDB_TEXT:
 			if (size<0) {
@@ -878,7 +940,7 @@ char *mdb_col_to_string(MdbHandle *mdb, void *buf, int start, int \
datatype, int  size, text, MDB_BIND_SIZE);
 			}
 		break;
-		case MDB_SDATETIME:
+		case MDB_DATETIME:
 			text = mdb_date_to_string(mdb, start);
 		break;
 		case MDB_MEMO:
@@ -888,6 +950,9 @@ char *mdb_col_to_string(MdbHandle *mdb, void *buf, int start, int \
datatype, int  text = mdb_money_to_string(mdb, start);
 		case MDB_NUMERIC:
 		break;
+		case MDB_REPID:
+		  text = mdb_uuid_to_string(mdb, start);
+		break;
 		default:
 			text = g_strdup("");
 		break;
@@ -907,6 +972,7 @@ int mdb_col_disp_size(MdbColumn *col)
 			return 6;
 		break;
 		case MDB_LONGINT:
+		case MDB_COMPLEX:
 			return 11;
 		break;
 		case MDB_FLOAT:
@@ -918,7 +984,7 @@ int mdb_col_disp_size(MdbColumn *col)
 		case MDB_TEXT:
 			return col->col_size;
 		break;
-		case MDB_SDATETIME:
+		case MDB_DATETIME:
 			return 20;
 		break;
 		case MDB_MEMO:
@@ -943,6 +1009,7 @@ int mdb_col_fixed_size(MdbColumn *col)
 			return 2;
 		break;
 		case MDB_LONGINT:
+		case MDB_COMPLEX:
 			return 4;
 		break;
 		case MDB_FLOAT:
@@ -954,9 +1021,12 @@ int mdb_col_fixed_size(MdbColumn *col)
 		case MDB_TEXT:
 			return -1;
 		break;
-		case MDB_SDATETIME:
+		case MDB_DATETIME:
 			return 4;
 		break;
+		case MDB_BINARY:
+			return -1;
+		break;
 		case MDB_MEMO:
 			return -1;
 		break;
diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/dump.c \
b/src/migration/mdb/3rdparty/mdbtools/libmdb/dump.c index ffd9c11..afa002d 100644
--- a/src/migration/mdb/3rdparty/mdbtools/libmdb/dump.c
+++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/dump.c
@@ -1,3 +1,21 @@
+/* MDB Tools - A library for reading MS Access database files
+ * Copyright (C) 2000-2011 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
+ */
+
 #include <ctype.h>
 #include <string.h>
 #include <stdio.h>
@@ -6,7 +24,7 @@
 #include "dmalloc.h"
 #endif
 
-void buffer_dump(const void* buf, int start, size_t len)
+void mdb_buffer_dump(const void* buf, int start, size_t len)
 {
 	char asc[20];
 	int j, k;
diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/file.c \
b/src/migration/mdb/3rdparty/mdbtools/libmdb/file.c index d8688d2..1792e9f 100644
--- a/src/migration/mdb/3rdparty/mdbtools/libmdb/file.c
+++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/file.c
@@ -12,11 +12,11 @@
  * 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.
+ * 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 <inttypes.h>
 #include "mdbtools.h"
 
 #ifdef DMALLOC
@@ -35,7 +35,7 @@ typedef struct {
 	guint16		tab_first_dpg_offset;
 	guint16		tab_cols_start_offset;
 	guint16		tab_ridx_entry_size;
-	guint16		col_fixed_offset;
+	guint16		col_flags_offset;
 	guint16		col_size_offset;
 	guint16		col_num_offset;
 	guint16		tab_col_entry_size;
@@ -52,8 +52,69 @@ MdbFormatConstants MdbJet3Constants = {
 	2048, 0x08, 12, 25, 27, 31, 35, 36, 43, 8, 13, 16, 1, 18, 39, 3, 14, 5
 };
 
+typedef struct _RC4_KEY
+{
+	unsigned char state[256];
+	unsigned char x;
+	unsigned char y;
+} RC4_KEY;
+
+#define swap_byte(x,y) t = *(x); *(x) = *(y); *(y) = t
+
 static ssize_t _mdb_read_pg(MdbHandle *mdb, void *pg_buf, unsigned long pg);
 
+static void RC4_set_key(RC4_KEY *key, int key_data_len, unsigned char *key_data_ptr)
+{
+	unsigned char t;
+	unsigned char index1;
+	unsigned char index2;
+	unsigned char* state;
+	short counter;
+
+	state = &key->state[0];
+	for(counter = 0; counter < 256; counter++)
+		state[counter] = counter;
+	key->x = 0;
+	key->y = 0;
+	index1 = 0;
+	index2 = 0;
+	for(counter = 0; counter < 256; counter++) {
+		index2 = (key_data_ptr[index1] + state[counter] + index2) % 256;
+		swap_byte(&state[counter], &state[index2]);
+		index1 = (index1 + 1) % key_data_len;
+	}
+}
+
+/*
+ * this algorithm does 'encrypt in place' instead of inbuff/outbuff
+ * note also: encryption and decryption use same routine
+ * implementation supplied by (Adam Back) at <adam at cypherspace dot org>
+ */
+
+static void RC4(RC4_KEY *key, int buffer_len, unsigned char * buff)
+{
+	unsigned char t;
+	unsigned char x;
+	unsigned char y;
+	unsigned char* state;
+	unsigned char xorIndex;
+	short counter;
+
+	x = key->x;
+	y = key->y;
+	state = &key->state[0];
+	for(counter = 0; counter < buffer_len; counter++) {
+		x = (x + 1) % 256;
+		y = (state[x] + y) % 256;
+		swap_byte(&state[x], &state[y]);
+		xorIndex = (state[x] + state[y]) % 256;
+		buff[counter] ^= state[xorIndex];
+	}
+	key->x = x;
+	key->y = y;
+}
+
+
 /**
  * mdb_find_file:
  * @filename: path to MDB (database) file
@@ -73,7 +134,11 @@ static char *mdb_find_file(const char *file_name)
 
 	/* try the provided file name first */
 	if (!stat(file_name, &status)) {
-		return g_strdup(file_name);
+		char *result;
+		result = g_strdup(file_name);
+		if (!result)
+			fprintf(stderr, "Can't alloc filename\n");
+		return result;
 	}
 
 	/* Now pull apart $MDBPATH and try those */
@@ -134,6 +199,8 @@ void mdb_set_encoding(MdbHandle *mdb, const char *encoding_name)
 MdbHandle *mdb_open(const char *filename, MdbFileFlags flags)
 {
 	MdbHandle *mdb;
+	int key[] = {0x86, 0xfb, 0xec, 0x37, 0x5d, 0x44, 0x9c, 0xfa, 0xc6, 0x5e, 0x28, \
0xe6, 0x13, 0xb6}; +	int j, pos;
 	int open_flags;
 
 	mdb = (MdbHandle *) g_malloc0(sizeof(MdbHandle));
@@ -152,7 +219,7 @@ MdbHandle *mdb_open(const char *filename, MdbFileFlags flags)
 	mdb->f->fd = -1;
 	mdb->f->filename = mdb_find_file(filename);
 	if (!mdb->f->filename) {
-		fprintf(stderr, "Can't alloc filename\n");
+		fprintf(stderr, "File not found\n");
 		mdb_close(mdb);
 		return NULL;
 	}
@@ -184,15 +251,56 @@ MdbHandle *mdb_open(const char *filename, MdbFileFlags flags)
 		return NULL;
 	}
 	mdb->f->jet_version = mdb_get_int32(mdb->pg_buf, 0x14);
-	if (IS_JET4(mdb)) {
-		mdb->fmt = &MdbJet4Constants;
-	} else if (IS_JET3(mdb)) {
+	switch(mdb->f->jet_version) {
+	case MDB_VER_JET3:
 		mdb->fmt = &MdbJet3Constants;
-	} else {
+		break;
+	case MDB_VER_JET4:
+	case MDB_VER_ACCDB_2007:
+	case MDB_VER_ACCDB_2010:
+		mdb->fmt = &MdbJet4Constants;
+		break;
+	default:
 		fprintf(stderr,"Unknown Jet version.\n");
 		mdb_close(mdb);
 		return NULL;
 	}
+	mdb->f->db_key = mdb_get_int32(mdb->pg_buf, 0x3e);
+	/* I don't know if this value is valid for some versions?
+	 * it doesn't seem to be valid for the databases I have
+	 *
+	 * f->db_key ^= 0xe15e01b9;
+	 */
+	mdb->f->db_key ^= 0x4ebc8afb;
+	/* fprintf(stderr, "Encrypted file, RC4 key seed= %d\n", mdb->f->db_key); */
+	if (mdb->f->db_key) {
+		/* write is not supported for encrypted files yet */
+		mdb->f->writable = FALSE;
+		/* that should be enought, but reopen the file read only just to be
+		 * sure we don't write invalid data */
+		close(mdb->f->fd);
+		open_flags = O_RDONLY;
+#ifdef _WIN32
+		open_flags |= O_BINARY;
+#endif
+		mdb->f->fd = open(mdb->f->filename, open_flags);
+		if (mdb->f->fd==-1) {
+			fprintf(stderr, "Couldn't ropen file %s in read only\n", mdb->f->filename);
+			mdb_close(mdb);
+			return NULL;
+		}
+	}
+
+	/* get the db password located at 0x42 bytes into the file */
+	for (pos=0;pos<14;pos++) {
+		j = mdb_get_int32(mdb->pg_buf, 0x42+pos);
+		j ^= key[pos];
+		if ( j != 0)
+			mdb->f->db_passwd[pos] = j;
+		else
+			mdb->f->db_passwd[pos] = '\0';
+	}
+
 	mdb_iconv_init(mdb);
 
 	return mdb;
@@ -282,7 +390,7 @@ ssize_t mdb_read_pg(MdbHandle *mdb, unsigned long pg)
 	if (pg && mdb->cur_pg == pg) return mdb->fmt->pg_size;
 
 	len = _mdb_read_pg(mdb, mdb->pg_buf, pg);
-
+	//fprintf(stderr, "read page %d type %02x\n", pg, mdb->pg_buf[0]);
 	mdb->cur_pg = pg;
 	/* kan - reset the cur_pos on a new page read */
 	mdb->cur_pos = 0; /* kan */
@@ -303,7 +411,7 @@ static ssize_t _mdb_read_pg(MdbHandle *mdb, void *pg_buf, \
unsigned long pg)  
         fstat(mdb->f->fd, &status);
         if (status.st_size < offset) {
-                fprintf(stderr,"offset %lu is beyond EOF\n",offset);
+                fprintf(stderr,"offset %jd is beyond EOF\n",(intmax_t)offset);
                 return 0;
         }
 #if !MDB_NO_STATS
@@ -320,6 +428,18 @@ static ssize_t _mdb_read_pg(MdbHandle *mdb, void *pg_buf, \
unsigned long pg)  /* fprintf(stderr,"EOF reached %d bytes returned.\n",len, \
mdb->fmt->pg_size); */  return 0;
 	}
+	/*
+	 * unencrypt the page if necessary.
+	 * it might make sense to cache the unencrypted data blocks?
+	 */
+	if (pg != 0 && mdb->f->db_key != 0)
+	{
+		RC4_KEY rc4_key;
+		unsigned int tmp_key = mdb->f->db_key ^ pg;
+		RC4_set_key(&rc4_key, 4, (unsigned char *)&tmp_key);
+		RC4(&rc4_key, mdb->fmt->pg_size, pg_buf);
+	}
+
 	return len;
 }
 void mdb_swap_pgbuf(MdbHandle *mdb)
diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/iconv.c \
b/src/migration/mdb/3rdparty/mdbtools/libmdb/iconv.c index ab19cbd..7f19cc0 100644
--- a/src/migration/mdb/3rdparty/mdbtools/libmdb/iconv.c
+++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/iconv.c
@@ -12,13 +12,12 @@
  * 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.
+ * 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 <errno.h>
 #include "mdbtools.h"
-#include "errno.h"
 
 #ifdef DMALLOC
 #include "dmalloc.h"
@@ -43,7 +42,7 @@ mdb_unicode2ascii(MdbHandle *mdb, char *src, size_t slen, char \
*dest, size_t dle  return 0;
 
 	/* Uncompress 'Unicode Compressed' string into tmp */
-	if (IS_JET4(mdb) && (slen>=2)
+	if (!IS_JET3(mdb) && (slen>=2)
 	 && ((src[0]&0xff)==0xff) && ((src[1]&0xff)==0xfe)) {
 		unsigned int compress=1;
 		src += 2;
@@ -72,22 +71,25 @@ mdb_unicode2ascii(MdbHandle *mdb, char *src, size_t slen, char \
*dest, size_t dle  len_out = dlen;
 
 #if HAVE_ICONV
-
+	//printf("1 len_in %d len_out %d\n",len_in, len_out);
 	while (1) {
 		iconv(mdb->iconv_in, &in_ptr, &len_in, &out_ptr, &len_out);
 		if ((!len_in) || (errno == E2BIG)) break;
 		/* Don't bail if impossible conversion is encountered */
-		in_ptr += (IS_JET4(mdb)) ? 2 : 1;
-		len_in -= (IS_JET4(mdb)) ? 2 : 1;
+		in_ptr += (IS_JET3(mdb)) ? 1 : 2;
+		len_in -= (IS_JET3(mdb)) ? 1 : 2;
 		*out_ptr++ = '?';
 		len_out--;
 	}
-
+	//printf("2 len_in %d len_out %d\n",len_in, len_out);
 	dlen -= len_out;
 #else
 	if (IS_JET3(mdb)) {
-		strncpy(out_ptr, in_ptr, len_in);
-		dlen = len_in;
+               size_t copy_len = len_in;
+               if (copy_len > dlen)
+                       copy_len = dlen;
+               strncpy(out_ptr, in_ptr, copy_len);
+               dlen = copy_len;
 	} else {
 		/* rough UCS-2LE to ISO-8859-1 conversion */
 		unsigned int i;
@@ -99,7 +101,7 @@ mdb_unicode2ascii(MdbHandle *mdb, char *src, size_t slen, char \
*dest, size_t dle  
 	if (tmp) g_free(tmp);
 	dest[dlen]='\0';
-
+	//printf("dest %s\n",dest);
 	return dlen;
 }
 
@@ -123,7 +125,7 @@ mdb_ascii2unicode(MdbHandle *mdb, char *src, size_t slen, char \
*dest, size_t dle  
 #ifdef HAVE_ICONV
 	iconv(mdb->iconv_out, &in_ptr, &len_in, &out_ptr, &len_out);
-
+	//printf("len_in %d len_out %d\n", len_in, len_out);
 	dlen -= len_out;
 #else
 	if (IS_JET3(mdb)) {
@@ -141,7 +143,7 @@ mdb_ascii2unicode(MdbHandle *mdb, char *src, size_t slen, char \
*dest, size_t dle  #endif
 
 	/* Unicode Compression */
-	if(IS_JET4(mdb) && (dlen>4)) {
+	if(!IS_JET3(mdb) && (dlen>4)) {
 		unsigned char *tmp = g_malloc(dlen);
 		unsigned int tptr = 0, dptr = 0;
 		int comp = 1;
@@ -182,6 +184,21 @@ mdb_ascii2unicode(MdbHandle *mdb, char *src, size_t slen, char \
*dest, size_t dle  return dlen;
 }
 
+const char*
+mdb_target_charset(MdbHandle *mdb)
+{
+#ifdef HAVE_ICONV
+	const char *iconv_code = getenv("MDBICONV");
+	if (!iconv_code)
+		iconv_code = "UTF-8";
+	return iconv_code;
+#else
+	if (!IS_JET3(mdb))
+		return "ISO-8859-1";
+	return NULL; // same as input: unknown
+#endif
+}
+
 void mdb_iconv_init(MdbHandle *mdb)
 {
 	const char *iconv_code;
@@ -192,10 +209,10 @@ void mdb_iconv_init(MdbHandle *mdb)
 	}
 
 #ifdef HAVE_ICONV
-        if (IS_JET4(mdb)) {
-                mdb->iconv_out = iconv_open("UCS-2LE", iconv_code);
-                mdb->iconv_in = iconv_open(iconv_code, "UCS-2LE");
-        } else {
+	if (!IS_JET3(mdb)) {
+		mdb->iconv_out = iconv_open("UCS-2LE", iconv_code);
+		mdb->iconv_in = iconv_open(iconv_code, "UCS-2LE");
+	} else {
 		/* According to Microsoft Knowledge Base pages 289525 and */
 		/* 202427, code page info is not contained in the database */
 
@@ -208,8 +225,9 @@ void mdb_iconv_init(MdbHandle *mdb)
 			// get the default from OS
 			char default_encoding[] = "CP       ";
 			if (GetLocaleInfoA( MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), \
                SORT_DEFAULT),
-			 LOCALE_IDEFAULTANSICODEPAGE, default_encoding+2, sizeof(default_encoding)-2-1 ))
+			        LOCALE_IDEFAULTANSICODEPAGE, default_encoding+2, \
sizeof(default_encoding)-2-1 )) {  mdb->jet3_iconv_code = g_strdup(default_encoding);
+			}
 			else
 #endif
 				mdb->jet3_iconv_code = g_strdup("CP1252");
@@ -223,7 +241,9 @@ void mdb_iconv_init(MdbHandle *mdb)
 void mdb_iconv_close(MdbHandle *mdb)
 {
 #ifdef HAVE_ICONV
-        if (mdb->iconv_out != (iconv_t)-1) iconv_close(mdb->iconv_out);
-        if (mdb->iconv_in != (iconv_t)-1) iconv_close(mdb->iconv_in);
+    if (mdb->iconv_out != (iconv_t)-1) iconv_close(mdb->iconv_out);
+    if (mdb->iconv_in != (iconv_t)-1) iconv_close(mdb->iconv_in);
 #endif
 }
+
+
diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/index.c \
b/src/migration/mdb/3rdparty/mdbtools/libmdb/index.c index f517f2b..865d5a4 100644
--- a/src/migration/mdb/3rdparty/mdbtools/libmdb/index.c
+++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/index.c
@@ -12,9 +12,8 @@
  * 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.
+ * 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 "mdbtools.h"
@@ -69,24 +68,29 @@ mdb_read_indices(MdbTableDef *table)
 	MdbHandle *mdb = entry->mdb;
 	MdbFormatConstants *fmt = mdb->fmt;
 	MdbIndex *pidx;
-	unsigned int i, j;
-	int idx_num, key_num, col_num;
+	unsigned int i, j, k;
+	int key_num, col_num, cleaned_col_num;
 	int cur_pos, name_sz, idx2_sz, type_offset;
 	int index_start_pg = mdb->cur_pg;
 	gchar *tmpbuf;
 
-        table->indices = g_ptr_array_new();
+	table->indices = g_ptr_array_new();
 
-        if (IS_JET4(mdb)) {
-		cur_pos = table->index_start + 52 * table->num_real_idxs;
-		idx2_sz = 28;
-		type_offset = 23;
-	} else {
+	if (IS_JET3(mdb)) {
 		cur_pos = table->index_start + 39 * table->num_real_idxs;
 		idx2_sz = 20;
 		type_offset = 19;
+	} else {
+		cur_pos = table->index_start + 52 * table->num_real_idxs;
+		idx2_sz = 28;
+		type_offset = 23;
 	}
 
+	//fprintf(stderr, "num_idxs:%d num_real_idxs:%d\n", table->num_idxs, \
table->num_real_idxs); +	/* num_real_idxs should be the number of indexes of type 2.
+	 * It's not always the case. Happens on Northwind Orders table.
+	 */
+	table->num_real_idxs = 0;
 	tmpbuf = (gchar *) g_malloc(idx2_sz);
 	for (i=0;i<table->num_idxs;i++) {
 		read_pg_if_n(mdb, tmpbuf, &cur_pos, idx2_sz);
@@ -95,45 +99,64 @@ mdb_read_indices(MdbTableDef *table)
 		pidx->index_num = mdb_get_int16(tmpbuf, 4);
 		pidx->index_type = tmpbuf[type_offset];
 		g_ptr_array_add(table->indices, pidx);
+		/*
+		{
+			gint32 dumy0 = mdb_get_int32(tmpbuf, 0);
+			gint8 dumy1 = tmpbuf[8];
+			gint32 dumy2 = mdb_get_int32(tmpbuf, 9);
+			gint32 dumy3 = mdb_get_int32(tmpbuf, 13);
+			gint16 dumy4 = mdb_get_int16(tmpbuf, 17);
+			fprintf(stderr, "idx #%d: num2:%d type:%d\n", i, pidx->index_num, \
pidx->index_type); +			fprintf(stderr, "idx #%d: %d %d %d %d %d\n", i, dumy0, dumy1, \
dumy2, dumy3, dumy4); +		}*/
+		if (pidx->index_type!=2)
+			table->num_real_idxs++;
 	}
+	//fprintf(stderr, "num_idxs:%d num_real_idxs:%d\n", table->num_idxs, \
table->num_real_idxs);  g_free(tmpbuf);
 
 	for (i=0;i<table->num_idxs;i++) {
 		pidx = g_ptr_array_index (table->indices, i);
-		if (IS_JET4(mdb)) {
-			name_sz=read_pg_if_16(mdb, &cur_pos);
-		} else {
+		if (IS_JET3(mdb)) {
 			name_sz=read_pg_if_8(mdb, &cur_pos);
+		} else {
+			name_sz=read_pg_if_16(mdb, &cur_pos);
 		}
 		tmpbuf = g_malloc(name_sz);
 		read_pg_if_n(mdb, tmpbuf, &cur_pos, name_sz);
 		mdb_unicode2ascii(mdb, tmpbuf, name_sz, pidx->name, MDB_MAX_OBJ_NAME);
 		g_free(tmpbuf);
-
+		//fprintf(stderr, "index %d type %d name %s\n", pidx->index_num, pidx->index_type, \
pidx->name);  }
 
 	mdb_read_alt_pg(mdb, entry->table_pg);
 	mdb_read_pg(mdb, index_start_pg);
 	cur_pos = table->index_start;
-	idx_num=0;
 	for (i=0;i<table->num_real_idxs;i++) {
-		if (IS_JET4(mdb)) cur_pos += 4;
-		do {
-			pidx = g_ptr_array_index (table->indices, idx_num++);
-        } while (idx_num < table->num_real_idxs && pidx /*&& pidx != \
0x736e6f6300616d65 && pidx!=(MdbIndex*)0xbaadf00d*/ /*(js) temp? hack*/&& \
                pidx->index_type==2);
-
-		/* if there are more real indexes than index entries left after
-		   removing type 2's decrement real indexes and continue.  Happens
-		   on Northwind Orders table.
-		*/
-		if (idx_num == table->num_real_idxs || !pidx /*|| pidx==(MdbIndex*)0xbaadf00d*/ \
                /*(js) temp? hack*/ /*|| pidx != 0x736e6f6300616d65*/) {
-			table->num_real_idxs--;
+		if (!IS_JET3(mdb)) cur_pos += 4;
+		/* look for index number i */
+		for (j=0; j<table->num_idxs; ++j) {
+			pidx = g_ptr_array_index (table->indices, j);
+			if (pidx->index_type!=2 && pidx->index_num==i)
+				break;
+		}
+		if (j==table->num_idxs) {
+			fprintf(stderr, "ERROR: can't find index #%d.\n", i);
 			continue;
 		}
+		//fprintf(stderr, "index %d #%d (%s) index_type:%d\n", i, pidx->index_num, \
pidx->name, pidx->index_type);  
 		pidx->num_rows = mdb_get_int32(mdb->alt_pg_buf,
 				fmt->tab_cols_start_offset +
-				(i*fmt->tab_ridx_entry_size));
+				(pidx->index_num*fmt->tab_ridx_entry_size));
+		/*
+		fprintf(stderr, "ridx block1 i:%d data1:0x%08x data2:0x%08x\n",
+			i,
+			mdb_get_int32(mdb->pg_buf,
+				fmt->tab_cols_start_offset + pidx->index_num * fmt->tab_ridx_entry_size),
+			mdb_get_int32(mdb->pg_buf,
+				fmt->tab_cols_start_offset + pidx->index_num * fmt->tab_ridx_entry_size +4));
+		fprintf(stderr, "pidx->num_rows:%d\n", pidx->num_rows);*/
 
 		key_num=0;
 		for (j=0;j<MDB_MAX_IDX_COLS;j++) {
@@ -142,18 +165,37 @@ mdb_read_indices(MdbTableDef *table)
 				cur_pos++;
 				continue;
 			}
+			/* here we have the internal column number that does not
+			 * always match the table columns because of deletions */
+			cleaned_col_num = -1;
+			for (k=0; k<table->num_cols; k++) {
+				MdbColumn *col = g_ptr_array_index(table->columns,k);
+				if (col->col_num == col_num) {
+					cleaned_col_num = k;
+					break;
+				}
+			}
+			if (cleaned_col_num==-1) {
+				fprintf(stderr, "CRITICAL: can't find column with internal id %d in index %s\n",
+					col_num, pidx->name);
+				cur_pos++;
+				continue;
+			}
 			/* set column number to a 1 based column number and store */
-			pidx->key_col_num[key_num] = col_num + 1;
+			pidx->key_col_num[key_num] = cleaned_col_num + 1;
 			pidx->key_col_order[key_num] =
 				(read_pg_if_8(mdb, &cur_pos)) ? MDB_ASC : MDB_DESC;
+			//fprintf(stderr, "component %d using column #%d (internally %d)\n", j, \
cleaned_col_num,  col_num);  key_num++;
 		}
 		pidx->num_keys = key_num;
 
 		cur_pos += 4;
+		//fprintf(stderr, "pidx->unknown_pre_first_pg:0x%08x\n", read_pg_if_32(mdb, \
&cur_pos));  pidx->first_pg = read_pg_if_32(mdb, &cur_pos);
 		pidx->flags = read_pg_if_8(mdb, &cur_pos);
-		if (IS_JET4(mdb)) cur_pos += 9;
+		//fprintf(stderr, "pidx->first_pg:%d pidx->flags:0x%02x\n",	pidx->first_pg, \
pidx->flags); +		if (!IS_JET3(mdb)) cur_pos += 9;
 	}
 	return NULL;
 }
@@ -185,7 +227,7 @@ mdb_index_swap_n(unsigned char *src, int sz, unsigned char *dest)
 void
 mdb_index_cache_sarg(MdbColumn *col, MdbSarg *sarg, MdbSarg *idx_sarg)
 {
-
+	//guint32 cache_int;
 	unsigned char *c;
 
 	switch (col->col_type) {
@@ -195,10 +237,10 @@ mdb_index_cache_sarg(MdbColumn *col, MdbSarg *sarg, MdbSarg \
*idx_sarg)  
 		case MDB_LONGINT:
 		idx_sarg->value.i = GUINT32_SWAP_LE_BE(sarg->value.i);
-
+		//cache_int = sarg->value.i * -1;
 		c = (unsigned char *) &(idx_sarg->value.i);
 		c[0] |= 0x80;
-
+		//printf("int %08x %02x %02x %02x %02x\n", sarg->value.i, c[0], c[1], c[2], c[3]);
 		break;
 
 		case MDB_INT:
@@ -247,25 +289,25 @@ mdb_index_test_sargs(MdbHandle *mdb, MdbIndex *idx, char *buf, \
int len)  MdbSarg *sarg;
 	MdbField field;
 	MdbSargNode node;
-
+	//int c_offset = 0,
 	int c_len;
 
-
-
-
-
+	//fprintf(stderr,"mdb_index_test_sargs called on ");
+	//for (i=0;i<len;i++)
+		//fprintf(stderr,"%02x ",buf[i]); //mdb->pg_buf[offset+i]);
+	//fprintf(stderr,"\n");
 	for (i=0;i<idx->num_keys;i++) {
-
+		//c_offset++; /* the per column null indicator/flags */
 		col=g_ptr_array_index(table->columns,idx->key_col_num[i]-1);
 		/*
 		 * This will go away eventually
 		 */
 		if (col->col_type==MDB_TEXT) {
-
+			//c_len = strlen(&mdb->pg_buf[offset + c_offset]);
 			c_len = strlen(buf);
 		} else {
 			c_len = col->col_size;
-
+			//fprintf(stderr,"Only text types currently supported.  How did we get here?\n");
 		}
 		/*
 		 * If we have no cached index values for this column,
@@ -276,7 +318,7 @@ mdb_index_test_sargs(MdbHandle *mdb, MdbIndex *idx, char *buf, \
int len)  for (j=0;j<col->num_sargs;j++) {
 				sarg = g_ptr_array_index (col->sargs, j);
 				idx_sarg = g_memdup(sarg,sizeof(MdbSarg));
-
+				//printf("calling mdb_index_cache_sarg\n");
 				mdb_index_cache_sarg(col, sarg, idx_sarg);
 				g_ptr_array_add(col->idx_sarg_cache, idx_sarg);
 			}
@@ -287,7 +329,7 @@ mdb_index_test_sargs(MdbHandle *mdb, MdbIndex *idx, char *buf, \
int len)  /* XXX - kludge */
 			node.op = sarg->op;
 			node.value = sarg->value;
-
+			//field.value = &mdb->pg_buf[offset + c_offset];
 			field.value = buf;
 		       	field.siz = c_len;
 		       	field.is_null = FALSE;
@@ -314,9 +356,9 @@ mdb_index_pack_bitmap(MdbHandle *mdb, MdbIndexPage *ipg)
 	start = ipg->idx_starts[elem++];
 
 	while (start) {
-
+		//fprintf(stdout, "elem %d is %d\n", elem, ipg->idx_starts[elem]);
 		len = ipg->idx_starts[elem] - start;
-
+		//fprintf(stdout, "len is %d\n", len);
 		for (i=0; i < len; i++) {
 			mask_bit++;
 			if (mask_bit==8) {
@@ -327,7 +369,7 @@ mdb_index_pack_bitmap(MdbHandle *mdb, MdbIndexPage *ipg)
 			/* upon reaching the len, set the bit */
 		}
 		mask_byte = (1 << mask_bit) | mask_byte;
-
+		//fprintf(stdout, "mask byte is %02x at %d\n", mask_byte, mask_pos);
 		start = ipg->idx_starts[elem++];
 	}
 	/* flush the last byte if any */
@@ -353,7 +395,7 @@ mdb_index_unpack_bitmap(MdbHandle *mdb, MdbIndexPage *ipg)
 
 	ipg->idx_starts[elem++]=start;
 
-
+	//fprintf(stdout, "Unpacking index page %lu\n", ipg->pg);
 	do {
 		len = 0;
 		do {
@@ -365,7 +407,7 @@ mdb_index_unpack_bitmap(MdbHandle *mdb, MdbIndexPage *ipg)
 			mask_byte = mdb->pg_buf[mask_pos];
 			len++;
 		} while (mask_pos <= 0xf8 && !((1 << mask_bit) & mask_byte));
-
+		//fprintf(stdout, "%d %d %d %d\n", mask_pos, mask_bit, mask_byte, len);
 
 		start += len;
 		if (mask_pos < 0xf8) ipg->idx_starts[elem++]=start;
@@ -388,7 +430,7 @@ mdb_index_find_next_on_page(MdbHandle *mdb, MdbIndexPage *ipg)
 
 	/* if this page has not been unpacked to it */
 	if (!ipg->idx_starts[0]){
-
+		//fprintf(stdout, "Unpacking page %d\n", ipg->pg);
 		mdb_index_unpack_bitmap(mdb, ipg);
 	}
 
@@ -396,7 +438,7 @@ mdb_index_find_next_on_page(MdbHandle *mdb, MdbIndexPage *ipg)
 	if (ipg->idx_starts[ipg->start_pos + 1]==0) return 0;
 	ipg->len = ipg->idx_starts[ipg->start_pos+1] - ipg->idx_starts[ipg->start_pos];
 	ipg->start_pos++;
-
+	//fprintf(stdout, "Start pos %d\n", ipg->start_pos);
 
 	return ipg->len;
 }
@@ -443,13 +485,13 @@ mdb_find_next_leaf(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain \
                *chain)
 	 */
 	do {
 		ipg->len = 0;
-
+		//printf("finding next on pg %lu\n", ipg->pg);
 		if (!mdb_index_find_next_on_page(mdb, ipg)) {
-
+			//printf("find_next_on_page returned 0\n");
 			return 0;
 		}
 		pg = mdb_get_int32_msb(mdb->pg_buf, ipg->offset + ipg->len - 3) >> 8;
-
+		//printf("Looking at pg %lu at %lu %d\n", pg, ipg->offset, ipg->len);
 		ipg->offset += ipg->len;
 
 		/*
@@ -458,7 +500,7 @@ mdb_find_next_leaf(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain \
                *chain)
 		 */
 		newipg = mdb_chain_add_page(mdb, chain, pg);
 		newipg = mdb_find_next_leaf(mdb, idx, chain);
-
+		//printf("returning pg %lu\n",newipg->pg);
 		return newipg;
 	} while (!passed);
 	/* no more pages */
@@ -517,9 +559,9 @@ mdb_index_unwind(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain \
*chain)  {
 	MdbIndexPage *ipg;
 
-
+	//printf("page %lu finished\n",ipg->pg);
 	if (chain->cur_depth==1) {
-
+		//printf("cur_depth == 1 we're out\n");
 		return NULL;
 	}
 	/*
@@ -528,13 +570,13 @@ mdb_index_unwind(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain \
                *chain)
 	*/
 	ipg = NULL;
 	while (chain->cur_depth>1 && ipg==NULL) {
-
+		//printf("chain depth %d\n", chain->cur_depth);
 		chain->cur_depth--;
 		ipg = mdb_find_next_leaf(mdb, idx, chain);
 		if (ipg) mdb_index_find_next_on_page(mdb, ipg);
 	}
 	if (chain->cur_depth==1) {
-
+		//printf("last leaf %lu\n", chain->last_leaf_found);
 		return NULL;
 	}
 	return ipg;
@@ -577,20 +619,20 @@ mdb_index_find_next(MdbHandle *mdb, MdbIndex *idx, \
MdbIndexChain *chain, guint32  chain->clean_up_mode = 1;
 			}
 			if (chain->clean_up_mode) {
-
+				//fprintf(stdout,"in cleanup mode\n");
 
 				if (!chain->last_leaf_found) return 0;
 				mdb_read_pg(mdb, chain->last_leaf_found);
 				chain->last_leaf_found = mdb_get_int32(
 					mdb->pg_buf, 0x0c);
-
+				//printf("next leaf %lu\n", chain->last_leaf_found);
 				mdb_read_pg(mdb, chain->last_leaf_found);
 				/* reuse the chain for cleanup mode */
 				chain->cur_depth = 1;
 				ipg = &chain->pages[0];
 				mdb_index_page_init(ipg);
 				ipg->pg = chain->last_leaf_found;
-
+				//printf("next on page %d\n",
 				if (!mdb_index_find_next_on_page(mdb, ipg))
 					return 0;
 			}
@@ -598,28 +640,28 @@ mdb_index_find_next(MdbHandle *mdb, MdbIndex *idx, \
MdbIndexChain *chain, guint32  pg_row = mdb_get_int32_msb(mdb->pg_buf, ipg->offset + \
                ipg->len - 4);
 		*row = pg_row & 0xff;
 		*pg = pg_row >> 8;
-
+		//printf("row = %d pg = %lu ipg->pg = %lu offset = %lu len = %d\n", *row, *pg, \
ipg->pg, ipg->offset, ipg->len);  \
col=g_ptr_array_index(idx->table->columns,idx->key_col_num[0]-1);  idx_sz = \
mdb_col_fixed_size(col);  /* handle compressed indexes, single key indexes only? */
 		if (idx->num_keys==1 && idx_sz>0 && ipg->len - 4 < idx_sz) {
-
-
+			//printf("short index found\n");
+			//mdb_buffer_dump(ipg->cache_value, 0, idx_sz);
 			memcpy(&ipg->cache_value[idx_sz - (ipg->len - 4)], &mdb->pg_buf[ipg->offset], \
                ipg->len);
-
+			//mdb_buffer_dump(ipg->cache_value, 0, idx_sz);
 		} else {
 			idx_start = ipg->offset + (ipg->len - 4 - idx_sz);
 			memcpy(ipg->cache_value, &mdb->pg_buf[idx_start], idx_sz);
 		}
 
-
+		//idx_start = ipg->offset + (ipg->len - 4 - idx_sz);
 		passed = mdb_index_test_sargs(mdb, idx, (char *)(ipg->cache_value), idx_sz);
 
 		ipg->offset += ipg->len;
 	} while (!passed);
 
-
-
+	//fprintf(stdout,"len = %d pos %d\n", ipg->len, ipg->mask_pos);
+	//mdb_buffer_dump(mdb->pg_buf, ipg->offset, ipg->len);
 
 	return ipg->len;
 }
@@ -677,11 +719,12 @@ mdb_index_find_row(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain \
*chain, guint32  
 void mdb_index_walk(MdbTableDef *table, MdbIndex *idx)
 {
-MdbHandle *mdb = table->entry->mdb;
-int cur_pos = 0;
-unsigned char marker;
-MdbColumn *col;
-unsigned int i;
+/*
+	MdbHandle *mdb = table->entry->mdb;
+	int cur_pos = 0;
+	unsigned char marker;
+	MdbColumn *col;
+	unsigned int i;
 
 	if (idx->num_keys!=1) return;
 
@@ -691,8 +734,9 @@ unsigned int i;
 	for (i=0;i<idx->num_keys;i++) {
 		marker = mdb->pg_buf[cur_pos++];
 		col=g_ptr_array_index(table->columns,idx->key_col_num[i]-1);
-
+		//printf("column %d coltype %d col_size %d (%d)\n",i,col->col_type, \
mdb_col_fixed_size(col), col->col_size);  }
+*/
 }
 void
 mdb_index_dump(MdbTableDef *table, MdbIndex *idx)
@@ -759,7 +803,7 @@ int mdb_index_compute_cost(MdbTableDef *table, MdbIndex *idx)
 	 */
 	if (idx->flags & MDB_IDX_UNIQUE) {
 		if (idx->num_keys == 1) {
-
+			//printf("op is %d\n", sarg->op);
 			switch (sarg->op) {
 				case MDB_EQUAL:
 					return 1; break;
@@ -831,7 +875,7 @@ mdb_choose_index(MdbTableDef *table, int *choice)
 	for (i=0;i<table->num_idxs;i++) {
 		idx = g_ptr_array_index (table->indices, i);
 		cost = mdb_index_compute_cost(table, idx);
-
+		//printf("cost for %s is %d\n", idx->name, cost);
 		if (cost && cost < least) {
 			least = cost;
 			*choice = i;
@@ -852,9 +896,9 @@ mdb_index_scan_init(MdbHandle *mdb, MdbTableDef *table)
 		table->chain = g_malloc0(sizeof(MdbIndexChain));
 		table->mdbidx = mdb_clone_handle(mdb);
 		mdb_read_pg(table->mdbidx, table->scan_idx->first_pg);
-
+		//printf("best index is %s\n",table->scan_idx->name);
 	}
-
+	//printf("TABLE SCAN? %d\n", table->strategy);
 }
 void
 mdb_index_scan_free(MdbTableDef *table)
diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/like.c \
b/src/migration/mdb/3rdparty/mdbtools/libmdb/like.c index 4e6d554..e89c11d 100644
--- a/src/migration/mdb/3rdparty/mdbtools/libmdb/like.c
+++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/like.c
@@ -12,14 +12,13 @@
  * 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.
+ * 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 <stdio.h>
 #include <string.h>
-#include <mdbtools.h>
+#include "mdbtools.h"
 
 #ifdef DMALLOC
 #include "dmalloc.h"
diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/map.c \
b/src/migration/mdb/3rdparty/mdbtools/libmdb/map.c index 1788b27..2566074 100644
--- a/src/migration/mdb/3rdparty/mdbtools/libmdb/map.c
+++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/map.c
@@ -12,9 +12,8 @@
  * 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.
+ * 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 "mdbtools.h"
@@ -23,7 +22,7 @@
 #include "dmalloc.h"
 #endif
 
-static guint32
+static gint32
 mdb_map_find_next0(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 \
start_pg)  {
 	guint32 pgnum, i, usage_bitlen;
@@ -42,7 +41,7 @@ mdb_map_find_next0(MdbHandle *mdb, unsigned char *map, unsigned int \
map_sz, guin  /* didn't find anything */
 	return 0;
 }
-static int
+static gint32
 mdb_map_find_next1(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 \
start_pg)  {
 	guint32 map_ind, max_map_pgs, offset, usage_bitlen;
@@ -83,7 +82,10 @@ mdb_map_find_next1(MdbHandle *mdb, unsigned char *map, unsigned \
int map_sz, guin  /* didn't find anything */
 	return 0;
 }
-guint32
+
+/* returns 0 on EOF */
+/* returns -1 on error (unsupported map type) */
+gint32
 mdb_map_find_next(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 \
start_pg)  {
 	if (map[0] == 0) {
@@ -114,11 +116,14 @@ mdb_map_find_next_freepage(MdbTableDef *table, int row_size)
 		pgnum = mdb_map_find_next(mdb,
 				table->free_usage_map,
 				table->freemap_sz, cur_pg);
-
+		//printf("looking at page %d\n", pgnum);
 		if (!pgnum) {
 			/* allocate new page */
 			pgnum = mdb_alloc_page(table);
 			return pgnum;
+		} else if (pgnum==-1) {
+			fprintf(stderr, "Error: mdb_map_find_next_freepage error while reading maps.\n");
+			exit(1);
 		}
 		cur_pg = pgnum;
 
@@ -127,7 +132,7 @@ mdb_map_find_next_freepage(MdbTableDef *table, int row_size)
 
 	} while (free_space < row_size);
 
-
+	//printf("page %d has %d bytes left\n", pgnum, free_space);
 
 	return pgnum;
 }
diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/mem.c \
b/src/migration/mdb/3rdparty/mdbtools/libmdb/mem.c index 92fc20c..6f871cd 100644
--- a/src/migration/mdb/3rdparty/mdbtools/libmdb/mem.c
+++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/mem.c
@@ -12,45 +12,20 @@
  * 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.
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
-#ifdef JAVA
-#include "javadefines.h"
-#else
+
 #include "mdbtools.h"
-#include <locale.h>
 
-#ifdef DMALLOC
-#include "dmalloc.h"
-#endif
-#endif  /* JAVA */
-/**
- * mdb_init:
- *
- * Initializes the LibMDB library.  This function should be called exactly once
- * by calling program and prior to any other function.
- *
- **/
-/* METHOD */ void mdb_init()
+MDB_DEPRECATED(void,
+mdb_init())
 {
-#if !MDB_NO_BACKENDS
-	mdb_init_backends();
-#endif
+	fprintf(stderr, "mdb_init() is DEPRECATED and does nothing. Stop calling it.\n");
 }
 
-/**
- * mdb_exit:
- *
- * Cleans up the LibMDB library.  This function should be called exactly once
- * by the calling program prior to exiting (or prior to final use of LibMDB
- * functions).
- *
- **/
-/* METHOD */ void mdb_exit()
+MDB_DEPRECATED(void,
+mdb_exit())
 {
-#if !MDB_NO_BACKENDS
-	mdb_remove_backends();
-#endif
+	fprintf(stderr, "mdb_exit() is DEPRECATED and does nothing. Stop calling it.\n");
 }
diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/money.c \
b/src/migration/mdb/3rdparty/mdbtools/libmdb/money.c index 370d632..488d570 100644
--- a/src/migration/mdb/3rdparty/mdbtools/libmdb/money.c
+++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/money.c
@@ -12,9 +12,8 @@
  * 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.
+ * 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 <stdio.h>
@@ -24,10 +23,10 @@
 #include "dmalloc.h"
 #endif
 
-#define MAXPRECISION 19
+#define MAX_NUMERIC_PRECISION 28
 /*
 ** these routines are copied from the freetds project which does something
-** very similar
+** very similiar
 */
 
 static int multiply_byte(unsigned char *product, int num, unsigned char \
*multiplier); @@ -43,41 +42,70 @@ static char *array_to_string(unsigned char *array, \
                int unsigned scale, int neg);
  */
 char *mdb_money_to_string(MdbHandle *mdb, int start)
 {
-	#define num_bytes 8
+	int num_bytes=8, scale=4;
 	int i;
 	int neg=0;
-	unsigned char multiplier[MAXPRECISION], temp[MAXPRECISION];
-	unsigned char product[MAXPRECISION];
-	unsigned char money[num_bytes];
+       unsigned char multiplier[MAX_NUMERIC_PRECISION], temp[MAX_NUMERIC_PRECISION];
+       unsigned char product[MAX_NUMERIC_PRECISION];
+       unsigned char bytes[num_bytes];
 
-	memset(multiplier,0,MAXPRECISION);
-	memset(product,0,MAXPRECISION);
+       memset(multiplier,0,MAX_NUMERIC_PRECISION);
+       memset(product,0,MAX_NUMERIC_PRECISION);
 	multiplier[0]=1;
-	memcpy(money, mdb->pg_buf + start, num_bytes);
+       memcpy(bytes, mdb->pg_buf + start, num_bytes);
 
 	/* Perform two's complement for negative numbers */
-	if (money[7] & 0x80) {
+       if (bytes[num_bytes-1] & 0x80) {
 		neg = 1;
 		for (i=0;i<num_bytes;i++) {
-			money[i] = ~money[i];
+                       bytes[i] = ~bytes[i];
 		}
 		for (i=0; i<num_bytes; i++) {
-			money[i] ++;
-			if (money[i]!=0) break;
+                       bytes[i] ++;
+                       if (bytes[i]!=0) break;
 		}
 	}
 
 	for (i=0;i<num_bytes;i++) {
 		/* product += multiplier * current byte */
-		multiply_byte(product, money[i], multiplier);
+               multiply_byte(product, bytes[i], multiplier);
 
 		/* multiplier = multiplier * 256 */
-		memcpy(temp, multiplier, MAXPRECISION);
-		memset(multiplier,0,MAXPRECISION);
+               memcpy(temp, multiplier, MAX_NUMERIC_PRECISION);
+               memset(multiplier, 0, MAX_NUMERIC_PRECISION);
 		multiply_byte(multiplier, 256, temp);
 	}
-	return array_to_string(product, 4, neg);
+       return array_to_string(product, scale, neg);
+
+}
+
+char *mdb_numeric_to_string(MdbHandle *mdb, int start, int prec, int scale) {
+       int num_bytes = 16;
+       int i;
+       int neg=0;
+       unsigned char multiplier[MAX_NUMERIC_PRECISION], temp[MAX_NUMERIC_PRECISION];
+       unsigned char product[MAX_NUMERIC_PRECISION];
+       unsigned char bytes[num_bytes];
+
+       memset(multiplier,0,MAX_NUMERIC_PRECISION);
+       memset(product,0,MAX_NUMERIC_PRECISION);
+       multiplier[0]=1;
+       memcpy(bytes, mdb->pg_buf + start + 1, num_bytes);
+
+       /* Perform two's complement for negative numbers */
+       if (mdb->pg_buf[start] & 0x80) neg = 1;
+       for (i=0;i<num_bytes;i++) {
+               /* product += multiplier * current byte */
+               multiply_byte(product, bytes[12-4*(i/4)+i%4], multiplier);
+
+               /* multiplier = multiplier * 256 */
+               memcpy(temp, multiplier, MAX_NUMERIC_PRECISION);
+               memset(multiplier, 0, MAX_NUMERIC_PRECISION);
+               multiply_byte(multiplier, 256, temp);
+       }
+       return array_to_string(product, scale, neg);
 }
+
 static int multiply_byte(unsigned char *product, int num, unsigned char *multiplier)
 {
 	unsigned char number[3];
@@ -87,7 +115,7 @@ static int multiply_byte(unsigned char *product, int num, unsigned \
char *multipl  number[1]=(num/10)%10;
 	number[2]=(num/100)%10;
 
-	for (i=0;i<MAXPRECISION;i++) {
+       for (i=0;i<MAX_NUMERIC_PRECISION;i++) {
 		if (multiplier[i] == 0) continue;
 		for (j=0;j<3;j++) {
 			if (number[j] == 0) continue;
@@ -101,7 +129,7 @@ static int do_carry(unsigned char *product)
 {
 	unsigned int j;
 
-	for (j=0;j<MAXPRECISION-1;j++) {
+       for (j=0;j<MAX_NUMERIC_PRECISION-1;j++) {
 		if (product[j]>9) {
 			product[j+1]+=product[j]/10;
 			product[j]=product[j]%10;
@@ -117,9 +145,10 @@ static char *array_to_string(unsigned char *array, unsigned int \
scale, int neg)  char *s;
 	unsigned int top, i, j=0;
 
-	for (top=MAXPRECISION;(top>0) && (top-1>scale) && !array[top-1];top--);
+       for (top=MAX_NUMERIC_PRECISION;(top>0) && (top-1>scale) && \
!array[top-1];top--);  
-	s = (char *) g_malloc(22);
+       /* allocate enough space for all digits + minus sign + decimal point + \
trailing NULL byte */ +       s = (char *) g_malloc(MAX_NUMERIC_PRECISION+3);
 
 	if (neg)
 		s[j++] = '-';
diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/options.c \
b/src/migration/mdb/3rdparty/mdbtools/libmdb/options.c index 6b43a0e..02af719 100644
--- a/src/migration/mdb/3rdparty/mdbtools/libmdb/options.c
+++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/options.c
@@ -12,17 +12,15 @@
  * 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.
+ * 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 <stdio.h>
 #include <string.h>
 #include <stdarg.h>
 #include <stdlib.h>
-
-#include <mdbtools.h>
+#include "mdbtools.h"
 
 #ifdef DMALLOC
 #include "dmalloc.h"
@@ -36,17 +34,17 @@ static int optset;
 static void load_options();
 
 void
-mdb_debug(int klass, char *fmt, ...)
+mdb_debug(int klass, const char *fmt, ...)
 {
 #ifdef DEBUG
 	va_list ap;
 
 	if (!optset) load_options();
 	if (klass & opts) {
-    	va_start(ap, fmt);
-    	vfprintf (stdout,fmt, ap);
-    	va_end(ap);
-    	fprintf(stdout,"\n");
+		va_start(ap, fmt);
+		vfprintf (stderr,fmt, ap);
+		va_end(ap);
+		fprintf(stderr,"\n");
 	}
 #endif
 }
@@ -57,26 +55,28 @@ load_options()
 	char *opt;
 	char *s;
 
-    if (!optset && (s=getenv("MDBOPTS"))) {
+	if (!optset && (s=getenv("MDBOPTS"))) {
 		opt = strtok(s, ":");
-		do {
-        	if (!strcmp(opt, "use_index")) opts |= MDB_USE_INDEX;
-        	if (!strcmp(opt, "no_memo")) opts |= MDB_NO_MEMO;
-        	if (!strcmp(opt, "debug_like")) opts |= MDB_DEBUG_LIKE;
-        	if (!strcmp(opt, "debug_write")) opts |= MDB_DEBUG_WRITE;
-        	if (!strcmp(opt, "debug_usage")) opts |= MDB_DEBUG_USAGE;
-        	if (!strcmp(opt, "debug_ole")) opts |= MDB_DEBUG_OLE;
-        	if (!strcmp(opt, "debug_row")) opts |= MDB_DEBUG_ROW;
-        	if (!strcmp(opt, "debug_all")) {
+		while (opt) {
+			if (!strcmp(opt, "use_index")) opts |= MDB_USE_INDEX;
+			if (!strcmp(opt, "no_memo")) opts |= MDB_NO_MEMO;
+			if (!strcmp(opt, "debug_like")) opts |= MDB_DEBUG_LIKE;
+			if (!strcmp(opt, "debug_write")) opts |= MDB_DEBUG_WRITE;
+			if (!strcmp(opt, "debug_usage")) opts |= MDB_DEBUG_USAGE;
+			if (!strcmp(opt, "debug_ole")) opts |= MDB_DEBUG_OLE;
+			if (!strcmp(opt, "debug_row")) opts |= MDB_DEBUG_ROW;
+			if (!strcmp(opt, "debug_props")) opts |= MDB_DEBUG_PROPS;
+			if (!strcmp(opt, "debug_all")) {
 				opts |= MDB_DEBUG_LIKE;
 				opts |= MDB_DEBUG_WRITE;
 				opts |= MDB_DEBUG_USAGE;
 				opts |= MDB_DEBUG_OLE;
 				opts |= MDB_DEBUG_ROW;
+				opts |= MDB_DEBUG_PROPS;
 			}
 			opt = strtok(NULL,":");
-		} while (opt);
-    }
+		}
+	}
 	optset = 1;
 }
 int
diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/props.c \
b/src/migration/mdb/3rdparty/mdbtools/libmdb/props.c new file mode 100644
index 0000000..38e0660
--- /dev/null
+++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/props.c
@@ -0,0 +1,215 @@
+/* MDB Tools - A library for reading MS Access database file
+ * Copyright (C) 2000-2011 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
+ */
+
+#include "mdbtools.h"
+
+static GPtrArray *
+mdb_read_props_list(MdbHandle *mdb, gchar *kkd, int len)
+{
+	guint32 record_len;
+	int pos = 0;
+	gchar *name;
+	GPtrArray *names = NULL;
+	int i=0;
+
+	names = g_ptr_array_new();
+#if MDB_DEBUG
+	mdb_buffer_dump(kkd, 0, len);
+#endif
+	pos = 0;
+	while (pos < len) {
+		record_len = mdb_get_int16(kkd, pos);
+		pos += 2;
+		if (mdb_get_option(MDB_DEBUG_PROPS)) {
+			fprintf(stderr, "%02d ",i++);
+			mdb_buffer_dump(kkd, pos - 2, record_len + 2);
+		}
+		name = g_malloc(3*record_len + 1); /* worst case scenario is 3 bytes out per byte \
in */ +		mdb_unicode2ascii(mdb, &kkd[pos], record_len, name, 3*record_len);
+
+		pos += record_len;
+		g_ptr_array_add(names, name);
+#if MDB_DEBUG
+		printf("new len = %d\n", names->len);
+#endif
+	}
+	return names;
+}
+static gboolean
+free_hash_entry(gpointer key, gpointer value, gpointer user_data)
+{
+	g_free(key);
+	g_free(value);
+	return TRUE;
+}
+void
+mdb_free_props(MdbProperties *props)
+{
+	if (!props) return;
+
+	if (props->name) g_free(props->name);
+	if (props->hash) {
+		g_hash_table_foreach(props->hash, (GHFunc)free_hash_entry, 0);
+		g_hash_table_destroy(props->hash);
+	}
+	g_free(props);
+}
+
+static void
+free_names(GPtrArray *names) {
+	g_ptr_array_foreach(names, (GFunc)g_free, NULL);
+	g_ptr_array_free(names, TRUE);
+}
+MdbProperties *
+mdb_alloc_props()
+{
+	MdbProperties *props;
+
+	props = g_malloc0(sizeof(MdbProperties));
+
+	return props;
+}
+static MdbProperties *
+mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int len)
+{
+	guint32 record_len, name_len;
+	int pos = 0;
+	int elem, dtype, dsize;
+	gchar *name, *value;
+	MdbProperties *props;
+	int i=0;
+
+#if MDB_DEBUG
+	mdb_buffer_dump(kkd, 0, len);
+#endif
+	pos = 0;
+
+	record_len = mdb_get_int16(kkd, pos);
+	pos += 4;
+	name_len = mdb_get_int16(kkd, pos);
+	pos += 2;
+	props = mdb_alloc_props();
+	if (name_len) {
+		props->name = g_malloc(3*name_len + 1);
+		mdb_unicode2ascii(mdb, kkd+pos, name_len, props->name, 3*name_len);
+		mdb_debug(MDB_DEBUG_PROPS,"prop block named: %s", props->name);
+	}
+	pos += name_len;
+
+	props->hash = g_hash_table_new(g_str_hash, g_str_equal);
+
+	while (pos < len) {
+		record_len = mdb_get_int16(kkd, pos);
+		dtype = kkd[pos + 3];
+		elem = mdb_get_int16(kkd, pos + 4);
+		dsize = mdb_get_int16(kkd, pos + 6);
+		value = g_malloc(dsize + 1);
+		strncpy(value, &kkd[pos + 8], dsize);
+		value[dsize] = '\0';
+		name = g_ptr_array_index(names,elem);
+		if (mdb_get_option(MDB_DEBUG_PROPS)) {
+			fprintf(stderr, "%02d ",i++);
+			mdb_debug(MDB_DEBUG_PROPS,"elem %d (%s) dsize %d dtype %d", elem, name, dsize, \
dtype); +			mdb_buffer_dump(value, 0, dsize);
+		}
+		if (dtype == MDB_MEMO) dtype = MDB_TEXT;
+		if (dtype == MDB_BOOL) {
+			g_hash_table_insert(props->hash, g_strdup(name),
+				g_strdup(kkd[pos + 8] ? "yes" : "no"));
+		} else {
+			g_hash_table_insert(props->hash, g_strdup(name),
+			  mdb_col_to_string(mdb, kkd, pos + 8, dtype, dsize));
+		}
+		g_free(value);
+		pos += record_len;
+	}
+	return props;
+
+}
+
+static void
+print_keyvalue(gpointer key, gpointer value, gpointer outfile)
+{
+		fprintf((FILE*)outfile,"\t%s: %s\n", (gchar *)key, (gchar *)value);
+}
+void
+mdb_dump_props(MdbProperties *props, FILE *outfile, int show_name) {
+	if (show_name)
+		fprintf(outfile,"name: %s\n", props->name ? props->name : "(none)");
+	g_hash_table_foreach(props->hash, print_keyvalue, outfile);
+	if (show_name)
+		fputc('\n', outfile);
+}
+
+/*
+ * That function takes a raw KKD/MR2 binary buffer,
+ * typically read from LvProp in table MSysbjects
+ * and returns a GArray of MdbProps*
+ */
+GArray*
+mdb_kkd_to_props(MdbHandle *mdb, void *buffer, size_t len) {
+	guint32 record_len;
+	guint16 record_type;
+	size_t pos;
+	GPtrArray *names = NULL;
+	MdbProperties *props;
+	GArray *result;
+
+#if MDB_DEBUG
+	mdb_buffer_dump(buffer, 0, len);
+#endif
+	mdb_debug(MDB_DEBUG_PROPS,"starting prop parsing of type %s", buffer);
+
+	if (strcmp("KKD", buffer) && strcmp("MR2", buffer)) {
+		fprintf(stderr, "Unrecognized format.\n");
+		mdb_buffer_dump(buffer, 0, len);
+		return NULL;
+	}
+
+	result = g_array_new(0, 0, sizeof(MdbProperties*));
+
+	pos = 4;
+	while (pos < len) {
+		record_len = mdb_get_int32(buffer, pos);
+		record_type = mdb_get_int16(buffer, pos + 4);
+		mdb_debug(MDB_DEBUG_PROPS,"prop chunk type:0x%04x len:%d", record_type, \
record_len); +		//mdb_buffer_dump(buffer, pos+4, record_len);
+		switch (record_type) {
+			case 0x80:
+				if (names) free_names(names);
+				names = mdb_read_props_list(mdb, buffer+pos+6, record_len - 6);
+				break;
+			case 0x00:
+			case 0x01:
+				if (!names) {
+					fprintf(stderr,"sequence error!\n");
+					break;
+				}
+				props = mdb_read_props(mdb, names, buffer+pos+6, record_len - 6);
+				g_array_append_val(result, props);
+				//mdb_dump_props(props, stderr, 1);
+				break;
+			default:
+				fprintf(stderr,"Unknown record type %d\n", record_type);
+				break;
+		}
+		pos += record_len;
+	}
+	if (names) free_names(names);
+	return result;
+}
diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/sargs.c \
b/src/migration/mdb/3rdparty/mdbtools/libmdb/sargs.c index 83499f7..cee28c0 100644
--- a/src/migration/mdb/3rdparty/mdbtools/libmdb/sargs.c
+++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/sargs.c
@@ -12,9 +12,8 @@
  * 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.
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 /*
@@ -27,8 +26,9 @@
  * datatype support is a bit weak at this point.  To add more types create
  * a mdb_test_[type]() function and invoke it from mdb_test_sarg()
  */
-#include "mdbtools.h"
 
+#include <time.h>
+#include "mdbtools.h"
 #ifdef DMALLOC
 #include "dmalloc.h"
 #endif
@@ -76,7 +76,7 @@ int mdb_test_int(MdbSargNode *node, gint32 i)
 {
 	switch (node->op) {
 		case MDB_EQUAL:
-
+			//fprintf(stderr, "comparing %ld and %ld\n", i, node->value.i);
 			if (node->value.i == i) return 1;
 			break;
 		case MDB_GT:
@@ -97,8 +97,51 @@ int mdb_test_int(MdbSargNode *node, gint32 i)
 	}
 	return 0;
 }
-#if 0
-#endif
+
+int
+mdb_test_date(MdbSargNode *node, double td)
+{
+	struct tm found;
+	/* TODO: you should figure out a way to pull mdb_date_to_string in here
+	 * char date_tmp[MDB_BIND_SIZE];
+	 */
+
+	time_t found_t;
+	time_t asked_t;
+
+	double diff;
+
+	mdb_date_to_tm(td, &found);
+
+	asked_t = node->value.i;
+	found_t = mktime(&found);
+
+	diff = difftime(asked_t, found_t);
+
+	switch (node->op) {
+	case MDB_EQUAL:
+		if (diff==0) return 1;
+		break;
+	case MDB_GT:
+		if (diff<0) return 1;
+		break;
+	case MDB_LT:
+		if (diff>0) return 1;
+		break;
+	case MDB_GTEQ:
+		if (diff<=0) return 1;
+		break;
+	case MDB_LTEQ:
+		if (diff>=0) return 1;
+		break;
+	default:
+		fprintf(stderr, "Calling mdb_test_sarg on unknown operator. Add code to \
mdb_test_date() for operator %d\n", node->op); +		break;
+	}
+	return 0;
+}
+
+
 int
 mdb_find_indexable_sargs(MdbSargNode *node, gpointer data)
 {
@@ -120,7 +163,7 @@ mdb_find_indexable_sargs(MdbSargNode *node, gpointer data)
 	 * probably better off table scanning.
 	 */
 	if (mdb_is_relational_op(node->op) && node->col) {
-
+		//printf("op = %d value = %s\n", node->op, node->value.s);
 		sarg.op = node->op;
 		sarg.value = node->value;
 		mdb_add_sarg(node->col, &sarg);
@@ -155,6 +198,8 @@ mdb_test_sarg(MdbHandle *mdb, MdbColumn *col, MdbSargNode *node, \
MdbField *field  case MDB_TEXT:
 			mdb_unicode2ascii(mdb, field->value, field->siz, tmpbuf, 256);
 			return mdb_test_string(node, tmpbuf);
+		case MDB_DATETIME:
+			return mdb_test_date(node, mdb_get_double(field->value, 0));
 		default:
 			fprintf(stderr, "Calling mdb_test_sarg on unknown type.  Add code to \
mdb_test_sarg() for type %d\n",col->col_type);  break;
diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/stats.c \
b/src/migration/mdb/3rdparty/mdbtools/libmdb/stats.c new file mode 100644
index 0000000..3719826
--- /dev/null
+++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/stats.c
@@ -0,0 +1,77 @@
+/* MDB Tools - A library for reading MS Access database files
+ * Copyright (C) 2000 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 "mdbtools.h"
+
+#if !MDB_NO_STATS
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+/**
+ * mdb_stats_on:
+ * @mdb: Handle to the (open) MDB file to collect stats on.
+ *
+ * Begins collection of statistics on an MDBHandle.
+ *
+ * Statistics in LibMDB will track the number of reads from the MDB file.  The
+ * collection of statistics is started and stopped with the mdb_stats_on and
+ * mdb_stats_off functions.  Collected statistics are accessed by reading the
+ * MdbStatistics structure or calling mdb_dump_stats.
+ *
+ */
+void
+mdb_stats_on(MdbHandle *mdb)
+{
+	if (!mdb->stats)
+		mdb->stats = g_malloc0(sizeof(MdbStatistics));
+
+	mdb->stats->collect = TRUE;
+}
+/**
+ * mdb_stats_off:
+ * @mdb: pointer to handle of MDB file with active stats collection.
+ *
+ * Turns off statistics collection.
+ *
+ * If mdb_stats_off is not called, statistics will be turned off when handle
+ * is freed using mdb_close.
+ **/
+void
+mdb_stats_off(MdbHandle *mdb)
+{
+	if (!mdb->stats) return;
+
+	mdb->stats->collect = FALSE;
+}
+/**
+ * mdb_dump_stats:
+ * @mdb: pointer to handle of MDB file with active stats collection.
+ *
+ * Dumps current statistics to stdout.
+ **/
+void
+mdb_dump_stats(MdbHandle *mdb)
+{
+	if (!mdb->stats) return;
+
+	fprintf(stdout, "Physical Page Reads: %lu\n", mdb->stats->pg_reads);
+}
+
+#endif /* !MDB_NO_STATS */
diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/table.c \
b/src/migration/mdb/3rdparty/mdbtools/libmdb/table.c index 1698e0f..89611c1 100644
--- a/src/migration/mdb/3rdparty/mdbtools/libmdb/table.c
+++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/table.c
@@ -12,9 +12,8 @@
  * 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.
+ * 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 "mdbtools.h"
@@ -76,15 +75,16 @@ MdbTableDef *mdb_read_table(MdbCatalogEntry *entry)
 	MdbTableDef *table;
 	MdbHandle *mdb = entry->mdb;
 	MdbFormatConstants *fmt = mdb->fmt;
-	int len, row_start, pg_row;
+	int row_start, pg_row;
 	void *buf, *pg_buf = mdb->pg_buf;
+	guint i;
 
 	mdb_read_pg(mdb, entry->table_pg);
 	if (mdb_get_byte(pg_buf, 0) != 0x02)  /* not a valid table def page */
 		return NULL;
 	table = mdb_alloc_tabledef(entry);
 
-	len = mdb_get_int16(pg_buf, 8);
+	mdb_get_int16(pg_buf, 8); /* len */
 
 	table->num_rows = mdb_get_int32(pg_buf, fmt->tab_num_rows_offset);
 	table->num_var_cols = mdb_get_int16(pg_buf, fmt->tab_num_cols_offset-2);
@@ -97,7 +97,7 @@ MdbTableDef *mdb_read_table(MdbCatalogEntry *entry)
 	mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &(table->map_sz));
 	table->usage_map = g_memdup((char*)buf + row_start, table->map_sz);
 	if (mdb_get_option(MDB_DEBUG_USAGE))
-		buffer_dump(buf, row_start, table->map_sz);
+		mdb_buffer_dump(buf, row_start, table->map_sz);
 	mdb_debug(MDB_DEBUG_USAGE,"usage map found on page %ld row %d start %d len %d",
 		pg_row >> 8, pg_row & 0xff, row_start, table->map_sz);
 
@@ -110,6 +110,13 @@ MdbTableDef *mdb_read_table(MdbCatalogEntry *entry)
 
 	table->first_data_pg = mdb_get_int16(pg_buf, fmt->tab_first_dpg_offset);
 
+	if (entry->props)
+		for (i=0; i<entry->props->len; ++i) {
+			MdbProperties *props = g_array_index(entry->props, MdbProperties*, i);
+			if (!props->name)
+				table->props = props;
+		}
+
 	return table;
 }
 MdbTableDef *mdb_read_table_by_name(MdbHandle *mdb, gchar *table_name, int obj_type)
@@ -161,7 +168,6 @@ read_pg_if_8(MdbHandle *mdb, int *cur_pos)
 void *
 read_pg_if_n(MdbHandle *mdb, void *buf, int *cur_pos, size_t len)
 {
-	char *buf_char = (char *)buf;
 	/* Advance to page which contains the first byte */
 	while (*cur_pos >= mdb->fmt->pg_size) {
 		mdb_read_pg(mdb, mdb_get_int32(mdb->pg_buf,4));
@@ -170,20 +176,20 @@ read_pg_if_n(MdbHandle *mdb, void *buf, int *cur_pos, size_t \
len)  /* Copy pages into buffer */
 	while (*cur_pos + len >= mdb->fmt->pg_size) {
 		int piece_len = mdb->fmt->pg_size - *cur_pos;
-		if (buf_char) {
-			memcpy(buf_char, mdb->pg_buf + *cur_pos, piece_len);
-			buf_char += piece_len;
+		if (buf) {
+			memcpy(buf, mdb->pg_buf + *cur_pos, piece_len);
+			buf += piece_len;
 		}
 		len -= piece_len;
 		mdb_read_pg(mdb, mdb_get_int32(mdb->pg_buf,4));
 		*cur_pos = 8;
 	}
 	/* Copy into buffer from final page */
-	if (len && buf_char) {
-		memcpy(buf_char, mdb->pg_buf + *cur_pos, len);
+	if (len && buf) {
+		memcpy(buf, mdb->pg_buf + *cur_pos, len);
 	}
 	*cur_pos += len;
-	return buf_char;
+	return buf;
 }
 
 
@@ -193,11 +199,20 @@ void mdb_append_column(GPtrArray *columns, MdbColumn *in_col)
 }
 void mdb_free_columns(GPtrArray *columns)
 {
-	unsigned int i;
+	unsigned int i, j;
+	MdbColumn *col;
 
 	if (!columns) return;
-	for (i=0; i<columns->len; i++)
-		g_free (g_ptr_array_index(columns, i));
+	for (i=0; i<columns->len; i++) {
+		col = (MdbColumn *) g_ptr_array_index(columns, i);
+		if (col->sargs) {
+			for (j=0; j<col->sargs->len; j++) {
+				g_free( g_ptr_array_index(col->sargs, j));
+			}
+			g_ptr_array_free(col->sargs, TRUE);
+		}
+		g_free(col);
+	}
 	g_ptr_array_free(columns, TRUE);
 }
 GPtrArray *mdb_read_columns(MdbTableDef *table)
@@ -206,9 +221,10 @@ GPtrArray *mdb_read_columns(MdbTableDef *table)
 	MdbFormatConstants *fmt = mdb->fmt;
 	MdbColumn *pcol;
 	unsigned char *col;
-	unsigned int i;
+	unsigned int i, j;
 	int cur_pos;
 	size_t name_sz;
+	GArray *allprops;
 
 	table->columns = g_ptr_array_new();
 
@@ -225,24 +241,26 @@ GPtrArray *mdb_read_columns(MdbTableDef *table)
 	for (i=0;i<table->num_cols;i++) {
 #ifdef MDB_DEBUG
 	/* printf("column %d\n", i);
-	buffer_dump(mdb->pg_buf, cur_pos, fmt->tab_col_entry_size); */
+	mdb_buffer_dump(mdb->pg_buf, cur_pos, fmt->tab_col_entry_size); */
 #endif
 		read_pg_if_n(mdb, col, &cur_pos, fmt->tab_col_entry_size);
 		pcol = (MdbColumn *) g_malloc0(sizeof(MdbColumn));
 
-		pcol->col_type = col[0];
+		pcol->table = table;
 
+		pcol->col_type = col[0];
 
+		// col_num_offset == 1 or 5
 		pcol->col_num = col[fmt->col_num_offset];
 
-
-
+		//fprintf(stdout,"----- column %d -----\n",pcol->col_num);
+		// col_var == 3 or 7
 		pcol->var_col_num = mdb_get_int16(col, fmt->tab_col_offset_var);
+		//fprintf(stdout,"var column pos %d\n",pcol->var_col_num);
 
-
-
+		// col_var == 5 or 9
 		pcol->row_col_num = mdb_get_int16(col, fmt->tab_row_col_num_offset);
-
+		//fprintf(stdout,"row column num %d\n",pcol->row_col_num);
 
 		/* FIXME: can this be right in Jet3 and Jet4? */
 		if (pcol->col_type == MDB_NUMERIC) {
@@ -250,16 +268,18 @@ GPtrArray *mdb_read_columns(MdbTableDef *table)
 			pcol->col_scale = col[12];
 		}
 
+		// col_flags_offset == 13 or 15
+		pcol->is_fixed = col[fmt->col_flags_offset] & 0x01 ? 1 : 0;
+		pcol->is_long_auto = col[fmt->col_flags_offset] & 0x04 ? 1 : 0;
+		pcol->is_uuid_auto = col[fmt->col_flags_offset] & 0x40 ? 1 : 0;
 
-		pcol->is_fixed = col[fmt->col_fixed_offset] & 0x01 ? 1 : 0;
-
-
+		// tab_col_offset_fixed == 14 or 21
 		pcol->fixed_offset = mdb_get_int16(col, fmt->tab_col_offset_fixed);
-
-
+		//fprintf(stdout,"fixed column offset %d\n",pcol->fixed_offset);
+		//fprintf(stdout,"col type %s\n",pcol->is_fixed ? "fixed" : "variable");
 
 		if (pcol->col_type != MDB_BOOL) {
-
+			// col_size_offset == 16 or 23
 			pcol->col_size = mdb_get_int16(col, fmt->col_size_offset);
 		} else {
 			pcol->col_size=0;
@@ -277,24 +297,34 @@ GPtrArray *mdb_read_columns(MdbTableDef *table)
 		char *tmp_buf;
 		pcol = g_ptr_array_index(table->columns, i);
 
-		if (IS_JET4(mdb)) {
-			name_sz = read_pg_if_16(mdb, &cur_pos);
-		} else if (IS_JET3(mdb)) {
+		if (IS_JET3(mdb))
 			name_sz = read_pg_if_8(mdb, &cur_pos);
-		} else {
-			fprintf(stderr,"Unknown MDB version\n");
-			continue;
-		}
+		else
+			name_sz = read_pg_if_16(mdb, &cur_pos);
 		tmp_buf = (char *) g_malloc(name_sz);
 		read_pg_if_n(mdb, tmp_buf, &cur_pos, name_sz);
 		mdb_unicode2ascii(mdb, tmp_buf, name_sz, pcol->name, MDB_MAX_OBJ_NAME);
 		g_free(tmp_buf);
 
+
 	}
 
 	/* Sort the columns by col_num */
 	g_ptr_array_sort(table->columns, (GCompareFunc)mdb_col_comparer);
 
+	allprops = table->entry->props;
+	if (allprops)
+		for (i=0;i<table->num_cols;i++) {
+			pcol = g_ptr_array_index(table->columns, i);
+			for (j=0; j<allprops->len; ++j) {
+				MdbProperties *props = g_array_index(allprops, MdbProperties*, j);
+				if (props->name && pcol->name && !strcmp(props->name, pcol->name)) {
+					pcol->props = props;
+					break;
+				}
+
+			}
+		}
 	table->index_start = cur_pos;
 	return table->columns;
 }
@@ -306,7 +336,6 @@ MdbTableDef *table;
 MdbColumn *col;
 int coln;
 MdbIndex *idx;
-MdbHandle *mdb = entry->mdb;
 unsigned int i, bitn;
 guint32 pgnum;
 
@@ -316,6 +345,8 @@ guint32 pgnum;
 	fprintf(stdout,"number of columns   = %d\n",table->num_cols);
 	fprintf(stdout,"number of indices   = %d\n",table->num_real_idxs);
 
+	if (table->props)
+		mdb_dump_props(table->props, stdout, 0);
 	mdb_read_columns(table);
 	mdb_read_indices(table);
 
@@ -324,8 +355,10 @@ guint32 pgnum;
 
 		fprintf(stdout,"column %d Name: %-20s Type: %s(%d)\n",
 			i, col->name,
-			mdb_get_coltype_string(mdb->default_backend, col->col_type),
+			mdb_get_colbacktype_string(col),
 			col->col_size);
+		if (col->props)
+			mdb_dump_props(col->props, stdout, 0);
 	}
 
 	for (i=0;i<table->num_idxs;i++) {
@@ -371,3 +404,17 @@ int mdb_is_system_table(MdbCatalogEntry *entry)
 	return ((entry->object_type == MDB_TABLE)
 	 && (entry->flags & 0x80000002)) ? 1 : 0;
 }
+
+const char *
+mdb_table_get_prop(const MdbTableDef *table, const gchar *key) {
+	if (!table->props)
+		return NULL;
+	return g_hash_table_lookup(table->props->hash, key);
+}
+
+const char *
+mdb_col_get_prop(const MdbColumn *col, const gchar *key) {
+	if (!col->props)
+		return NULL;
+	return g_hash_table_lookup(col->props->hash, key);
+}
diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/worktable.c \
b/src/migration/mdb/3rdparty/mdbtools/libmdb/worktable.c index 09c064d..a398d98 \
                100644
--- a/src/migration/mdb/3rdparty/mdbtools/libmdb/worktable.c
+++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/worktable.c
@@ -12,9 +12,8 @@
  * 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.
+ * 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 "mdbtools.h"
@@ -74,6 +73,7 @@ mdb_create_temp_table(MdbHandle *mdb, char *name)
 void
 mdb_temp_table_add_col(MdbTableDef *table, MdbColumn *col)
 {
+	col->table = table,
 	col->col_num = table->num_cols;
 	if (!col->is_fixed)
 		col->var_col_num = table->num_var_cols++;
diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/write.c \
b/src/migration/mdb/3rdparty/mdbtools/libmdb/write.c index 69da633..95b806e 100644
--- a/src/migration/mdb/3rdparty/mdbtools/libmdb/write.c
+++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/write.c
@@ -12,41 +12,65 @@
  * 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.
+ * 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 <time.h>
+#include <math.h>
+#include <inttypes.h>
 #include "mdbtools.h"
-#include "time.h"
-#include "math.h"
 
 #ifdef DMALLOC
 #include "dmalloc.h"
 #endif
 
 
-
+//static int mdb_copy_index_pg(MdbTableDef *table, MdbIndex *idx, MdbIndexPage \
*ipg);  static int mdb_add_row_to_leaf_pg(MdbTableDef *table, MdbIndex *idx, \
MdbIndexPage *ipg, MdbField *idx_fields, guint32 pgnum, guint16 rownum);  
 void
-_mdb_put_int16(void *buf, guint32 offset, guint32 value)
+mdb_put_int16(void *buf, guint32 offset, guint32 value)
 {
 	value = GINT32_TO_LE(value);
 	memcpy((char*)buf + offset, &value, 2);
 }
 void
-_mdb_put_int32(void *buf, guint32 offset, guint32 value)
+_mdb_put_int16(void *buf, guint32 offset, guint32 value)
+#ifdef HAVE_ATTRIBUTE_ALIAS
+__attribute__((alias("mdb_put_int16")));
+#else
+{ mdb_put_int16((char*)buf, offset, value); }
+#endif
+
+void
+mdb_put_int32(void *buf, guint32 offset, guint32 value)
 {
 	value = GINT32_TO_LE(value);
 	memcpy((char*)buf + offset, &value, 4);
 }
 void
-_mdb_put_int32_msb(void *buf, guint32 offset, guint32 value)
+_mdb_put_int32(void *buf, guint32 offset, guint32 value)
+#ifdef HAVE_ATTRIBUTE_ALIAS
+__attribute__((alias("mdb_put_int32")));
+#else
+{ mdb_put_int32((char*)buf, offset, value); }
+#endif
+
+void
+mdb_put_int32_msb(void *buf, guint32 offset, guint32 value)
 {
 	value = GINT32_TO_BE(value);
 	memcpy((char*)buf + offset, &value, 4);
 }
+void
+_mdb_put_int32_mdb(void *buf, guint32 offset, guint32 value)
+#ifdef HAVE_ATTRIBUTE_ALIAS
+__attribute__((alias("mdb_put_int32_msb")));
+#else
+{ mdb_put_int32_msb((char*)buf, offset, value); }
+#endif
+
 ssize_t
 mdb_write_pg(MdbHandle *mdb, unsigned long pg)
 {
@@ -57,7 +81,7 @@ mdb_write_pg(MdbHandle *mdb, unsigned long pg)
 	fstat(mdb->f->fd, &status);
 	/* is page beyond current size + 1 ? */
 	if ((size_t)status.st_size < (offset + mdb->fmt->pg_size)) {
-		fprintf(stderr,"offset %lu is beyond EOF\n",offset);
+		fprintf(stderr,"offset %jd is beyond EOF\n",(intmax_t)offset);
 		return 0;
 	}
 	lseek(mdb->f->fd, offset, SEEK_SET);
@@ -158,31 +182,31 @@ mdb_crack_row(MdbTableDef *table, int row_start, int row_end, \
MdbField *fields)  unsigned int i;
 
 	if (mdb_get_option(MDB_DEBUG_ROW)) {
-		buffer_dump(pg_buf, row_start, row_end - row_start + 1);
+		mdb_buffer_dump(pg_buf, row_start, row_end - row_start + 1);
 	}
 
-	if (IS_JET4(mdb)) {
-		row_cols = mdb_get_int16(pg_buf, row_start);
-		col_count_size = 2;
-	} else {
+	if (IS_JET3(mdb)) {
 		row_cols = mdb_get_byte(pg_buf, row_start);
 		col_count_size = 1;
+	} else {
+		row_cols = mdb_get_int16(pg_buf, row_start);
+		col_count_size = 2;
 	}
 
 	bitmask_sz = (row_cols + 7) / 8;
-	nullmask = (unsigned char*)pg_buf + row_end - bitmask_sz + 1;
+	nullmask = (unsigned char *)pg_buf + row_end - bitmask_sz + 1;
 
 	/* read table of variable column locations */
-	row_var_cols = IS_JET4(mdb) ?
-		mdb_get_int16(pg_buf, row_end - bitmask_sz - 1) :
-		mdb_get_byte(pg_buf, row_end - bitmask_sz);
-	var_col_offsets = (unsigned int *)g_malloc((row_var_cols+1)*sizeof(int));
 	if (table->num_var_cols > 0) {
-		if (IS_JET4(mdb)) {
-			mdb_crack_row4(mdb, row_start, row_end, bitmask_sz,
+		row_var_cols = IS_JET3(mdb) ?
+			mdb_get_byte(pg_buf, row_end - bitmask_sz) :
+			mdb_get_int16(pg_buf, row_end - bitmask_sz - 1);
+		var_col_offsets = (unsigned int *)g_malloc((row_var_cols+1)*sizeof(int));
+		if (IS_JET3(mdb)) {
+			mdb_crack_row3(mdb, row_start, row_end, bitmask_sz,
 				 row_var_cols, var_col_offsets);
 		} else {
-			mdb_crack_row3(mdb, row_start, row_end, bitmask_sz,
+			mdb_crack_row4(mdb, row_start, row_end, bitmask_sz,
 				 row_var_cols, var_col_offsets);
 		}
 	}
@@ -246,7 +270,7 @@ mdb_pack_null_mask(unsigned char *buffer, int num_fields, \
MdbField *fields)  /* column is null if bit is clear (0) */
 		if (!fields[i].is_null) {
 			byte |= 1 << bit;
-
+			//printf("%d %d %d %d\n", i, bit, 1 << bit, byte);
 		}
 		bit++;
 		if (bit==8) {
@@ -404,10 +428,10 @@ mdb_pack_row(MdbTableDef *table, unsigned char *row_buffer, int \
unsigned num_fie  }
 		}
 	}
-	if (IS_JET4(table->entry->mdb)) {
-		return mdb_pack_row4(table, row_buffer, num_fields, fields);
-	} else {
+	if (IS_JET3(table->entry->mdb)) {
 		return mdb_pack_row3(table, row_buffer, num_fields, fields);
+	} else {
+		return mdb_pack_row4(table, row_buffer, num_fields, fields);
 	}
 }
 int
@@ -428,8 +452,8 @@ mdb_new_leaf_pg(MdbCatalogEntry *entry)
 	MdbHandle *mdb = entry->mdb;
 	void *new_pg = g_malloc0(mdb->fmt->pg_size);
 
-	_mdb_put_int16(new_pg, 2, 0x0104);
-	_mdb_put_int32(new_pg, 4, entry->table_pg);
+	mdb_put_int16(new_pg, 0, 0x0104);
+	mdb_put_int32(new_pg, 4, entry->table_pg);
 
 	return new_pg;
 }
@@ -439,13 +463,14 @@ mdb_new_data_pg(MdbCatalogEntry *entry)
 	MdbFormatConstants *fmt = entry->mdb->fmt;
 	void *new_pg = g_malloc0(fmt->pg_size);
 
-	_mdb_put_int16(new_pg, 2, 0x0101);
-	_mdb_put_int16(new_pg, 2, fmt->pg_size - fmt->row_count_offset - 2);
-	_mdb_put_int32(new_pg, 4, entry->table_pg);
+	mdb_put_int16(new_pg, 0, 0x0101);
+	mdb_put_int16(new_pg, 2, fmt->pg_size - fmt->row_count_offset - 2);
+	mdb_put_int32(new_pg, 4, entry->table_pg);
 
 	return new_pg;
 }
 
+/* could be static */
 int
 mdb_update_indexes(MdbTableDef *table, int num_fields, MdbField *fields, guint32 \
pgnum, guint16 rownum)  {
@@ -476,25 +501,22 @@ mdb_init_index_chain(MdbTableDef *table, MdbIndex *idx)
 	return 1;
 }
 
+/* could be static */
 int
 mdb_update_index(MdbTableDef *table, MdbIndex *idx, unsigned int num_fields, \
MdbField *fields, guint32 pgnum, guint16 rownum)  {
 	MdbCatalogEntry *entry = table->entry;
 	MdbHandle *mdb = entry->mdb;
-	/*
-	int idx_xref[16];
-	*/
+	/*int idx_xref[16];*/
 	unsigned int i, j;
 	MdbIndexChain *chain;
 	MdbField idx_fields[10];
 
 	for (i = 0; i < idx->num_keys; i++) {
 		for (j = 0; j < num_fields; j++) {
-			/* key_col_num is 1 based, can't remember why though */
+			// key_col_num is 1 based, can't remember why though
 			if (fields[j].colnum == idx->key_col_num[i]-1) {
-			        /*
-				idx_xref[i] = j;
-				*/
+				/* idx_xref[i] = j; */
 				idx_fields[i] = fields[j];
 			}
 		}
@@ -515,10 +537,10 @@ mdb_update_index(MdbTableDef *table, MdbIndex *idx, unsigned \
int num_fields, Mdb  chain = g_malloc0(sizeof(MdbIndexChain));
 
 	mdb_index_find_row(mdb, idx, chain, pgnum, rownum);
-
-
-
-
+	//printf("chain depth = %d\n", chain->cur_depth);
+	//printf("pg = %" G_GUINT32_FORMAT "\n",
+		//chain->pages[chain->cur_depth-1].pg);
+	//mdb_copy_index_pg(table, idx, &chain->pages[chain->cur_depth-1]);
 	mdb_add_row_to_leaf_pg(table, idx, &chain->pages[chain->cur_depth-1], idx_fields, \
pgnum, rownum);  
 	return 1;
@@ -541,7 +563,7 @@ mdb_insert_row(MdbTableDef *table, int num_fields, MdbField \
*fields)  }
 	new_row_size = mdb_pack_row(table, row_buffer, num_fields, fields);
 	if (mdb_get_option(MDB_DEBUG_WRITE)) {
-		buffer_dump(row_buffer, 0, new_row_size);
+		mdb_buffer_dump(row_buffer, 0, new_row_size);
 	}
 	pgnum = mdb_map_find_next_freepage(table, new_row_size);
 	if (!pgnum) {
@@ -552,13 +574,13 @@ mdb_insert_row(MdbTableDef *table, int num_fields, MdbField \
*fields)  rownum = mdb_add_row_to_pg(table, row_buffer, new_row_size);
 
 	if (mdb_get_option(MDB_DEBUG_WRITE)) {
-		buffer_dump(mdb->pg_buf, 0, 40);
-		buffer_dump(mdb->pg_buf, fmt->pg_size - 160, 160);
+		mdb_buffer_dump(mdb->pg_buf, 0, 40);
+		mdb_buffer_dump(mdb->pg_buf, fmt->pg_size - 160, 160);
 	}
 	mdb_debug(MDB_DEBUG_WRITE, "writing page %d", pgnum);
 	if (!mdb_write_pg(mdb, pgnum)) {
-		fprintf(stderr, "write failed! exiting...\n");
-		exit(1);
+		fprintf(stderr, "write failed!\n");
+		return 0;
 	}
 
 	mdb_update_indexes(table, num_fields, fields, pgnum, rownum);
@@ -606,7 +628,7 @@ mdb_add_row_to_pg(MdbTableDef *table, unsigned char *row_buffer, \
int new_row_siz  mdb_find_row(mdb, i, &row_start, &row_size);
 			pos -= row_size;
 			memcpy((char*)new_pg + pos, mdb->pg_buf + row_start, row_size);
-			_mdb_put_int16(new_pg, (fmt->row_count_offset + 2) + (i*2), pos);
+			mdb_put_int16(new_pg, (fmt->row_count_offset + 2) + (i*2), pos);
 		}
 	}
 
@@ -614,14 +636,14 @@ mdb_add_row_to_pg(MdbTableDef *table, unsigned char \
*row_buffer, int new_row_siz  pos -= new_row_size;
 	memcpy((char*)new_pg + pos, row_buffer, new_row_size);
 	/* add row to the row offset table */
-	_mdb_put_int16(new_pg, (fmt->row_count_offset + 2) + (num_rows*2), pos);
+	mdb_put_int16(new_pg, (fmt->row_count_offset + 2) + (num_rows*2), pos);
 
 	/* update number rows on this page */
 	num_rows++;
-	_mdb_put_int16(new_pg, fmt->row_count_offset, num_rows);
+	mdb_put_int16(new_pg, fmt->row_count_offset, num_rows);
 
 	/* update the freespace */
-	_mdb_put_int16(new_pg,2,pos - fmt->row_count_offset - 2 - (num_rows*2));
+	mdb_put_int16(new_pg,2,pos - fmt->row_count_offset - 2 - (num_rows*2));
 
 	/* copy new page over old */
 	if (!table->is_temp_table) {
@@ -655,7 +677,7 @@ unsigned int num_fields;
 
 	mdb_debug(MDB_DEBUG_WRITE,"page %lu row %d start %d end %d", (unsigned long) \
table->cur_phys_pg, table->cur_row-1, row_start, row_end);  if \
                (mdb_get_option(MDB_DEBUG_LIKE))
-		buffer_dump(mdb->pg_buf, row_start, old_row_size);
+		mdb_buffer_dump(mdb->pg_buf, row_start, old_row_size);
 
 	for (i=0;i<table->num_cols;i++) {
 		col = g_ptr_array_index(table->columns,i);
@@ -668,7 +690,7 @@ unsigned int num_fields;
 
 	if (mdb_get_option(MDB_DEBUG_WRITE)) {
 		for (i=0;i<num_fields;i++) {
-
+			//printf("col %d %d start %d siz %d fixed 5d\n", i, fields[i].colnum, \
fields[i].start, fields[i].siz, fields[i].is_fixed);  }
 	}
 	for (i=0;i<table->num_cols;i++) {
@@ -681,15 +703,21 @@ unsigned int num_fields;
 
 	new_row_size = mdb_pack_row(table, row_buffer, num_fields, fields);
 	if (mdb_get_option(MDB_DEBUG_WRITE))
-		buffer_dump(row_buffer, 0, new_row_size);
+		mdb_buffer_dump(row_buffer, 0, new_row_size);
 	if (new_row_size > (old_row_size + mdb_pg_get_freespace(mdb))) {
 		fprintf(stderr, "No space left on this page, update will not occur\n");
 		return 0;
 	}
 	/* do it! */
 	mdb_replace_row(table, table->cur_row-1, row_buffer, new_row_size);
-	return 0;
+	return 0; /* FIXME */
 }
+
+/* WARNING the return code is opposite to convention used elsewhere:
+ * returns 0 on success
+ * returns 1 on failure
+ * This might change on next ABI break.
+ */
 int
 mdb_replace_row(MdbTableDef *table, int row, void *new_row, int new_row_size)
 {
@@ -704,14 +732,14 @@ guint16 num_rows;
 int i, pos;
 
 	if (mdb_get_option(MDB_DEBUG_WRITE)) {
-		buffer_dump(mdb->pg_buf, 0, 40);
-		buffer_dump(mdb->pg_buf, pg_size - 160, 160);
+		mdb_buffer_dump(mdb->pg_buf, 0, 40);
+		mdb_buffer_dump(mdb->pg_buf, pg_size - 160, 160);
 	}
 	mdb_debug(MDB_DEBUG_WRITE,"updating row %d on page %lu", row, (unsigned long) \
table->cur_phys_pg);  new_pg = mdb_new_data_pg(entry);
 
 	num_rows = mdb_get_int16(mdb->pg_buf, rco);
-	_mdb_put_int16(new_pg, rco, num_rows);
+	mdb_put_int16(new_pg, rco, num_rows);
 
 	pos = pg_size;
 
@@ -720,20 +748,20 @@ int i, pos;
 		mdb_find_row(mdb, i, &row_start, &row_size);
 		pos -= row_size;
 		memcpy((char*)new_pg + pos, mdb->pg_buf + row_start, row_size);
-		_mdb_put_int16(new_pg, rco + 2 + i*2, pos);
+		mdb_put_int16(new_pg, rco + 2 + i*2, pos);
 	}
 
 	/* our row */
 	pos -= new_row_size;
 	memcpy((char*)new_pg + pos, new_row, new_row_size);
-	_mdb_put_int16(new_pg, rco + 2 + row*2, pos);
+	mdb_put_int16(new_pg, rco + 2 + row*2, pos);
 
 	/* rows after */
 	for (i=row+1;i<num_rows;i++) {
 		mdb_find_row(mdb, i, &row_start, &row_size);
 		pos -= row_size;
 		memcpy((char*)new_pg + pos, mdb->pg_buf + row_start, row_size);
-		_mdb_put_int16(new_pg, rco + 2 + i*2, pos);
+		mdb_put_int16(new_pg, rco + 2 + i*2, pos);
 	}
 
 	/* almost done, copy page over current */
@@ -741,15 +769,15 @@ int i, pos;
 
 	g_free(new_pg);
 
-	_mdb_put_int16(mdb->pg_buf, 2, mdb_pg_get_freespace(mdb));
+	mdb_put_int16(mdb->pg_buf, 2, mdb_pg_get_freespace(mdb));
 	if (mdb_get_option(MDB_DEBUG_WRITE)) {
-		buffer_dump(mdb->pg_buf, 0, 40);
-		buffer_dump(mdb->pg_buf, pg_size - 160, 160);
+		mdb_buffer_dump(mdb->pg_buf, 0, 40);
+		mdb_buffer_dump(mdb->pg_buf, pg_size - 160, 160);
 	}
 	/* drum roll, please */
 	if (!mdb_write_pg(mdb, table->cur_phys_pg)) {
-		fprintf(stderr, "write failed! exiting...\n");
-		exit(1);
+		fprintf(stderr, "write failed!\n");
+		return 1;
 	}
 	return 0;
 }
@@ -796,16 +824,18 @@ mdb_copy_index_pg(MdbTableDef *table, MdbIndex *idx, \
MdbIndexPage *ipg)  }
 
 		pg_row = mdb_get_int32_msb(mdb->pg_buf, ipg->offset + ipg->len - 4);
+		/* guint32 pg = pg_row >> 8; */
 		row = pg_row & 0xff;
+		/* unsigned char iflag = mdb->pg_buf[ipg->offset]; */
 
 		/* turn the key hash back into a value */
 		mdb_index_swap_n(&mdb->pg_buf[ipg->offset + 1], col->col_size, key_hash);
 		key_hash[col->col_size - 1] &= 0x7f;
 
 		if (mdb_get_option(MDB_DEBUG_WRITE)) {
-			buffer_dump(mdb->pg_buf, ipg->offset, ipg->len);
-			buffer_dump(mdb->pg_buf, ipg->offset + 1, col->col_size);
-			buffer_dump(key_hash, 0, col->col_size);
+			mdb_buffer_dump(mdb->pg_buf, ipg->offset, ipg->len);
+			mdb_buffer_dump(mdb->pg_buf, ipg->offset + 1, col->col_size);
+			mdb_buffer_dump(key_hash, 0, col->col_size);
 		}
 
 		memcpy((char*)new_pg + ipg->offset, mdb->pg_buf + ipg->offset, ipg->len);
@@ -815,31 +845,36 @@ mdb_copy_index_pg(MdbTableDef *table, MdbIndex *idx, \
MdbIndexPage *ipg)  row++;
 	}
 
+	if (!row) {
+		fprintf(stderr,"missing indexes not yet supported, aborting\n");
+		return 0;
+	}
+	//mdb_put_int16(new_pg, mdb->fmt->row_count_offset, row);
 	/* free space left */
-	_mdb_put_int16(new_pg, 2, mdb->fmt->pg_size - ipg->offset);
-
+	mdb_put_int16(new_pg, 2, mdb->fmt->pg_size - ipg->offset);
+	//printf("offset = %d\n", ipg->offset);
 
 	mdb_index_swap_n(idx_fields[0].value, col->col_size, key_hash);
 	key_hash[0] |= 0x080;
 	if (mdb_get_option(MDB_DEBUG_WRITE)) {
 		printf("key_hash\n");
-		buffer_dump(idx_fields[0].value, 0, col->col_size);
-		buffer_dump(key_hash, 0, col->col_size);
+		mdb_buffer_dump(idx_fields[0].value, 0, col->col_size);
+		mdb_buffer_dump(key_hash, 0, col->col_size);
 		printf("--------\n");
 	}
 	((char *)new_pg)[ipg->offset] = 0x7f;
 	memcpy((char*)new_pg + ipg->offset + 1, key_hash, col->col_size);
 	pg_row = (pgnum << 8) | ((rownum-1) & 0xff);
-	_mdb_put_int32_msb(new_pg, ipg->offset + 5, pg_row);
+	mdb_put_int32_msb(new_pg, ipg->offset + 5, pg_row);
 	ipg->idx_starts[row++] = ipg->offset + ipg->len;
-
+	//ipg->idx_starts[row] = ipg->offset + ipg->len;
 	if (mdb_get_option(MDB_DEBUG_WRITE)) {
-		buffer_dump(mdb->pg_buf, 0, mdb->fmt->pg_size);
+		mdb_buffer_dump(mdb->pg_buf, 0, mdb->fmt->pg_size);
 	}
 	memcpy(mdb->pg_buf, new_pg, mdb->fmt->pg_size);
 	mdb_index_pack_bitmap(mdb, ipg);
 	if (mdb_get_option(MDB_DEBUG_WRITE)) {
-		buffer_dump(mdb->pg_buf, 0, mdb->fmt->pg_size);
+		mdb_buffer_dump(mdb->pg_buf, 0, mdb->fmt->pg_size);
 	}
 	g_free(new_pg);
 
diff --git a/src/migration/mdb/3rdparty/mdbtools/update_diffs.sh \
b/src/migration/mdb/3rdparty/mdbtools/update_diffs.sh deleted file mode 100755
index fae35dc..0000000
--- a/src/migration/mdb/3rdparty/mdbtools/update_diffs.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-
-cd libmdb
-for i in `ls -1 *.c` ; do cd ..; diff -u ./libmdb.cvs/$i ./libmdb/$i > \
                ../diffs/`echo $i | sed -e 's/\.c/\.diff/g'` ; cd libmdb; done
-
-cd ..
-diff -u ./include.cvs/mdbtools.h ./include/mdbtools.h > ../diffs/mdbtools.diff
diff --git a/src/migration/mdb/ChangeLog b/src/migration/mdb/ChangeLog
index e7bf6b9..2db9229 100644
--- a/src/migration/mdb/ChangeLog
+++ b/src/migration/mdb/ChangeLog
@@ -1,3 +1,7 @@
+Mon Jun 24 21:04:51 CEST 2014
+  Update to mdbtools from June. This also fixes primary keys import.
+-- Jarosław Staniek <staniek@kde.org>
+
 Mon Jun  4 14:49:44 CEST 2007
   Ported to Qt4, imported into calligra/kexi/migration/ for Kexi 2.0.
 -- Jarosław Staniek <staniek@kde.org>
diff --git a/src/migration/mdb/src/CMakeLists.txt \
b/src/migration/mdb/src/CMakeLists.txt index 34e0a52..bbd90ad 100644
--- a/src/migration/mdb/src/CMakeLists.txt
+++ b/src/migration/mdb/src/CMakeLists.txt
@@ -3,7 +3,10 @@ if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_GNUC)
     add_definitions(-Wno-missing-format-attribute)
     add_definitions(-Wno-sign-compare)
     add_definitions(-Wno-unused-parameter)
-endif ()
+    add_definitions(-Wno-pointer-arith)
+    add_definitions(-std=c99)
+    add_definitions(-Wno-cast-qual)
+endif (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_GNUC)
 
 set(MDBTOOLS_SOURCE_DIR "${CMAKE_SOURCE_DIR}/src/migration/mdb/3rdparty/mdbtools")
 
@@ -31,7 +34,9 @@ ${MDBTOOLS_SOURCE_DIR}/libmdb/map.c
 ${MDBTOOLS_SOURCE_DIR}/libmdb/mem.c
 ${MDBTOOLS_SOURCE_DIR}/libmdb/money.c
 ${MDBTOOLS_SOURCE_DIR}/libmdb/options.c
+${MDBTOOLS_SOURCE_DIR}/libmdb/props.c
 ${MDBTOOLS_SOURCE_DIR}/libmdb/sargs.c
+${MDBTOOLS_SOURCE_DIR}/libmdb/stats.c
 ${MDBTOOLS_SOURCE_DIR}/libmdb/table.c
 ${MDBTOOLS_SOURCE_DIR}/libmdb/worktable.c
 ${MDBTOOLS_SOURCE_DIR}/libmdb/write.c
diff --git a/src/migration/mdb/src/keximdb/mdbmigrate.cpp \
b/src/migration/mdb/src/keximdb/mdbmigrate.cpp index e0c45ba..21f7b29 100644
--- a/src/migration/mdb/src/keximdb/mdbmigrate.cpp
+++ b/src/migration/mdb/src/keximdb/mdbmigrate.cpp
@@ -1,6 +1,6 @@
 /* This file is part of the KDE project
    Copyright (C) 2005,2006 Martin Ellis <martin.ellis@kdemail.net>
-   Copyright (C) 2005 Jarosław Staniek <staniek@kde.org>
+   Copyright (C) 2005-2014 Jarosław Staniek <staniek@kde.org>
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
@@ -50,18 +50,6 @@ MDBMigrate::MDBMigrate(QObject *parent, const QVariantList &args)
     setPropertyValue(nonUnicodePropId, QString());
     setPropertyCaption(nonUnicodePropId, xi18n("Source Database Non-Unicode \
Character Encoding"));  
-    initBackend();
-}
-
-MDBMigrate::~MDBMigrate()
-{
-    releaseBackend();
-}
-
-void MDBMigrate::initBackend()
-{
-    mdb_init();
-
     // Date format associated with Qt::ISODate: YYYY-MM-DDTHH:MM:SS
     // (where T is a literal).  The following is equivalent to %FT%T, but
     // backards compatible with old/Windows C libraries.
@@ -69,9 +57,8 @@ void MDBMigrate::initBackend()
     mdb_set_date_fmt("%Y-%m-%dT%H:%M:%S");
 }
 
-void MDBMigrate::releaseBackend()
+MDBMigrate::~MDBMigrate()
 {
-    mdb_exit();
 }
 
 QVariant MDBMigrate::propertyValue(const QByteArray& propName)
@@ -227,7 +214,7 @@ QVariant MDBMigrate::toQVariant(const char* data, unsigned int \
len, int type)  case MDB_BOOL:    //! @todo use &bool!
     case MDB_BYTE:
         return QString::fromUtf8(data, len).toShort();
-    case MDB_SDATETIME:
+    case MDB_DATETIME:
         return QDateTime::fromString(data, Qt::ISODate);
     case MDB_INT:
     case MDB_LONGINT:
@@ -350,7 +337,7 @@ KDbField::Type MDBMigrate::type(int type)
     case MDB_DOUBLE:
         kexiType = KDbField::Double;
         break;
-    case MDB_SDATETIME:
+    case MDB_DATETIME:
         kexiType = KDbField::DateTime;
         break;
     case MDB_TEXT:
@@ -428,10 +415,10 @@ bool MDBMigrate::getPrimaryKey(KDbTableSchema* table, \
MdbTableDef* tableDef)  
     if (ok) {
         //qDebug() << *p_idx;
-    
+
         // ... and add it to the table definition
         // but only if the PK has only one field, so far :o(
-    
+
         KDbField *f;
         if (idx->num_keys == 1 && (f = table->field(idx->key_col_num[0] - 1))) {
             f->setPrimaryKey(true);
@@ -455,5 +442,3 @@ bool MDBMigrate::drv_getTableSize(const QString& table, quint64& \
size)  mdb_free_tabledef(tableDef);
     return true;
 }
-
-
diff --git a/src/migration/mdb/src/keximdb/mdbmigrate.h \
b/src/migration/mdb/src/keximdb/mdbmigrate.h index c27b90e..d9669f9 100644
--- a/src/migration/mdb/src/keximdb/mdbmigrate.h
+++ b/src/migration/mdb/src/keximdb/mdbmigrate.h
@@ -1,6 +1,6 @@
 /* This file is part of the KDE project
    Copyright (C) 2005,2006 Martin Ellis <martin.ellis@kdemail.net>
-   Copyright (C) 2005 Jarosław Staniek <staniek@kde.org>
+   Copyright (C) 2005-2014 Jarosław Staniek <staniek@kde.org>
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
@@ -35,7 +35,6 @@ namespace KexiMigration
 
 class MDBMigrate : public KexiMigrate
 {
-    Q_OBJECT
     KEXIMIGRATION_DRIVER
 
 public:
@@ -86,8 +85,6 @@ protected:
     virtual bool drv_getTableSize(const QString& table, quint64 *size);
 
 private:
-    void initBackend();
-    void releaseBackend();
     MdbHandle *m_mdb;
 };
 }


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic