diff --git a/kexi/kexiutils/completer/KexiCompleter.cpp b/kexi/kexiutils/completer/KexiCompleter.cpp --- a/kexi/kexiutils/completer/KexiCompleter.cpp +++ b/kexi/kexiutils/completer/KexiCompleter.cpp @@ -148,7 +148,6 @@ #include #include #include -#include #include #include #include @@ -929,26 +928,27 @@ showPopup(popupRect); } -void KexiCompleterPrivate::showPopup(const QRect& rect) +static void adjustPopupGeometry(QWidget *popupWidget, QWidget *widget, int widthHint, + int heightHint, const QRect ¤tRect) { const QRect screen = QApplication::desktop()->availableGeometry(widget); - Qt::LayoutDirection dir = widget->layoutDirection(); + const Qt::LayoutDirection dir = widget->layoutDirection(); QPoint pos; int rh, w; - int h = (popup->sizeHintForRow(0) * qMin(maxVisibleItems, popup->model()->rowCount()) + 3) + 3; - QScrollBar *hsb = popup->horizontalScrollBar(); - if (hsb && hsb->isVisible()) - h += popup->horizontalScrollBar()->sizeHint().height(); + int h = heightHint; - if (rect.isValid()) { - rh = rect.height(); - w = rect.width(); - pos = widget->mapToGlobal(dir == Qt::RightToLeft ? rect.bottomRight() : rect.bottomLeft()); + if (currentRect.isValid()) { + rh = currentRect.height(); + w = currentRect.width(); + pos = widget->mapToGlobal(dir == Qt::RightToLeft ? currentRect.bottomRight() : currentRect.bottomLeft()); } else { rh = widget->height(); pos = widget->mapToGlobal(QPoint(0, widget->height() - 2)); w = widget->width(); } + if (widthHint > w) { + w = widthHint; + } if (w > screen.width()) w = screen.width(); @@ -959,16 +959,30 @@ int top = pos.y() - rh - screen.top() + 2; int bottom = screen.bottom() - pos.y(); - h = qMax(h, popup->minimumHeight()); + h = qMax(h, popupWidget->minimumHeight()); if (h > bottom) { h = qMin(qMax(top, bottom), h); if (top > bottom) pos.setY(pos.y() - h - rh + 2); } - popup->setGeometry(pos.x(), pos.y(), w, h); + popupWidget->setGeometry(pos.x(), pos.y(), w, h); +} +void KexiCompleterPrivate::showPopup(const QRect& rect) +{ + int widthHint = popup->sizeHintForColumn(0); + QScrollBar *vsb = popup->verticalScrollBar(); + if (vsb) { + widthHint += vsb->sizeHint().width() + 3 + 3; + } + int heightHint = (popup->sizeHintForRow(0) * qMin(maxVisibleItems, popup->model()->rowCount()) + 3) + 3; + QScrollBar *hsb = popup->horizontalScrollBar(); + if (hsb && hsb->isVisible()) { + heightHint += hsb->sizeHint().height(); + } + adjustPopupGeometry(popup, widget, widthHint, heightHint, rect); if (!popup->isVisible()) popup->show(); } diff --git a/kexi/main/KexiSearchLineEdit.cpp b/kexi/main/KexiSearchLineEdit.cpp --- a/kexi/main/KexiSearchLineEdit.cpp +++ b/kexi/main/KexiSearchLineEdit.cpp @@ -1,5 +1,5 @@ /* This file is part of the KDE project - Copyright (C) 2011-2015 Jarosław Staniek + Copyright (C) 2011-2016 Jarosław Staniek Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). This program is free software; you can redistribute it and/or @@ -199,6 +199,7 @@ } KexiSearchLineEditCompleter *completer; + QTreeView *popupTreeView; KexiSearchLineEditCompleterPopupModel *model; KexiSearchLineEditPopupItemDelegate *delegate; QPointer previouslyFocusedWidget; @@ -237,6 +238,17 @@ { } + //! Implemented to improve width hint + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const + { + QSize size(QStyledItemDelegate::sizeHint(option, index)); + QStyleOptionViewItemV4 v4 = option; + QStyledItemDelegate::initStyleOption(&v4, index); + const QSize s = v4.widget->style()->sizeFromContents(QStyle::CT_ItemViewItem, &v4, size, v4.widget); + size.setWidth(s.width()); + return size; + } + virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { @@ -352,10 +364,10 @@ : KLineEdit(parent), d(new Private(this)) { d->completer = new KexiSearchLineEditCompleter(this); - QTreeView *treeView = new QTreeView; - kexiTester() << KexiTestObject(treeView, "globalSearch.treeView"); + d->popupTreeView = new QTreeView; + kexiTester() << KexiTestObject(d->popupTreeView, "globalSearch.treeView"); - d->completer->setPopup(treeView); + d->completer->setPopup(d->popupTreeView); d->completer->setModel(d->model = new KexiSearchLineEditCompleterPopupModel(d->completer)); d->completer->setCaseSensitivity(Qt::CaseInsensitive); d->completer->setSubstringCompletion(true); @@ -365,10 +377,10 @@ // filtering so only table names are displayed. d->completer->setModelSorting(KexiCompleter::UnsortedModel); - treeView->setHeaderHidden(true); - treeView->setRootIsDecorated(false); - treeView->setItemDelegate( - d->delegate = new KexiSearchLineEditPopupItemDelegate(treeView, d->completer)); + d->popupTreeView->setHeaderHidden(true); + d->popupTreeView->setRootIsDecorated(false); + d->popupTreeView->setItemDelegate( + d->delegate = new KexiSearchLineEditPopupItemDelegate(d->popupTreeView, d->completer)); // forked initialization like in QLineEdit::setCompleter: d->completer->setWidget(this); @@ -809,6 +821,7 @@ d->completer->setCompletionPrefix(text); } + d->popupTreeView->resizeColumnToContents(0); d->completer->complete(); } diff --git a/kexi/migration/mdb/3rdparty/mdbtools/include/mdbtools.h b/kexi/migration/mdb/3rdparty/mdbtools/include/mdbtools.h --- a/kexi/migration/mdb/3rdparty/mdbtools/include/mdbtools.h +++ b/kexi/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 #include - #ifdef HAVE_ICONV #include #endif +#ifdef _WIN32 +#include +#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 { 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ } 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,6 +473,7 @@ /* 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); @@ -451,10 +492,13 @@ 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 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_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,23 +569,28 @@ 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); extern int mdb_update_row(MdbTableDef *table); 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); @@ -555,6 +608,7 @@ 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/kexi/migration/mdb/3rdparty/mdbtools/libmdb/catalog.c b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/catalog.c --- a/kexi/migration/mdb/3rdparty/mdbtools/libmdb/catalog.c +++ b/kexi/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" @@ -36,7 +35,7 @@ "Module", "Relationship", "Unknown 0x09", - "Unknown 0x0a", + "User Info", "Database" }; @@ -49,11 +48,21 @@ void mdb_free_catalog(MdbHandle *mdb) { - unsigned int i; + unsigned int i, j; + MdbCatalogEntry *entry; if ((!mdb) || (!mdb->catalog)) return; - for (i=0; icatalog->len; i++) - g_free (g_ptr_array_index(mdb->catalog, i)); + for (i=0; icatalog->len; i++) { + entry = (MdbCatalogEntry *)g_ptr_array_index(mdb->catalog, i); + if (entry) { + if (entry->props) { + for (j=0; jprops->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 @@ 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,31 +104,55 @@ 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); entry->object_type = (type & 0x7F); entry->table_pg = atol(obj_id) & 0x00FFFFFF; entry->flags = atol(obj_flags); mdb->num_catalog++; - g_ptr_array_add(mdb->catalog, entry); + 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; inum_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 @@ for (i=0;inum_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/kexi/migration/mdb/3rdparty/mdbtools/libmdb/data.c b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/data.c --- a/kexi/migration/mdb/3rdparty/mdbtools/libmdb/data.c +++ b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/data.c @@ -12,25 +12,25 @@ * 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 +#include #include "mdbtools.h" -#include "time.h" -#include "math.h" #ifdef DMALLOC #include "dmalloc.h" #endif #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); @@ -139,12 +139,12 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ #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,38 +307,52 @@ } 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; MdbHandle *mdb = entry->mdb; 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 /* can't do a fast read, go back to the old way */ 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 @@ } 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,32 +463,44 @@ 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) { guint32 ole_len; void *buf; 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 @@ 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,36 +673,29 @@ 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> 24); strcpy(text, ""); 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,75 +772,105 @@ 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; double y = 10.0; 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 @@ return (int)i; } } +#endif char *mdb_col_to_string(MdbHandle *mdb, void *buf, int start, int datatype, int size) { @@ -850,24 +907,29 @@ 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 @@ 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 @@ 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 @@ return 6; break; case MDB_LONGINT: + case MDB_COMPLEX: return 11; break; case MDB_FLOAT: @@ -918,7 +984,7 @@ case MDB_TEXT: return col->col_size; break; - case MDB_SDATETIME: + case MDB_DATETIME: return 20; break; case MDB_MEMO: @@ -943,6 +1009,7 @@ return 2; break; case MDB_LONGINT: + case MDB_COMPLEX: return 4; break; case MDB_FLOAT: @@ -954,9 +1021,12 @@ 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/kexi/migration/mdb/3rdparty/mdbtools/libmdb/dump.c b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/dump.c --- a/kexi/migration/mdb/3rdparty/mdbtools/libmdb/dump.c +++ b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/dump.c @@ -1,12 +1,30 @@ +/* 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 #include #include #ifdef DMALLOC #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/kexi/migration/mdb/3rdparty/mdbtools/libmdb/file.c b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/file.c --- a/kexi/migration/mdb/3rdparty/mdbtools/libmdb/file.c +++ b/kexi/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 #include "mdbtools.h" #ifdef DMALLOC @@ -35,7 +35,7 @@ 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 @@ 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 + */ + +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 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* 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/kexi/migration/mdb/3rdparty/mdbtools/libmdb/iconv.c b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/iconv.c --- a/kexi/migration/mdb/3rdparty/mdbtools/libmdb/iconv.c +++ b/kexi/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 #include "mdbtools.h" -#include "errno.h" #ifdef DMALLOC #include "dmalloc.h" @@ -43,7 +42,7 @@ 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 @@ 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 @@ if (tmp) g_free(tmp); dest[dlen]='\0'; - + //printf("dest %s\n",dest); return dlen; } @@ -123,7 +125,7 @@ #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 @@ #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 @@ 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 @@ } #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 */ @@ -207,9 +224,10 @@ #ifdef _WIN32 // 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 )) + if (GetLocaleInfoA( MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), SORT_DEFAULT), + 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_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/kexi/migration/mdb/3rdparty/mdbtools/libmdb/index.c b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/index.c --- a/kexi/migration/mdb/3rdparty/mdbtools/libmdb/index.c +++ b/kexi/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,91 +68,134 @@ 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;inum_idxs;i++) { read_pg_if_n(mdb, tmpbuf, &cur_pos, idx2_sz); pidx = (MdbIndex *) g_malloc0(sizeof(MdbIndex)); pidx->table = table; pidx->index_num = mdb_get_int16(tmpbuf, 4); - pidx->index_type = tmpbuf[type_offset]; + 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;inum_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;inum_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; jnum_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;jnum_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 @@ 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 @@ 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 @@ MdbSarg *sarg; MdbField field; MdbSargNode node; - + //int c_offset = 0, int c_len; - - - - + //fprintf(stderr,"mdb_index_test_sargs called on "); + //for (i=0;ipg_buf[offset+i]); + //fprintf(stderr,"\n"); for (i=0;inum_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 @@ for (j=0;jnum_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 @@ /* 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 @@ 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 @@ /* 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 @@ ipg->idx_starts[elem++]=start; - + //fprintf(stdout, "Unpacking index page %lu\n", ipg->pg); do { len = 0; do { @@ -365,7 +407,7 @@ 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,15 +430,15 @@ /* 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); } 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,22 +485,22 @@ */ 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; /* * add to the chain and call this function * recursively. */ 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,24 +559,24 @@ { MdbIndexPage *ipg; - + //printf("page %lu finished\n",ipg->pg); if (chain->cur_depth==1) { - + //printf("cur_depth == 1 we're out\n"); return NULL; } /* * unwind the stack until we find something or reach * the top. */ 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,49 +619,49 @@ 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; } } 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 @@ 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 @@ for (i=0;inum_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 @@ */ 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 @@ for (i=0;inum_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 @@ 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/kexi/migration/mdb/3rdparty/mdbtools/libmdb/like.c b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/like.c --- a/kexi/migration/mdb/3rdparty/mdbtools/libmdb/like.c +++ b/kexi/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 #include -#include +#include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" diff --git a/kexi/migration/mdb/3rdparty/mdbtools/libmdb/map.c b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/map.c --- a/kexi/migration/mdb/3rdparty/mdbtools/libmdb/map.c +++ b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/map.c @@ -12,18 +12,17 @@ * 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" #ifdef DMALLOC #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 @@ /* 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 @@ /* 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,20 +116,23 @@ 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; mdb_read_pg(mdb, pgnum); free_space = mdb_pg_get_freespace(mdb); } while (free_space < row_size); - + //printf("page %d has %d bytes left\n", pgnum, free_space); return pgnum; } diff --git a/kexi/migration/mdb/3rdparty/mdbtools/libmdb/mem.c b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/mem.c --- a/kexi/migration/mdb/3rdparty/mdbtools/libmdb/mem.c +++ b/kexi/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 -#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/kexi/migration/mdb/3rdparty/mdbtools/libmdb/money.c b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/money.c --- a/kexi/migration/mdb/3rdparty/mdbtools/libmdb/money.c +++ b/kexi/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 @@ -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 @@ */ 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;ipg_buf + start + 1, num_bytes); + + /* Perform two's complement for negative numbers */ + if (mdb->pg_buf[start] & 0x80) neg = 1; + for (i=0;i9) { product[j+1]+=product[j]/10; product[j]=product[j]%10; @@ -117,9 +145,10 @@ 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/kexi/migration/mdb/3rdparty/mdbtools/libmdb/options.c b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/options.c --- a/kexi/migration/mdb/3rdparty/mdbtools/libmdb/options.c +++ b/kexi/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 #include #include #include - -#include +#include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" @@ -42,11 +40,11 @@ va_list ap; if (!optset) load_options(); - if (klass & opts) { - va_start(ap, fmt); - vfprintf (stdout,fmt, ap); - va_end(ap); - fprintf(stdout,"\n"); + if (klass & opts) { + va_start(ap, fmt); + vfprintf (stderr,fmt, ap); + va_end(ap); + fprintf(stderr,"\n"); } #endif } @@ -57,26 +55,28 @@ 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/kexi/migration/mdb/3rdparty/mdbtools/libmdb/props.c b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/props.c new file mode 100644 --- /dev/null +++ b/kexi/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/kexi/migration/mdb/3rdparty/mdbtools/libmdb/sargs.c b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/sargs.c --- a/kexi/migration/mdb/3rdparty/mdbtools/libmdb/sargs.c +++ b/kexi/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 +#include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif @@ -76,7 +76,7 @@ { 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 @@ } 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 @@ * 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 @@ 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/kexi/migration/mdb/3rdparty/mdbtools/libmdb/stats.c b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/stats.c new file mode 100644 --- /dev/null +++ b/kexi/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/kexi/migration/mdb/3rdparty/mdbtools/libmdb/table.c b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/table.c --- a/kexi/migration/mdb/3rdparty/mdbtools/libmdb/table.c +++ b/kexi/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 *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 @@ 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 @@ table->first_data_pg = mdb_get_int16(pg_buf, fmt->tab_first_dpg_offset); + if (entry->props) + for (i=0; iprops->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,29 +168,28 @@ 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)); *cur_pos -= (mdb->fmt->pg_size - 8); } /* 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,22 +199,32 @@ } void mdb_free_columns(GPtrArray *columns) { - unsigned int i; + unsigned int i, j; + MdbColumn *col; if (!columns) return; - for (i=0; ilen; i++) - g_free (g_ptr_array_index(columns, i)); + for (i=0; ilen; i++) { + col = (MdbColumn *) g_ptr_array_index(columns, i); + if (col->sargs) { + for (j=0; jsargs->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) { MdbHandle *mdb = table->entry->mdb; 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,41 +241,45 @@ for (i=0;inum_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->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) { pcol->col_prec = col[11]; pcol->col_scale = col[12]; } - - pcol->is_fixed = col[fmt->col_fixed_offset] & 0x01 ? 1 : 0; + // 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; - + // 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 @@ 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;inum_cols;i++) { + pcol = g_ptr_array_index(table->columns, i); + for (j=0; jlen; ++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 @@ MdbColumn *col; int coln; MdbIndex *idx; -MdbHandle *mdb = entry->mdb; unsigned int i, bitn; guint32 pgnum; @@ -316,16 +345,20 @@ 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); for (i=0;inum_cols;i++) { col = g_ptr_array_index(table->columns,i); 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;inum_idxs;i++) { @@ -371,3 +404,17 @@ 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/kexi/migration/mdb/3rdparty/mdbtools/libmdb/worktable.c b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/worktable.c --- a/kexi/migration/mdb/3rdparty/mdbtools/libmdb/worktable.c +++ b/kexi/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 @@ 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/kexi/migration/mdb/3rdparty/mdbtools/libmdb/write.c b/kexi/migration/mdb/3rdparty/mdbtools/libmdb/write.c --- a/kexi/migration/mdb/3rdparty/mdbtools/libmdb/write.c +++ b/kexi/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 +#include +#include #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 @@ 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 @@ 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 = (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 @@ /* 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 @@ } } } - 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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,22 +628,22 @@ 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); } } /* add our new row */ 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 @@ 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;inum_cols;i++) { col = g_ptr_array_index(table->columns,i); @@ -668,7 +690,7 @@ if (mdb_get_option(MDB_DEBUG_WRITE)) { for (i=0;inum_cols;i++) { @@ -681,15 +703,21 @@ 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,52 +732,52 @@ 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; /* rows before */ for (i=0;ipg_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;ipg_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 */ memcpy(mdb->pg_buf, new_pg, pg_size); 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,50 +824,57 @@ } 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); ipg->offset += ipg->len; ipg->len = 0; 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/kexi/migration/mdb/3rdparty/mdbtools/update_diffs.sh b/kexi/migration/mdb/3rdparty/mdbtools/update_diffs.sh deleted file mode 100755 --- a/kexi/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/kexi/migration/mdb/ChangeLog b/kexi/migration/mdb/ChangeLog --- a/kexi/migration/mdb/ChangeLog +++ b/kexi/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 + Mon Jun 4 14:49:44 CEST 2007 Ported to Qt4, imported into calligra/kexi/migration/ for Kexi 2.0. -- Jarosław Staniek diff --git a/kexi/migration/mdb/src/CMakeLists.txt b/kexi/migration/mdb/src/CMakeLists.txt --- a/kexi/migration/mdb/src/CMakeLists.txt +++ b/kexi/migration/mdb/src/CMakeLists.txt @@ -3,7 +3,9 @@ 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) +endif (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_GNUC) set(MDBTOOLS_SOURCE_DIR "${CMAKE_SOURCE_DIR}/kexi/migration/mdb/3rdparty/mdbtools") @@ -31,7 +33,9 @@ ${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/kexi/migration/mdb/src/keximdb/mdbmigrate.h b/kexi/migration/mdb/src/keximdb/mdbmigrate.h --- a/kexi/migration/mdb/src/keximdb/mdbmigrate.h +++ b/kexi/migration/mdb/src/keximdb/mdbmigrate.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project Copyright (C) 2005,2006 Martin Ellis - Copyright (C) 2005 Jarosław Staniek + Copyright (C) 2005-2014 Jarosław Staniek This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -33,7 +33,6 @@ class MDBMigrate : public KexiMigrate { - Q_OBJECT KEXIMIGRATION_DRIVER public: @@ -84,8 +83,6 @@ virtual bool drv_getTableSize(const QString& table, qulonglong& size); private: - void initBackend(); - void releaseBackend(); MdbHandle *m_mdb; }; } diff --git a/kexi/migration/mdb/src/keximdb/mdbmigrate.cpp b/kexi/migration/mdb/src/keximdb/mdbmigrate.cpp --- a/kexi/migration/mdb/src/keximdb/mdbmigrate.cpp +++ b/kexi/migration/mdb/src/keximdb/mdbmigrate.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project Copyright (C) 2005,2006 Martin Ellis - Copyright (C) 2005 Jarosław Staniek + Copyright (C) 2005-2014 Jarosław Staniek This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -51,28 +51,15 @@ setPropertyValue(nonUnicodePropId, QString()); setPropertyCaption(nonUnicodePropId, i18n("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. // See strftime documentation for more info. mdb_set_date_fmt("%Y-%m-%dT%H:%M:%S"); } -void MDBMigrate::releaseBackend() +MDBMigrate::~MDBMigrate() { - mdb_exit(); } QVariant MDBMigrate::propertyValue(const QByteArray& propName) @@ -224,7 +211,7 @@ 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: @@ -347,7 +334,7 @@ case MDB_DOUBLE: kexiType = KexiDB::Field::Double; break; - case MDB_SDATETIME: + case MDB_DATETIME: kexiType = KexiDB::Field::DateTime; break; case MDB_TEXT: @@ -446,6 +433,3 @@ mdb_free_tabledef(tableDef); return true; } - - -#include "mdbmigrate.moc" diff --git a/kexi/plugins/queries/kexiquerydesignerguieditor.h b/kexi/plugins/queries/kexiquerydesignerguieditor.h --- a/kexi/plugins/queries/kexiquerydesignerguieditor.h +++ b/kexi/plugins/queries/kexiquerydesignerguieditor.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project Copyright (C) 2004 Lucijan Busch - Copyright (C) 2004-2015 Jarosław Staniek + Copyright (C) 2004-2016 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public diff --git a/kexi/plugins/queries/kexiquerydesignerguieditor.cpp b/kexi/plugins/queries/kexiquerydesignerguieditor.cpp --- a/kexi/plugins/queries/kexiquerydesignerguieditor.cpp +++ b/kexi/plugins/queries/kexiquerydesignerguieditor.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project Copyright (C) 2004 Lucijan Busch - Copyright (C) 2004-2015 Jarosław Staniek + Copyright (C) 2004-2016 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -602,7 +602,7 @@ if (!d->dataTable->dataAwareObject()->acceptRowEdit()) return cancelled; - kDebug() << "queryChangedInPreviousView:" << tempData()->queryChangedInPreviousView(); + kDebug() << "queryChangedInView:" << tempData()->queryChangedInView(); if (mode == Kexi::DesignViewMode) { return true; @@ -612,7 +612,7 @@ KMessageBox::information(this, msgCannotSwitch_EmptyDesign()); return cancelled; } - if (tempData()->queryChangedInPreviousView() || !tempData()->query()) { + if (tempData()->queryChangedInView() != Kexi::NoViewMode || !tempData()->query()) { //remember current design in a temporary structure QString errMsg; //build schema; problems are not allowed @@ -626,7 +626,7 @@ return true; } else if (mode == Kexi::TextViewMode) { dontStore = true; - if (tempData()->queryChangedInPreviousView() || !tempData()->query()) { + if (tempData()->queryChangedInView() != Kexi::NoViewMode || !tempData()->query()) { //remember current design in a temporary structure //build schema; ignore problems buildSchema(); @@ -676,8 +676,8 @@ } else if (mode == Kexi::TextViewMode || mode == Kexi::DataViewMode) { // Switch from text or data view. In the second case, the design could be changed as well // because there could be changes made in the text view before switching to the data view. - if (tempData()->queryChangedInPreviousView()) { - //previous view changed query data + if (tempData()->queryChangedInView() == Kexi::TextViewMode) { + //SQL view changed the query design //-clear and regenerate GUI items initTableRows(); //! @todo @@ -711,7 +711,7 @@ d->dataTable->tableView()->adjustColumnWidthToContents(COLUMN_ID_COLUMN); d->dataTable->tableView()->adjustColumnWidthToContents(COLUMN_ID_TABLE); } - tempData()->setQueryChangedInPreviousView(false); + tempData()->setQueryChangedInView(false); setFocus(); //to allow shared actions proper update return true; } @@ -729,7 +729,7 @@ } QString errMsg; KexiQueryPart::TempData * temp = tempData(); - if (!temp->query() || !(viewMode() == Kexi::DesignViewMode && !temp->queryChangedInPreviousView())) { + if (!temp->query() || !(viewMode() == Kexi::DesignViewMode && temp->queryChangedInView() == Kexi::NoViewMode)) { //only rebuild schema if it has not been rebuilt previously if (!buildSchema(&errMsg)) { KMessageBox::sorry(this, errMsg); @@ -1254,24 +1254,24 @@ propertySetSwitched(); d->droppedNewRecord = 0; } - tempData()->setQueryChangedInPreviousView(true); + tempData()->setQueryChangedInView(true); } void KexiQueryDesignerGuiEditor::slotTableAdded(KexiDB::TableSchema & /*t*/) { if (!d->slotTableAdded_enabled) return; updateColumnsData(); setDirty(); - tempData()->setQueryChangedInPreviousView(true); + tempData()->setQueryChangedInView(true); d->dataTable->setFocus(); } void KexiQueryDesignerGuiEditor::slotTableHidden(KexiDB::TableSchema & /*t*/) { updateColumnsData(); setDirty(); - tempData()->setQueryChangedInPreviousView(true); + tempData()->setQueryChangedInView(true); } QByteArray KexiQueryDesignerGuiEditor::generateUniqueAlias() const @@ -1624,7 +1624,7 @@ #else //! @todo unused yet setDirty(true); - tempData()->setQueryChangedInPreviousView(true); + tempData()->setQueryChangedInView(true); #endif } @@ -1703,7 +1703,7 @@ (*set)["criteria"] = QVariant(); //clear it } setDirty(true); - tempData()->setQueryChangedInPreviousView(true); + tempData()->setQueryChangedInView(true); } else { result->success = false; @@ -1716,13 +1716,13 @@ void KexiQueryDesignerGuiEditor::slotTablePositionChanged(KexiRelationsTableContainer*) { setDirty(true); - // this is not needed here because only position has changed: tempData()->setQueryChangedInPreviousView(true); + // this is not needed here because only position has changed: tempData()->setQueryChangedInView(true); } void KexiQueryDesignerGuiEditor::slotAboutConnectionRemove(KexiRelationsConnection*) { setDirty(true); - tempData()->setQueryChangedInPreviousView(true); + tempData()->setQueryChangedInView(true); } void KexiQueryDesignerGuiEditor::slotAppendFields( @@ -1853,7 +1853,7 @@ } } } - tempData()->setQueryChangedInPreviousView(true); + tempData()->setQueryChangedInView(true); } void KexiQueryDesignerGuiEditor::slotNewItemStored(KexiPart::Item& item) diff --git a/kexi/plugins/queries/kexiquerydesignersql.h b/kexi/plugins/queries/kexiquerydesignersql.h --- a/kexi/plugins/queries/kexiquerydesignersql.h +++ b/kexi/plugins/queries/kexiquerydesignersql.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch - Copyright (C) 2004-2012 Jarosław Staniek + Copyright (C) 2004-2016 Jarosław Staniek This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public diff --git a/kexi/plugins/queries/kexiquerydesignersql.cpp b/kexi/plugins/queries/kexiquerydesignersql.cpp --- a/kexi/plugins/queries/kexiquerydesignersql.cpp +++ b/kexi/plugins/queries/kexiquerydesignersql.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch - Copyright (C) 2004-2014 Jarosław Staniek + Copyright (C) 2004-2016 Jarosław Staniek This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -18,6 +18,11 @@ * Boston, MA 02110-1301, USA. */ +#include "kexiquerydesignersql.h" +#include "kexiquerydesignersqleditor.h" +#include "kexiquerypart.h" +#include "kexisectionheader.h" + #include #include #include @@ -41,13 +46,6 @@ #include #include -#include "kexiquerydesignersqleditor.h" -#include "kexiquerydesignersql.h" -#include "kexiquerypart.h" - -#include "kexisectionheader.h" - - static bool compareSQL(const QString& sql1, const QString& sql2) { //! @todo use reformatting functions here @@ -211,7 +209,7 @@ if (sqlTextIsEmpty && mode == Kexi::DesignViewMode) { //special case: empty SQL text, allow to switch to the design view if (temp->query()) { - temp->setQueryChangedInPreviousView(true); //query changed + temp->setQueryChangedInView(true); //query changed temp->setQuery(0); } } @@ -224,7 +222,7 @@ && compareSQL(d->origStatement, d->editor->text())) { //statement unchanged! - nothing to do - temp->setQueryChangedInPreviousView(false); + temp->setQueryChangedInView(false); } else { //yes: parse SQL text if (sqlTextIsEmpty || !slotCheckQuery()) { @@ -235,7 +233,7 @@ return cancelled; } //do not change original query - it's invalid - temp->setQueryChangedInPreviousView(false); + temp->setQueryChangedInView(false); //this view is no longer _just_ switched from "NoViewMode" d->justSwitchedFromNoViewMode = false; return true; @@ -245,7 +243,7 @@ //replace old query schema with new one temp->setQuery(d->parsedQuery); //this will also delete temp->query() d->parsedQuery = 0; - temp->setQueryChangedInPreviousView(true); + temp->setQueryChangedInView(true); } } d->origStatement = d->editor->text(); @@ -279,7 +277,7 @@ if (query) { // Use query with Kexi keywords (but not driver-specific keywords) escaped. temp->setQuery(query); - if (temp->queryChangedInPreviousView()) { + if (temp->queryChangedInView() != Kexi::NoViewMode) { KexiDB::Connection::SelectStatementOptions options; options.identifierEscaping = KexiDB::Driver::EscapeKexi; options.addVisibleLookupColumns = false; @@ -293,10 +291,19 @@ return false; } - if (!compareSQL(d->origStatement, d->editor->text())) { - d->slotTextChangedEnabled = false; - d->editor->setText(d->origStatement); - d->slotTextChangedEnabled = true; + if (temp->queryChangedInView() == Kexi::DesignViewMode /* true in this scenario: + - user switched from SQL to Design, + - changed the design, + - switched to Data + - switched back to SQL */ + || mode != Kexi::DataViewMode) /* true in this scenario: user switched from No-view + or Design view */ + { + if (!compareSQL(d->origStatement, d->editor->text())) { + d->slotTextChangedEnabled = false; + d->editor->setText(d->origStatement); + d->slotTextChangedEnabled = true; + } } QTimer::singleShot(100, d->editor, SLOT(setFocus())); return true; diff --git a/kexi/plugins/queries/kexiquerypart.h b/kexi/plugins/queries/kexiquerypart.h --- a/kexi/plugins/queries/kexiquerypart.h +++ b/kexi/plugins/queries/kexiquerypart.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch - Copyright (C) 2004-2010 Jarosław Staniek + Copyright (C) 2004-2016 Jarosław Staniek This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -79,19 +79,22 @@ //! Connection used for retrieving definition of the query KexiDB::Connection *conn; - /*! @return true if \a query member has changed in previous view. + /*! @return view mode if which the query member has changed. + It's possibly one of previously visited views. Kexi::NoViewMode is the default, + what means that query was not changed. Used on view switching. We're checking this flag to see if we should rebuild internal structure for DesignViewMode of regenerated sql text in TextViewMode after switch from other view. */ - bool queryChangedInPreviousView() const; + Kexi::ViewMode queryChangedInView() const; - /*! Sets the queryChangedInPreviousView flag. - @see queryChangedInPreviousView() */ - void setQueryChangedInPreviousView(bool set); + /*! Sets the queryChangedInView flag. If @a set is true, then the flag is changed + to the current view mode. If @a set is false, the flag is changed to Kexi::NoViewMode. + @see queryChangedInView() */ + void setQueryChangedInView(bool set); private: KexiDB::QuerySchema *m_query; - bool m_queryChangedInPreviousView; + Kexi::ViewMode m_queryChangedInView; }; virtual KLocalizedString i18nMessage(const QString& englishMessage, diff --git a/kexi/plugins/queries/kexiquerypart.cpp b/kexi/plugins/queries/kexiquerypart.cpp --- a/kexi/plugins/queries/kexiquerypart.cpp +++ b/kexi/plugins/queries/kexiquerypart.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project Copyright (C) 2004 Lucijan Busch - Copyright (C) 2004-2010 Jarosław Staniek + Copyright (C) 2004-2016 Jarosław Staniek This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -178,7 +178,7 @@ : KexiWindowData(window) , KexiDB::Connection::TableSchemaChangeListenerInterface() , m_query(0) - , m_queryChangedInPreviousView(false) + , m_queryChangedInView(Kexi::NoViewMode) { this->conn = conn; } @@ -236,14 +236,15 @@ m_query = query; } -bool KexiQueryPart::TempData::queryChangedInPreviousView() const +Kexi::ViewMode KexiQueryPart::TempData::queryChangedInView() const { - return m_queryChangedInPreviousView; + return m_queryChangedInView; } -void KexiQueryPart::TempData::setQueryChangedInPreviousView(bool set) +void KexiQueryPart::TempData::setQueryChangedInView(bool set) { - m_queryChangedInPreviousView = set; + m_queryChangedInView = set ? qobject_cast(parent())->currentViewMode() + : Kexi::NoViewMode; } //----------------