int mdb_find_end_of_row(MdbHandle *mdb, int row) { int rco = mdb->fmt->row_count_offset; int row_end; #if 1 if (row > 1000) return -1; row_end = (row == 0) ? mdb->fmt->pg_size : mdb_get_int16(mdb->pg_buf, rco + row*2) & OFFSET_MASK; #else /* Search the previous "row start" values for the first non-'lookupflag' * one. If we don't find one, then the end of the page is the correct * value. */ int i, row_start; 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; } } row_end = (i == 0) ? mdb->fmt->pg_size : row_start & OFFSET_MASK; #endif return row_end - 1; }
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; }
int mdb_find_row(MdbHandle *mdb, int row, int *start, size_t *len) { int rco = mdb->fmt->row_count_offset; int next_start; if (row > 1000) return -1; *start = mdb_get_int16(mdb->pg_buf, rco + 2 + row*2); next_start = (row == 0) ? mdb->fmt->pg_size : mdb_get_int16(mdb->pg_buf, rco + row*2) & OFFSET_MASK; *len = next_start - (*start & OFFSET_MASK); return 0; }
MdbTableDef *mdb_read_table(MdbCatalogEntry *entry) { MdbTableDef *table; MdbHandle *mdb = entry->mdb; MdbFormatConstants *fmt = mdb->fmt; 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); 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); 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(buf + row_start, table->map_sz); if (mdb_get_option(MDB_DEBUG_USAGE)) 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); /* 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(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); if (entry->props) for (i=0; i<entry->props->len; ++i) { MdbProperties *props = g_array_index(entry->props, MdbProperties*, i); if (!props->name) table->props = props; } return table; }
int mdb_test_sarg(MdbHandle *mdb, MdbColumn *col, MdbSargNode *node, MdbField *field) { char tmpbuf[256]; if (node->op == MDB_ISNULL) return field->is_null?1:0; else if (node->op == MDB_NOTNULL) return field->is_null?0:1; switch (col->col_type) { case MDB_BOOL: return mdb_test_int(node, !field->is_null); break; case MDB_BYTE: return mdb_test_int(node, (gint32)((char *)field->value)[0]); break; case MDB_INT: return mdb_test_int(node, (gint32)mdb_get_int16(field->value, 0)); break; case MDB_LONGINT: return mdb_test_int(node, (gint32)mdb_get_int32(field->value, 0)); break; 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; } return 1; }
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; }
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); }
/* * That function takes a raw KKD/MR2 binary buffer, * typically read from LvProp in table MSysbjects * and returns a GPtrArray 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; }
int mdb_pg_get_int16(MdbHandle *mdb, int offset) { if (offset < 0 || offset+2 > mdb->fmt->pg_size) return -1; mdb->cur_pos+=2; return mdb_get_int16(mdb->pg_buf, offset); }
GPtrArray *mdb_read_columns(MdbTableDef *table) { MdbHandle *mdb = table->entry->mdb; MdbFormatConstants *fmt = mdb->fmt; MdbColumn *pcol; unsigned char *col; unsigned int i, j; 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); 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]; } // 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; } 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_JET3(mdb)) name_sz = read_pg_if_8(mdb, &cur_pos); 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); GArray *allprops = table->entry->props; if (allprops) for (i=0;i<table->num_cols;i++) { pcol = g_ptr_array_index(table->columns, i); for (j=0; j<allprops->len; ++j) { MdbProperties *props = g_array_index(allprops, MdbProperties*, j); if (props->name && pcol->name && !strcmp(props->name, pcol->name)) { pcol->props = props; break; } } } table->index_start = cur_pos; return table->columns; }
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; }
int mdb_fetch_row(MdbTableDef *table) { MdbHandle *mdb = table->entry->mdb; MdbFormatConstants *fmt = mdb->fmt; unsigned int rows; int rc; guint32 pg; if (table->num_rows==0) return 0; /* initialize */ if (!table->cur_pg_num) { table->cur_pg_num=1; table->cur_row=0; if ((!table->is_temp_table)&&(table->strategy!=MDB_INDEX_SCAN)) if (!mdb_read_next_dpg(table)) return 0; } do { if (table->is_temp_table) { GPtrArray *pages = table->temp_table_pages; rows = mdb_get_int16( g_ptr_array_index(pages, table->cur_pg_num-1), fmt->row_count_offset); if (table->cur_row >= rows) { table->cur_row = 0; table->cur_pg_num++; if (table->cur_pg_num > pages->len) return 0; } memcpy(mdb->pg_buf, g_ptr_array_index(pages, table->cur_pg_num-1), fmt->pg_size); } else if (table->strategy==MDB_INDEX_SCAN) { if (!mdb_index_find_next(table->mdbidx, table->scan_idx, table->chain, &pg, (guint16 *) &(table->cur_row))) { mdb_index_scan_free(table); return 0; } mdb_read_pg(mdb, pg); } else { rows = mdb_get_int16(mdb->pg_buf,fmt->row_count_offset); /* if at end of page, find a new page */ if (table->cur_row >= rows) { table->cur_row=0; if (!mdb_read_next_dpg(table)) { return 0; } } } /* printf("page %d row %d\n",table->cur_phys_pg, table->cur_row); */ rc = mdb_read_row(table, table->cur_row); table->cur_row++; } while (!rc); return 1; }
GPtrArray * mdb_read_indices(MdbTableDef *table) { MdbCatalogEntry *entry = table->entry; MdbHandle *mdb = entry->mdb; MdbFormatConstants *fmt = mdb->fmt; MdbIndex *pidx; unsigned int i, j; int idx_num, key_num, col_num; int cur_pos, name_sz, idx2_sz, type_offset; int index_start_pg = mdb->cur_pg; guchar *tmpbuf; 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 { cur_pos = table->index_start + 39 * table->num_real_idxs; idx2_sz = 20; type_offset = 19; } tmpbuf = (guchar *) g_malloc(idx2_sz); for (i=0;i<table->num_idxs;i++) { read_pg_if_n(mdb, tmpbuf, &cur_pos, idx2_sz); 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]; g_ptr_array_add(table->indices, pidx); } g_free(tmpbuf); for (i=0;i<table->num_idxs;i++) { pidx = g_ptr_array_index (table->indices, i); if (IS_JET4(mdb)) { name_sz=read_pg_if_16(mdb, &cur_pos); cur_pos += 2; tmpbuf = g_malloc(name_sz); read_pg_if_n(mdb, tmpbuf, &cur_pos, name_sz); cur_pos += name_sz; mdb_unicode2ascii(mdb, tmpbuf, 0, name_sz, pidx->name); g_free(tmpbuf); } else { read_pg_if(mdb, &cur_pos, 0); name_sz=mdb->pg_buf[cur_pos++]; read_pg_if_n(mdb, (unsigned char *) pidx->name, &cur_pos, name_sz); cur_pos += name_sz; pidx->name[name_sz]='\0'; } //fprintf(stderr, "index name %s\n", pidx->name); } mdb_read_alt_pg(mdb, entry->table_pg); mdb_read_pg(mdb, index_start_pg); cur_pos = table->index_start; idx_num=0; for (i=0;i<table->num_real_idxs;i++) { if (IS_JET4(mdb)) cur_pos += 4; do { pidx = g_ptr_array_index (table->indices, idx_num++); } while (pidx && 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 (!pidx) { table->num_real_idxs--; continue; } pidx->num_rows = mdb_get_int32(mdb->alt_pg_buf, fmt->tab_cols_start_offset + (i*fmt->tab_ridx_entry_size)); key_num=0; for (j=0;j<MDB_MAX_IDX_COLS;j++) { col_num=read_pg_if_16(mdb,&cur_pos); cur_pos += 2; read_pg_if(mdb, &cur_pos, 0); cur_pos++; if (col_num == 0xFFFF) continue; /* set column number to a 1 based column number and store */ pidx->key_col_num[key_num] = col_num + 1; pidx->key_col_order[key_num] = (mdb->pg_buf[cur_pos-1]) ? MDB_ASC : MDB_DESC; key_num++; } pidx->num_keys = key_num; cur_pos += 4; pidx->first_pg = read_pg_if_32(mdb, &cur_pos); cur_pos += 4; read_pg_if(mdb, &cur_pos, 0); pidx->flags = mdb->pg_buf[cur_pos++]; if (IS_JET4(mdb)) cur_pos += 9; } return NULL; }