diff options
Diffstat (limited to 'keximdb/src/mdbtools/libmdb/table.c')
-rw-r--r-- | keximdb/src/mdbtools/libmdb/table.c | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/keximdb/src/mdbtools/libmdb/table.c b/keximdb/src/mdbtools/libmdb/table.c new file mode 100644 index 0000000..8bf5f59 --- /dev/null +++ b/keximdb/src/mdbtools/libmdb/table.c @@ -0,0 +1,372 @@ +/* MDB Tools - A library for reading MS Access database file + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "mdbtools.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + + +static gint mdb_col_comparer(MdbColumn **a, MdbColumn **b) +{ + if ((*a)->col_num > (*b)->col_num) + return 1; + else if ((*a)->col_num < (*b)->col_num) + return -1; + else + return 0; +} + +unsigned char mdb_col_needs_size(int col_type) +{ + if (col_type == MDB_TEXT) { + return TRUE; + } else { + return FALSE; + } +} + +MdbTableDef *mdb_alloc_tabledef(MdbCatalogEntry *entry) +{ + MdbTableDef *table; + + table = (MdbTableDef *) g_malloc0(sizeof(MdbTableDef)); + table->entry=entry; + strcpy(table->name, entry->object_name); + + return table; +} +void mdb_free_tabledef(MdbTableDef *table) +{ + if (!table) return; + if (table->is_temp_table) { + unsigned int i; + /* Temp table pages are being stored in memory */ + for (i=0; i<table->temp_table_pages->len; i++) + g_free(g_ptr_array_index(table->temp_table_pages,i)); + g_ptr_array_free(table->temp_table_pages, TRUE); + /* Temp tables use dummy entries */ + g_free(table->entry); + } + mdb_free_columns(table->columns); + mdb_free_indices(table->indices); + g_free(table->usage_map); + g_free(table->free_usage_map); + g_free(table); +} +MdbTableDef *mdb_read_table(MdbCatalogEntry *entry) +{ + MdbTableDef *table; + MdbHandle *mdb = entry->mdb; + MdbFormatConstants *fmt = mdb->fmt; + int len, row_start, pg_row; + void *buf, *pg_buf = mdb->pg_buf; + + 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); + + 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); + table->num_cols = mdb_get_int16(pg_buf, fmt->tab_num_cols_offset); + table->num_idxs = mdb_get_int32(pg_buf, fmt->tab_num_idxs_offset); + table->num_real_idxs = mdb_get_int32(pg_buf, fmt->tab_num_ridxs_offset); + + /* grab a copy of the usage map */ + pg_row = mdb_get_int32(pg_buf, fmt->tab_usage_map_offset); + 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_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); + + /* grab a copy of the free space page map */ + pg_row = mdb_get_int32(pg_buf, fmt->tab_free_map_offset); + mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &(table->freemap_sz)); + table->free_usage_map = g_memdup((char*)buf + row_start, table->freemap_sz); + mdb_debug(MDB_DEBUG_USAGE,"free map found on page %ld row %d start %d len %d\n", + pg_row >> 8, pg_row & 0xff, row_start, table->freemap_sz); + + table->first_data_pg = mdb_get_int16(pg_buf, fmt->tab_first_dpg_offset); + + return table; +} +MdbTableDef *mdb_read_table_by_name(MdbHandle *mdb, gchar *table_name, int obj_type) +{ + unsigned int i; + MdbCatalogEntry *entry; + + mdb_read_catalog(mdb, obj_type); + + for (i=0; i<mdb->num_catalog; i++) { + entry = g_ptr_array_index(mdb->catalog, i); + if (!strcasecmp(entry->object_name, table_name)) + return mdb_read_table(entry); + } + + return NULL; +} + + +guint32 +read_pg_if_32(MdbHandle *mdb, int *cur_pos) +{ + char c[4]; + + read_pg_if_n(mdb, c, cur_pos, 4); + return mdb_get_int32(c, 0); +} +guint16 +read_pg_if_16(MdbHandle *mdb, int *cur_pos) +{ + char c[2]; + + read_pg_if_n(mdb, c, cur_pos, 2); + return mdb_get_int16(c, 0); +} +guint8 +read_pg_if_8(MdbHandle *mdb, int *cur_pos) +{ + guint8 c; + + read_pg_if_n(mdb, &c, cur_pos, 1); + return c; +} +/* + * Read data into a buffer, advancing pages and setting the + * page cursor as needed. In the case that buf in NULL, pages + * are still advanced and the page cursor is still updated. + */ +void * +read_pg_if_n(MdbHandle *mdb, void *buf, int *cur_pos, size_t len) +{ + /* 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) { + 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) { + memcpy(buf, mdb->pg_buf + *cur_pos, len); + } + *cur_pos += len; + return buf; +} + + +void mdb_append_column(GPtrArray *columns, MdbColumn *in_col) +{ + g_ptr_array_add(columns, g_memdup(in_col,sizeof(MdbColumn))); +} +void mdb_free_columns(GPtrArray *columns) +{ + unsigned int i; + + if (!columns) return; + for (i=0; i<columns->len; i++) + g_free (g_ptr_array_index(columns, i)); + 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; + int cur_pos; + size_t name_sz; + + table->columns = g_ptr_array_new(); + + col = (unsigned char *) g_malloc(fmt->tab_col_entry_size); + + cur_pos = fmt->tab_cols_start_offset + + (table->num_real_idxs * fmt->tab_ridx_entry_size); + + /* new code based on patch submitted by Tim Nelson 2000.09.27 */ + + /* + ** column attributes + */ + for (i=0;i<table->num_cols;i++) { +#ifdef MDB_DEBUG + /* printf("column %d\n", i); + buffer_dump(mdb->pg_buf, cur_pos, fmt->tab_col_entry_size); */ +#endif + read_pg_if_n(mdb, col, &cur_pos, fmt->tab_col_entry_size); + pcol = (MdbColumn *) g_malloc0(sizeof(MdbColumn)); + + pcol->col_type = col[0]; + + + pcol->col_num = col[fmt->col_num_offset]; + + + + pcol->var_col_num = mdb_get_int16(col, fmt->tab_col_offset_var); + + + + pcol->row_col_num = mdb_get_int16(col, fmt->tab_row_col_num_offset); + + + /* 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; + + + pcol->fixed_offset = mdb_get_int16(col, fmt->tab_col_offset_fixed); + + + + if (pcol->col_type != MDB_BOOL) { + + pcol->col_size = mdb_get_int16(col, fmt->col_size_offset); + } else { + pcol->col_size=0; + } + + g_ptr_array_add(table->columns, pcol); + } + + g_free (col); + + /* + ** column names - ordered the same as the column attributes table + */ + for (i=0;i<table->num_cols;i++) { + 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)) { + name_sz = read_pg_if_8(mdb, &cur_pos); + } else { + fprintf(stderr,"Unknown MDB version\n"); + continue; + } + 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); + + table->index_start = cur_pos; + return table->columns; +} + +#if !MDB_NO_BACKENDS +void mdb_table_dump(MdbCatalogEntry *entry) +{ +MdbTableDef *table; +MdbColumn *col; +int coln; +MdbIndex *idx; +MdbHandle *mdb = entry->mdb; +unsigned int i, bitn; +guint32 pgnum; + + table = mdb_read_table(entry); + fprintf(stdout,"definition page = %lu\n",entry->table_pg); + fprintf(stdout,"number of datarows = %d\n",table->num_rows); + fprintf(stdout,"number of columns = %d\n",table->num_cols); + fprintf(stdout,"number of indices = %d\n",table->num_real_idxs); + + mdb_read_columns(table); + mdb_read_indices(table); + + for (i=0;i<table->num_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), + col->col_size); + } + + for (i=0;i<table->num_idxs;i++) { + idx = g_ptr_array_index (table->indices, i); + mdb_index_dump(table, idx); + } + if (table->usage_map) { + printf("pages reserved by this object\n"); + printf("usage map pg %" G_GUINT32_FORMAT "\n", + table->map_base_pg); + printf("free map pg %" G_GUINT32_FORMAT "\n", + table->freemap_base_pg); + pgnum = mdb_get_int32(table->usage_map,1); + /* the first 5 bytes of the usage map mean something */ + coln = 0; + for (i=5;i<table->map_sz;i++) { + for (bitn=0;bitn<8;bitn++) { + if (table->usage_map[i] & 1 << bitn) { + coln++; + printf("%6" G_GUINT32_FORMAT, pgnum); + if (coln==10) { + printf("\n"); + coln = 0; + } else { + printf(" "); + } + } + pgnum++; + } + } + printf("\n"); + } +} +#endif + +int mdb_is_user_table(MdbCatalogEntry *entry) +{ + return ((entry->object_type == MDB_TABLE) + && !(entry->flags & 0x80000002)) ? 1 : 0; +} +int mdb_is_system_table(MdbCatalogEntry *entry) +{ + return ((entry->object_type == MDB_TABLE) + && (entry->flags & 0x80000002)) ? 1 : 0; +} |