From f016c9cc88fcd917137e7c3af87403cc4b448973 Mon Sep 17 00:00:00 2001 From: brianb Date: Fri, 5 Mar 2004 05:06:26 +0000 Subject: [PATCH] patch from Jeff Smith for mdb_pack_row4() and null mask fix --- ChangeLog | 5 + include/mdbtools.h | 1 + src/libmdb/write.c | 243 +++++++++++++++++++++++++++++---------------- src/sql/mdbsql.c | 62 +++++++++--- 4 files changed, 212 insertions(+), 99 deletions(-) diff --git a/ChangeLog b/ChangeLog index 240fe01..7680675 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Thu Mar 4 23:24:27 EST 2004 Brian Bruns + * include/mdbtools.h: add prototype for mdb_index_find_next() + * src/libmdb/write.c: add mdb_pack_row4() (Jeff Smith). Fix null mask order (Jeff, me) + * src/sql/mdbsql.c: convert list tables/describe table to ucs2 for jet4 db's + Thu Mar 4 15:30:21 EST 2004 Brian Bruns * src/odbc/Makefile.am: add newer files to driver * src/libmdb/options.c: add debug_row option diff --git a/include/mdbtools.h b/include/mdbtools.h index 6071a79..8947b21 100644 --- a/include/mdbtools.h +++ b/include/mdbtools.h @@ -469,6 +469,7 @@ extern int mdb_index_find_next_on_page(MdbHandle *mdb, MdbIndexPage *ipg); extern int mdb_index_find_next(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 *pg, guint16 *row); extern void mdb_index_hash_text(guchar *text, guchar *hash); extern void mdb_index_scan_init(MdbHandle *mdb, MdbTableDef *table); +extern int mdb_index_find_row(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 pg, guint16 row); /* stats.c */ extern void mdb_stats_on(MdbHandle *mdb); diff --git a/src/libmdb/write.c b/src/libmdb/write.c index 6d545c1..004a744 100644 --- a/src/libmdb/write.c +++ b/src/libmdb/write.c @@ -26,6 +26,8 @@ #endif +static int mdb_copy_index_pg(MdbTableDef *table, MdbIndexPage *ipg); + void _mdb_put_int16(unsigned char *buf, guint32 offset, guint32 value) { @@ -84,14 +86,14 @@ MdbIndex *idx; } return 0; } -int +static int mdb_crack_row4(MdbTableDef *table, int row_start, int row_end, MdbField *fields) { MdbCatalogEntry *entry = table->entry; MdbHandle *mdb = entry->mdb; MdbColumn *col; - int i, j; - int var_cols = 0, fixed_cols = 0, num_cols, totcols = 0; + int i; + int var_cols = 0, fixed_cols = 0, num_cols; int var_cols_found, fixed_cols_found, var_entry_pos; int col_start, next_col; unsigned char *nullmask; @@ -126,17 +128,17 @@ mdb_crack_row4(MdbTableDef *table, int row_start, int row_end, MdbField *fields) col = g_ptr_array_index (table->columns, i); if (mdb_is_fixed_col(col)) { fixed_cols++; - fields[totcols].colnum = i; - fields[totcols].siz = col->col_size; - fields[totcols++].is_fixed = 1; + fields[i].colnum = i; + fields[i].siz = col->col_size; + fields[i].is_fixed = 1; } } for (i = 0; i < table->num_cols; i++) { col = g_ptr_array_index (table->columns, i); if (!mdb_is_fixed_col(col)) { var_cols++; - fields[totcols].colnum = i; - fields[totcols++].is_fixed = 0; + fields[i].colnum = i; + fields[i].is_fixed = 0; } } @@ -149,13 +151,12 @@ mdb_crack_row4(MdbTableDef *table, int row_start, int row_end, MdbField *fields) fixed_cols_found = 0; var_cols_found = 0; - totcols = 0; - for (j=0;jnum_cols;j++) { - col = g_ptr_array_index(table->columns,j); + for (i=0;inum_cols;i++) { + col = g_ptr_array_index(table->columns,i); if (mdb_is_fixed_col(col) && fixed_cols_found <= fixed_cols) { real_offset += col->col_size; - fields[totcols].start = row_start + col->fixed_offset + 2; - fields[totcols++].value = &mdb->pg_buf[row_start + col->fixed_offset + 2]; + fields[i].start = row_start + col->fixed_offset + 2; + fields[i].value = &mdb->pg_buf[row_start + col->fixed_offset + 2]; fixed_cols_found++; } } @@ -175,8 +176,8 @@ mdb_crack_row4(MdbTableDef *table, int row_start, int row_end, MdbField *fields) col_start = mdb_pg_get_int16(mdb, row_end - 3 - bitmask_sz); - for (j=0;jnum_cols;j++) { - col = g_ptr_array_index(table->columns,j); + for (i=0;inum_cols;i++) { + col = g_ptr_array_index(table->columns,i); if (!mdb_is_fixed_col(col) && ++var_cols_found <= var_cols) { if (var_cols_found==var_cols) { len=eod - col_start; @@ -191,10 +192,9 @@ mdb_crack_row4(MdbTableDef *table, int row_start, int row_end, MdbField *fields) next_col = mdb_pg_get_int16(mdb, var_entry_pos); len = next_col - col_start; } /* if found==var_cols */ - while (len<0) len+=256; - fields[totcols].start = row_start + col_start; - fields[totcols].value = &mdb->pg_buf[row_start +col_start]; - fields[totcols++].siz = len; + fields[i].start = row_start + col_start; + fields[i].value = &mdb->pg_buf[row_start +col_start]; + fields[i].siz = len; col_start += len; } /* if !fixed */ } /* for */ @@ -205,32 +205,52 @@ mdb_crack_row4(MdbTableDef *table, int row_start, int row_end, MdbField *fields) static int mdb_crack_row3(MdbTableDef *table, int row_start, int row_end, MdbField *fields) { -MdbCatalogEntry *entry = table->entry; -MdbHandle *mdb = entry->mdb; -MdbColumn *col; -int i, j; -int var_cols = 0, fixed_cols = 0, num_cols, totcols = 0; -int var_cols_found, fixed_cols_found, var_entry_pos; -int col_start; -unsigned char *nullmask; -int bitmask_sz; -int byte_num, bit_num; -int num_of_jumps = 0, jumps_used = 0; -int eod, len; /* end of data */ + MdbCatalogEntry *entry = table->entry; + MdbHandle *mdb = entry->mdb; + MdbColumn *col; + int i; + int var_cols = 0, fixed_cols = 0, num_cols; + int var_cols_found, fixed_cols_found, var_entry_pos; + int col_start; + unsigned char *nullmask; + int bitmask_sz; + int byte_num, bit_num; + int num_of_jumps = 0, jumps_used = 0; + int eod, len; /* end of data */ + int row_pos; + + if (mdb_get_option(MDB_DEBUG_ROW)) { + buffer_dump(mdb->pg_buf, row_start, row_end+1); + } num_cols = mdb->pg_buf[row_start]; + if (num_cols != table->num_cols) { fprintf(stderr,"WARNING: number of table columns does not match number of row columns, strange results may occur\n"); } + /* compute nulls first to help with fixed colnum's */ + bitmask_sz = (num_cols - 1) / 8 + 1; + nullmask = &mdb->pg_buf[row_end - bitmask_sz + 1]; + + for (i=0;inum_cols;i++) { + col = g_ptr_array_index (table->columns, i); + row_pos = col->row_col_num; + byte_num = row_pos / 8; + bit_num = row_pos % 8; + /* logic on nulls is reverse, 1 is not null, 0 is null */ + fields[i].is_null = nullmask[byte_num] & 1 << bit_num ? 0 : 1; + //printf("col %d is %s\n", i, fields[i].is_null ? "null" : "not null"); + } + /* how many fixed cols? */ for (i = 0; i < table->num_cols; i++) { col = g_ptr_array_index (table->columns, i); if (mdb_is_fixed_col(col)) { fixed_cols++; - fields[totcols].colnum = i; - fields[totcols].siz = col->col_size; - fields[totcols++].is_fixed = 1; + fields[i].colnum = i; + fields[i].siz = col->col_size; + fields[i].is_fixed = 1; } } /* how many var cols? */ @@ -238,22 +258,11 @@ int eod, len; /* end of data */ col = g_ptr_array_index (table->columns, i); if (!mdb_is_fixed_col(col)) { var_cols++; - fields[totcols].colnum = i; - fields[totcols++].is_fixed = 0; + fields[i].colnum = i; + fields[i].is_fixed = 0; } } - bitmask_sz = (num_cols - 1) / 8 + 1; - nullmask = &mdb->pg_buf[row_end - bitmask_sz + 1]; - - for (i=0;ipg_buf[row_end-1-var_cols-bitmask_sz]; @@ -264,13 +273,12 @@ int eod, len; /* end of data */ fixed_cols_found = 0; var_cols_found = 0; - totcols = 0; /* loop through fixed columns and add values to fields[] */ - for (j=0;jnum_cols;j++) { - col = g_ptr_array_index(table->columns,j); + for (i=0;inum_cols;i++) { + col = g_ptr_array_index(table->columns,i); if (mdb_is_fixed_col(col) && ++fixed_cols_found <= fixed_cols) { - fields[totcols].start = row_start + col_start; - fields[totcols++].value = &mdb->pg_buf[row_start + col_start]; + fields[i].start = row_start + col_start; + fields[i].value = &mdb->pg_buf[row_start + col_start]; if (col->col_type != MDB_BOOL) col_start += col->col_size; } @@ -298,8 +306,8 @@ int eod, len; /* end of data */ /* col_start is now the offset to the first variable length field */ col_start = mdb->pg_buf[col_ptr]; - for (j=0;jnum_cols;j++) { - col = g_ptr_array_index(table->columns,j); + for (i=0;inum_cols;i++) { + col = g_ptr_array_index(table->columns,i); /* if it's a var_col and we aren't looking at a column * added after this row was created */ if (!mdb_is_fixed_col(col) && ++var_cols_found <= var_cols) { @@ -327,9 +335,9 @@ int eod, len; /* end of data */ len=mdb->pg_buf[var_entry_pos] - mdb->pg_buf[var_entry_pos+1]; } /* if found==var_cols */ while (len<0) len+=256; - fields[totcols].start = row_start + col_start; - fields[totcols].value = &mdb->pg_buf[row_start +col_start]; - fields[totcols++].siz = len; + fields[i].start = row_start + col_start; + fields[i].value = &mdb->pg_buf[row_start +col_start]; + fields[i].siz = len; col_start += len; } /* if !fixed */ } /* for */ @@ -349,17 +357,45 @@ MdbHandle *mdb = entry->mdb; return mdb_crack_row3(table, row_start, row_end, fields); } } + +static int +mdb_pack_null_mask(unsigned char *buffer, int num_fields, MdbField *fields) +{ + int pos = 0, bit = 0, byte = 0; + int i; + + /* 'Not null' bitmap */ + for (i=0; i> 8) & 0xff; + + /* Fixed length columns */ for (i=0;i> 8) & 0xff; + pos += 2; + /* Offsets of the variable-length columns */ + for (i=num_fields; i>num_fields-var_cols; i--) { + row_buffer[pos++] = fields[i-1].offset & 0xff; + row_buffer[pos++] = (fields[i-1].offset >> 8) & 0xff; + } + /* Number of variable-length columns */ + row_buffer[pos++] = var_cols & 0xff; + row_buffer[pos++] = (var_cols >> 8) & 0xff; + + pos += mdb_pack_null_mask(&row_buffer[pos], num_fields, fields); + + return pos; +} + +static int +mdb_pack_row3(MdbTableDef *table, unsigned char *row_buffer, int num_fields, MdbField *fields) +{ + unsigned int pos = 0; + unsigned int var_cols = 0; + int i; + + row_buffer[pos++] = num_fields; + + /* Fixed length columns */ + for (i=0;i=num_fields - var_cols;i--) { + for (i=num_fields-1;i>=(int)(num_fields - var_cols);i--) { row_buffer[pos++] = fields[i].offset % 256; } row_buffer[pos++] = var_cols; - byte = 0; - bit = 0; - for (i=0;ientry->mdb)) { + return mdb_pack_row4(table, row_buffer, num_fields, fields); + } else { + return mdb_pack_row3(table, row_buffer, num_fields, fields); + } +} +int mdb_pg_get_freespace(MdbHandle *mdb) { MdbFormatConstants *fmt = mdb->fmt; @@ -526,7 +598,6 @@ mdb_insert_row(MdbTableDef *table, int num_fields, MdbField *fields) MdbFormatConstants *fmt = mdb->fmt; guint32 pgnum; guint16 rownum; - unsigned char *new_pg; if (!mdb->f->writable) { fprintf(stderr, "File is not open for writing\n"); @@ -732,7 +803,7 @@ int i, pos; } return 0; } -int +static int mdb_copy_index_pg(MdbTableDef *table, MdbIndexPage *ipg) { MdbCatalogEntry *entry = table->entry; diff --git a/src/sql/mdbsql.c b/src/sql/mdbsql.c index e799fff..82b65e6 100644 --- a/src/sql/mdbsql.c +++ b/src/sql/mdbsql.c @@ -527,6 +527,27 @@ int vlen; } fprintf(stdout,"|"); } +static gchar * +convert_to_ucs2(MdbHandle *mdb, gchar *text) +{ + gchar *tmpstr; + int i; + + tmpstr = (gchar *) g_malloc((strlen(text)+1)*2); + if (IS_JET4(mdb)) { + /* sloppily convert to UCS2-LE */ + for (i=0;iobject_type == MDB_TABLE) { if (strncmp (entry->object_name, "MSys", 4)) { //col = g_ptr_array_index(table->columns,0); - fields[0].value = entry->object_name; - fields[0].siz = strlen(entry->object_name); + tmpstr = convert_to_ucs2(mdb, entry->object_name); + tmpsiz = IS_JET4(mdb) ? strlen(entry->object_name)*2 : strlen(entry->object_name); + fields[0].value = tmpstr; + fields[0].siz = tmpsiz; fields[0].is_fixed = 0; fields[0].is_null = 0; fields[0].start = 0; @@ -580,6 +605,7 @@ void mdb_sql_listtables(MdbSQL *sql) row_size = mdb_pack_row(ttable, row_buffer, 1, fields); mdb_add_row_to_pg(ttable,row_buffer, row_size); ttable->num_rows++; + g_free(tmpstr); } } } @@ -596,12 +622,13 @@ void mdb_sql_describe_table(MdbSQL *sql) MdbColumn *col, tcol; MdbSQLColumn *sqlcol; int i; - char colsize[11]; MdbField fields[4]; char tmpstr[256]; unsigned char row_buffer[4096]; unsigned char *new_pg; int row_size; + gchar *col_name, *col_type, *col_size; + int tmpsiz; if (!mdb) { mdb_sql_error("You must connect to a database first"); @@ -668,25 +695,31 @@ void mdb_sql_describe_table(MdbSQL *sql) for (i=0;inum_cols;i++) { - col = g_ptr_array_index(table->columns,i); - fields[0].value = col->name; - fields[0].siz = strlen(col->name); + col = g_ptr_array_index(table->columns,i); + col_name = convert_to_ucs2(mdb, col->name); + tmpsiz = IS_JET4(mdb) ? strlen(col->name)*2 : strlen(col->name); + fields[0].value = col_name; + fields[0].siz = tmpsiz; fields[0].is_fixed = 0; fields[0].is_null = 0; fields[0].start = 0; fields[0].colnum = 0; strcpy(tmpstr, mdb_get_coltype_string(mdb->default_backend, col->col_type)); - fields[1].value = tmpstr; - fields[1].siz = strlen(tmpstr); + col_type = convert_to_ucs2(mdb, tmpstr); + tmpsiz = IS_JET4(mdb) ? strlen(tmpstr)*2 : strlen(tmpstr); + fields[1].value = col_type; + fields[1].siz = tmpsiz; fields[1].is_fixed = 0; fields[1].is_null = 0; fields[1].start = 0; fields[1].colnum = 1; - sprintf(colsize,"%d",col->col_size); - fields[2].value = colsize; - fields[2].siz = strlen(colsize); + sprintf(tmpstr,"%d",col->col_size); + col_size = convert_to_ucs2(mdb, tmpstr); + tmpsiz = IS_JET4(mdb) ? strlen(tmpstr)*2 : strlen(tmpstr); + fields[2].value = col_size; + fields[2].siz = tmpsiz; fields[2].is_fixed = 0; fields[2].is_null = 0; fields[2].start = 0; @@ -694,6 +727,9 @@ void mdb_sql_describe_table(MdbSQL *sql) row_size = mdb_pack_row(ttable, row_buffer, 3, fields); mdb_add_row_to_pg(ttable,row_buffer, row_size); + g_free(col_name); + g_free(col_type); + g_free(col_size); ttable->num_rows++; }