From a74094c667aeb871659cb32826db0b10ca695386 Mon Sep 17 00:00:00 2001 From: brianb Date: Fri, 6 Feb 2004 02:34:20 +0000 Subject: [PATCH] sync up, see ChangeLog for details --- ChangeLog | 15 ++- HACKING | 78 ++++++++++++-- INSTALL | 2 +- README | 6 +- configure.in | 2 +- include/mdbtools.h | 4 +- src/libmdb/backend.c | 20 ++++ src/libmdb/data.c | 8 +- src/libmdb/index.c | 112 +++++++++++++++++--- src/libmdb/sargs.c | 17 ++- src/libmdb/table.c | 2 +- src/libmdb/write.c | 214 +++++++++++++++++++++++++++++-------- src/sql/lexer.c | 245 ++++++++++++++++++++++--------------------- src/sql/lexer.l | 1 + src/sql/parser.y | 13 ++- 15 files changed, 539 insertions(+), 200 deletions(-) diff --git a/ChangeLog b/ChangeLog index f54ef15..5ab82ab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,19 @@ -Sat Jan 10 17:18:00 EST 2004 Brian Bruns +Thu Feb 5 20:45:00 EST 2004 Brian Bruns + + * HACKING: added information on indexes + * src/sql/lexer.l: + * src/sql/parser.y: added is null/is not null, not working yet + * src/util/mdb-sql.c: fix readline support, added history file + * src/util/mdb-export.c: update usage for -D flag + * src/libmdb/backend.c: added mysql struct (not complete) + * src/libmdb/sargs.c: fix casts + * src/libmdb/write.c: break apart mdb_crack_row new index func + +Sat Jan 10 17:18:00 EST 2004 Brian Bruns * src/util/mdb-parse.c: fixed char comparison to -1 re: bug 688181 -Fri Jan 9 15:22:11 EST 2004 Brian Bruns +Fri Jan 9 15:22:11 EST 2004 Brian Bruns * include/mdbtools.h: * src/libmdb/index.c: diff --git a/HACKING b/HACKING index 0449a30..c9cd7c5 100644 --- a/HACKING +++ b/HACKING @@ -472,19 +472,75 @@ Indices are not completely understood but here is what we know. | ???? | 4 bytes | leaf_page | Pointer to leaf page, purpose unknown | +-------------------------------------------------------------------------+ -On the page pointed to by the table definition a series of records start at -byte offset 0xf8. +Index pages come in two flavors. -If the page is an index page (type 0x03) then the value of each key column is -stored (for integers it seems to be in msb-lsb order to help comparison) preceded -by a flag field and followed by the data pointer to the index entries record, this -is then followed by a pointer to a leaf index page. +0x04 pages are leaf pages which contain one entry for each row in the table. +Each entry is composed of a flag, the indexed column values and a page/row +pointer to the data. -The flag field is generally either 0x00, 0x7f, 0x80. 0x80 is the one's complement -of 0x7f and all text data in the index would then need to be negated. The reason -for this negation is unknown, although I suspect it has to do with descending -order. The 0x00 flag indicates that the key column is null, and no data will follow, -only the page pointer. +0x03 index pages make up the rest of the index tree and contain a flag, the +indexed columns, the page/row contains this entry, and the leaf page or +intermediate (another 0x03 page) page pointer for which this is the first +entry on. + +Both index types have a bitmask starting at 0x16 which identifies the starting +location of each index entry on this page. The first entry is assumed and +the count starts from the low order bit. For example take the data: + +00 20 00 04 80 00 ... + +This first entry starts at 0xf8 (always). Convert the bytes to binary starting with the low order bit and stopping at the first "on" bit: + +0000 0000 0000 01 +-- 00 --- -- 20 --> +This next entry starts 14 (0xe) bytes in at 0x105. Proceding from here, the next +entry: + + 00 0000 0000 001 +<-- 20 -- -- 00 --- -- 04 + +starts 13 (0xd) bytes further in at 0x112. The final entry starts at + + 0 0000 0000 0001 +<-- 04 -- -- 80 --- + +or 13 (0xd) bytes more at 0x120. In this example the rest of the mask (up to offset 0xf8) would be zero filled and thus this last entry at 0x120 isn't an actual entry but the stopping point of the data. + +Since 0xf8 = 248 and 0x16 = 22, (248 - 22) * 8 = 1808 and 2048 - 1808 = 240 leaving just enough space for the bit mask to encode the remainder of the page. One wonders why MS didn't use a row offset table like they did on data pages, +seems like it would have been easier and more flexible. + +So now we come to the index entries for type 0x03 pages which look like this: + ++------+---------+-------------+------------------------------------------+ +| data | length | name | description | ++------+---------+-------------+------------------------------------------+ +| 0x7f | 1 byte | flags | 0x80 LSB, 0x7f MSB, 0x00 null? | +| ???? | variable| indexed cols| indexed column data | +| ???? | 3 bytes | data page | page containing row referred to by this | +| | | | index entry | +| ???? | 1 byte | data row | row number on that page of this entry | +| ???? | 4 bytes | child page | next level index page containing this | +| | | | entry as first entry. Could be a leaf | +| | | | node. | ++-------------------------------------------------------------------------+ + +The flag field is generally either 0x00, 0x7f, 0x80. 0x80 is the one's +complement of 0x7f and all text data in the index would then need to be negated. +The reason for this negation is unknown, although I suspect it has to do with +descending order. The 0x00 flag indicates that the key column is null, and no +data will follow, only the page pointer. In multicolumn indexes the flag field plus data is repeated for the number of columns participating in the key. + +Update: There is a compression scheme utilized on leaf pages as follows: +Normally an index entry with an integer primary key would be 9 bytes (1 for the flags field, 4 for the integer, 3 for page, and 1 for row). The entry can be shorter than 9, containing only 5 bytes, the first byte is the last octet of the +encoded primary key field (integer) and the last four are the page/row pointer. +Thus if the first key value on the page is 1 and it points to page 261 (00 01 05 +) row 3, it becomes +7f 00 00 00 01 00 01 05 03 + +the next index entry can be: +02 00 01 05 04 + +that is, the key value is 2 (the last octet changes to 02) page 261 row 4. Access stores an 'alphabetic sort order' version of the text key columns in the index. Basically this means that upper and lower case characters A-Z are merged and start at 0x60. Digits are 0x56 through 0x5f. Once converted into this (non-ascii) character set, the text value is able to be sorted in 'alphabetic' diff --git a/INSTALL b/INSTALL index ab1fc5e..8b2f181 100644 --- a/INSTALL +++ b/INSTALL @@ -22,7 +22,7 @@ mdb-header -- generates a C header to be used in exporting mdb data to a C prog. mdb-parsecvs -- generates a C program given a CSV file made with mdb-export mdb-sql -- if --enable-sql is specified, a simple SQL engine (also used by ODBC and gmdb). -gmdb -- a graphical utility to browse MDB files. +gmdb2 -- a graphical utility to browse MDB files. And some utilities useful for debugging: diff --git a/README b/README index e34d733..3d44024 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is mdbtools version 0.4 +This is mdbtools version 0.6pre1 Welcome to the exciting world of MDB Tools! In short, MDB Tools is a set of program to help you use Microsoft Access file in various settings. The major @@ -12,7 +12,7 @@ pieces are: get results. . odbc - An ODBC driver for use with unixODBC driver manager. Allows one to use MDB files with PHP for example. -. gmdb - The GTK MDB File Viewer and debugger. Still alpha, but making +. gmdb2 - The Gnome MDB File Viewer and debugger. Still alpha, but making great progress. If you are interested in helping, read the HACKING file for a description of @@ -30,5 +30,5 @@ To install see the INSTALL file Check out http://mdbtools.sourceforge.net for CVS, mailing list and similar. Brian Bruns -camber@ais.org +brian@bruns.com diff --git a/configure.in b/configure.in index 40f2621..2b38c7c 100644 --- a/configure.in +++ b/configure.in @@ -127,4 +127,4 @@ AC_SUBST(READLINE_LIBS) localedir=${datadir}/locale AC_SUBST(localedir) -AC_OUTPUT(src/util/Makefile src/extras/Makefile Makefile include/Makefile src/libmdb/Makefile include/Makefile src/sql/Makefile src/odbc/Makefile doc/Makefile src/gmdb2/Makefile src/gmdb2/gladefiles/Makefile src/gmdb2/pixmaps/Makefile src/gmdb2/help/Makefile src/gmdb2/help/C/Makefile mdbtools.spec) +AC_OUTPUT(src/util/Makefile src/extras/Makefile Makefile include/Makefile src/libmdb/Makefile src/sql/Makefile src/odbc/Makefile doc/Makefile src/gmdb2/Makefile src/gmdb2/gladefiles/Makefile src/gmdb2/pixmaps/Makefile src/gmdb2/help/Makefile src/gmdb2/help/C/Makefile mdbtools.spec) diff --git a/include/mdbtools.h b/include/mdbtools.h index 1a859e0..d94a1ef 100644 --- a/include/mdbtools.h +++ b/include/mdbtools.h @@ -457,10 +457,10 @@ extern int mdb_like_cmp(char *s, char *r); /* write.c */ 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, int num_fields, MdbField *fields, guint32 pgnum, guint16 rownum); extern int mdb_pack_row(MdbTableDef *table, unsigned char *row_buffer, int num_fields, MdbField *fields); -extern void mdb_add_row_to_pg(MdbTableDef *table, unsigned char *row_buffer, int new_row_size); extern int mdb_replace_row(MdbTableDef *table, int row, unsigned char *new_row, int new_row_size); -extern int mdb_update_index(MdbTableDef *table, MdbIndex *idx, int num_fields, MdbField *fields); extern int mdb_pg_get_freespace(MdbHandle *mdb); extern int mdb_update_row(MdbTableDef *table); extern unsigned char *mdb_new_data_pg(MdbCatalogEntry *entry); diff --git a/src/libmdb/backend.c b/src/libmdb/backend.c index 335960f..c08e02d 100644 --- a/src/libmdb/backend.c +++ b/src/libmdb/backend.c @@ -110,6 +110,26 @@ MdbBackendType mdb_postgres_types[] = { {"Serial",0,0,0}, {"Postgres_Unknown 0x10",0,0,0}, }; +/* MySQL data types */ +MdbBackendType mdb_mysql_types[] = { + {"Mysql_Unknown 0x00",0,0,0}, + {"bit",0,0,0}, + {"char",1,0,1}, + {"smallint",0,0,0}, + {"int",0,0,0}, + {"money",0,0,0}, + {"real",0,0,0}, + {"float",0,0,0}, + {"smalldatetime",0,0,0}, + {"Mysql_Unknown 0x09",0,0,0}, + {"varchar",1,0,1}, + {"varbinary",1,0,1}, + {"text",1,0,1}, + {"Mysql_Unknown 0x0d",0,0,0}, + {"Mysql_Unknown 0x0e",0,0,0}, + {"Mysql_Unknown 0x0f",0,0,0}, + {"numeric",1,1,0}, +}; char *bound_values[MDB_MAX_COLS]; char *relationships[4]; diff --git a/src/libmdb/data.c b/src/libmdb/data.c index c6a3b3f..db14951 100644 --- a/src/libmdb/data.c +++ b/src/libmdb/data.c @@ -897,17 +897,19 @@ guint16 len; } /* swap the alt and regular page buffers, so we can call get_int16 */ mdb_swap_pgbuf(mdb); + row_stop = 0; if (memo_row) { row_stop = mdb_pg_get_int16(mdb, fmt->row_count_offset + 2 + (memo_row - 1) * 2) & 0x0FFF; - } else { + } + if (row_stop == 0) row_stop = fmt->pg_size - 1; - } + row_start = mdb_pg_get_int16(mdb, fmt->row_count_offset + 2 + memo_row * 2); + len = row_stop - row_start; #if MDB_DEBUG printf("row num %d row start %d row stop %d\n", memo_row, row_start, row_stop); buffer_dump(mdb->pg_buf,row_start, row_start + len); #endif - len = row_stop - row_start; if (IS_JET3(mdb)) { strncpy(text, &mdb->pg_buf[row_start], len); text[len]='\0'; diff --git a/src/libmdb/index.c b/src/libmdb/index.c index 2dd92a2..3c353ac 100644 --- a/src/libmdb/index.c +++ b/src/libmdb/index.c @@ -262,6 +262,10 @@ mdb_index_test_sargs(MdbHandle *mdb, MdbIndex *idx, int offset, int len) MdbSargNode node; int c_offset = 0, 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); @@ -326,14 +330,18 @@ mdb_index_find_next_on_page(MdbHandle *mdb, MdbIndexPage *ipg) return ipg->len; } -void mdb_index_page_init(MdbIndexPage *ipg) +void mdb_index_page_reset(MdbIndexPage *ipg) { - memset(ipg, 0, sizeof(MdbIndexPage)); ipg->offset = 0xf8; /* start byte of the index entries */ ipg->mask_pos = 0x16; ipg->mask_bit=0; ipg->len = 0; } +void mdb_index_page_init(MdbIndexPage *ipg) +{ + memset(ipg, 0, sizeof(MdbIndexPage)); + mdb_index_page_reset(ipg); +} /* * find the next leaf page if any given a chain. Assumes any exhausted leaf * pages at the end of the chain have been peeled off before the call. @@ -361,8 +369,10 @@ mdb_find_next_leaf(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain) do { ipg->len = 0; //printf("finding next on pg %lu\n", ipg->pg); - if (!mdb_index_find_next_on_page(mdb, ipg)) + if (!mdb_index_find_next_on_page(mdb, ipg)) { + //printf("find_next_on_page returned 0\n"); return 0; + } pg = mdb_pg_get_int24_msb(mdb, ipg->offset + ipg->len - 3); //printf("Looking at pg %lu at %lu %d\n", pg, ipg->offset, ipg->len); ipg->offset += ipg->len; @@ -373,7 +383,7 @@ mdb_find_next_leaf(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain) */ newipg = mdb_chain_add_page(mdb, chain, pg); newipg = mdb_find_next_leaf(mdb, idx, chain); - //printf("returning pg %lu\n",newipg->pg); + printf("returning pg %lu\n",newipg->pg); return newipg; } while (!passed); /* no more pages */ @@ -396,6 +406,10 @@ mdb_chain_add_page(MdbHandle *mdb, MdbIndexChain *chain, guint32 pg) return ipg; } +/* + * returns the bottom page of the IndexChain, if IndexChain is empty it + * initializes it by reading idx->first_pg (the root page) + */ MdbIndexPage * mdb_index_read_bottom_pg(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain) { @@ -451,8 +465,65 @@ mdb_index_find_next(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 */ if (!mdb_index_find_next_on_page(mdb, ipg)) { //printf("page %lu finished\n",ipg->pg); + if (chain->cur_depth==1) { + //printf("cur_depth == 1 we're out\n"); + return 0; + } + /* + * unwind the stack until we find something or reach + * the top. + */ + ipg = 0; + while (chain->cur_depth>1 && ipg==0) { + //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) return 0; + } + *row = mdb->pg_buf[ipg->offset + ipg->len - 1]; + *pg = mdb_pg_get_int24_msb(mdb, ipg->offset + ipg->len - 4); + //printf("row = %d pg = %lu ipg->pg = %lu offset = %lu len = %d\n", *row, *pg, ipg->pg, ipg->offset, ipg->len); + + passed = mdb_index_test_sargs(mdb, idx, ipg->offset, ipg->len); + + ipg->offset += ipg->len; + } while (!passed); + + //fprintf(stdout,"len = %d pos %d\n", ipg->len, ipg->mask_pos); + //buffer_dump(mdb->pg_buf, ipg->offset, ipg->offset+ipg->len-1); + + return ipg->len; +} +/* + * XXX - FIX ME + * This function is grossly inefficient. It scans the entire index building + * an IndexChain to a specific row. We should be checking the index pages + * for matches against the indexed fields to find the proper leaf page, but + * getting it working first and then make it fast! + */ +int +mdb_index_find_row(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 pg, guint16 row) +{ + MdbIndexPage *ipg; + int passed = 0; + guint32 datapg; + guint16 datarow; + + ipg = mdb_index_read_bottom_pg(mdb, idx, chain); + + do { + ipg->len = 0; + /* + * if no more rows on this leaf, try to find a new leaf + */ + if (!mdb_index_find_next_on_page(mdb, ipg)) { + /* back to top? We're done */ + if (chain->cur_depth==1) + return 0; + /* * unwind the stack until we find something or reach * the top. @@ -466,19 +537,20 @@ mdb_index_find_next(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 if (chain->cur_depth==1) return 0; } - *row = mdb->pg_buf[ipg->offset + ipg->len - 1]; - *pg = mdb_pg_get_int24_msb(mdb, ipg->offset + ipg->len - 4); - - passed = mdb_index_test_sargs(mdb, idx, ipg->offset, ipg->len); + /* test row and pg */ + datarow = mdb->pg_buf[ipg->offset + ipg->len - 1]; + datapg = mdb_pg_get_int24_msb(mdb, ipg->offset + ipg->len - 4); + if (datapg == pg && datarow == row) { + passed = 1; + } ipg->offset += ipg->len; } while (!passed); - //fprintf(stdout,"len = %d pos %d\n", ipg->len, ipg->mask_pos); - //buffer_dump(mdb->pg_buf, ipg->offset, ipg->offset+ipg->len-1); - - return ipg->len; + /* index chain from root to leaf should now be in "chain" */ + return 1; } + void mdb_index_walk(MdbTableDef *table, MdbIndex *idx) { MdbHandle *mdb = table->entry->mdb; @@ -520,6 +592,14 @@ mdb_index_dump(MdbTableDef *table, MdbIndex *idx) } mdb_index_walk(table, idx); } +/* + * compute_cost tries to assign a cost to a given index using the sargs + * available in this query. + * + * Indexes with no matching sargs are assigned 0 + * Unique indexes are preferred over non-uniques + * Operator preference is equal, like, isnull, others + */ int mdb_index_compute_cost(MdbTableDef *table, MdbIndex *idx) { int i; @@ -531,7 +611,7 @@ int mdb_index_compute_cost(MdbTableDef *table, MdbIndex *idx) if (idx->num_keys > 1) { for (i=0;inum_keys;i++) { col=g_ptr_array_index(table->columns,idx->key_col_num[i]-1); - sarg = g_ptr_array_index (col->sargs, 0); + if (col->sargs) sarg = g_ptr_array_index (col->sargs, 0); if (!sarg || sarg->op != MDB_EQUAL) not_all_equal++; } } @@ -609,6 +689,12 @@ int mdb_index_compute_cost(MdbTableDef *table, MdbIndex *idx) } return 0; } +/* + * choose_index runs mdb_index_compute_cost for each available index and picks + * the best. + * + * Returns strategy to use (table scan, or index scan) + */ MdbStrategy mdb_choose_index(MdbTableDef *table, int *choice) { diff --git a/src/libmdb/sargs.c b/src/libmdb/sargs.c index 1ea15a6..00adc6e 100644 --- a/src/libmdb/sargs.c +++ b/src/libmdb/sargs.c @@ -17,6 +17,16 @@ * Boston, MA 02111-1307, USA. */ +/* + * code for handling searchable arguments (sargs) used primary by the sql + * engine to support where clause handling. The sargs are configured in + * a tree with AND/OR operators connecting the child nodes. NOT operations + * have only one child on the left side. Logical operators (=,<,>,etc..) + * have no children. + * + * 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" #ifdef DMALLOC @@ -66,6 +76,7 @@ int mdb_test_int(MdbSargNode *node, gint32 i) { switch (node->op) { case MDB_EQUAL: + //fprintf(stderr, "comparing %ld and %ld\n", i, node->value.i); if (node->value.i == i) return 1; break; case MDB_GT: @@ -124,13 +135,13 @@ int lastchar; switch (col->col_type) { case MDB_BYTE: - return mdb_test_int(node, (int)((char *)buf)[0]); + return mdb_test_int(node, (gint32)((char *)buf)[0]); break; case MDB_INT: - return mdb_test_int(node, mdb_get_int16(buf, 0)); + return mdb_test_int(node, (gint32)mdb_get_int16(buf, 0)); break; case MDB_LONGINT: - return mdb_test_int(node, mdb_get_int32(buf, 0)); + return mdb_test_int(node, (gint32)mdb_get_int32(buf, 0)); break; case MDB_TEXT: if (IS_JET4(mdb)) { diff --git a/src/libmdb/table.c b/src/libmdb/table.c index 5b9f49d..7d8ef9e 100644 --- a/src/libmdb/table.c +++ b/src/libmdb/table.c @@ -189,7 +189,7 @@ GPtrArray *mdb_read_columns(MdbTableDef *table) read_pg_if(mdb, &cur_col, 0); col.col_type = mdb->pg_buf[cur_col]; - read_pg_if(mdb, &cur_col, fmt->col_num_offset); // col_num_offset == 1 + read_pg_if(mdb, &cur_col, fmt->col_num_offset); // col_num_offset == 1 or 5 col.col_num = mdb->pg_buf[cur_col + fmt->col_num_offset]; /* FIXME: can this be right in Jet3 and Jet4? */ diff --git a/src/libmdb/write.c b/src/libmdb/write.c index 6f639d7..fadfb8d 100644 --- a/src/libmdb/write.c +++ b/src/libmdb/write.c @@ -86,13 +86,13 @@ MdbIndex *idx; return 0; } int -mdb_crack_row(MdbTableDef *table, int row_start, int row_end, MdbField *fields) +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, fixed_cols, num_cols, totcols; +int var_cols = 0, fixed_cols = 0, num_cols, totcols = 0; int var_cols_found, fixed_cols_found, var_entry_pos; int col_start, next_col; unsigned char *nullmask; @@ -100,15 +100,8 @@ int bitmask_sz; int byte_num, bit_num; int eod, len; /* end of data */ - if (IS_JET4(mdb)) { - num_cols = mdb_pg_get_int16(mdb, row_start); - } else { - num_cols = mdb->pg_buf[row_start]; - } + num_cols = mdb_pg_get_int16(mdb, row_start); - totcols = 0; - var_cols = 0; /* mdb->pg_buf[row_end-1]; */ - fixed_cols = 0; /* num_cols - var_cols; */ for (i = 0; i < table->num_cols; i++) { col = g_ptr_array_index (table->columns, i); if (mdb_is_fixed_col(col)) { @@ -139,12 +132,7 @@ int eod, len; /* end of data */ } /* find the end of data pointer */ - if (IS_JET4(mdb)) { - eod = mdb_pg_get_int16(mdb, row_end - 3 - var_cols*2 - bitmask_sz); - } else { - eod = mdb->pg_buf[row_end-1-var_cols-bitmask_sz]; - } - //printf("eod is %d\n", eod); + eod = mdb_pg_get_int16(mdb, row_end - 3 - var_cols*2 - bitmask_sz); if (IS_JET4(mdb)) { col_start = 2; @@ -174,23 +162,14 @@ int eod, len; /* end of data */ len=eod - col_start; //printf("len = %d eod %d col_start %d\n",len, eod, col_start); } else { - if (IS_JET4(mdb)) { - /* position of the var table - * entry for this column */ - var_entry_pos = - row_end - - bitmask_sz - - var_cols_found * 2 - 2 - 1; - next_col = mdb_pg_get_int16(mdb, var_entry_pos); - len = next_col - col_start; - } else { - var_entry_pos = - row_end - - bitmask_sz - - var_cols_found - 1; - len=mdb->pg_buf[var_entry_pos] - mdb->pg_buf[var_entry_pos+1]; - //printf("%d %d %d %d\n", mdb->pg_buf[var_entry_pos-1],mdb->pg_buf[var_entry_pos],len, col_start); - } + /* position of the var table + * entry for this column */ + var_entry_pos = + row_end - + bitmask_sz - + var_cols_found * 2 - 2 - 1; + next_col = mdb_pg_get_int16(mdb, var_entry_pos); + len = next_col - col_start; } /* if found==var_cols */ if (len<0) len+=256; fields[totcols].start = row_start + col_start; @@ -203,6 +182,108 @@ int eod, len; /* end of data */ return num_cols; } +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, next_col; +unsigned char *nullmask; +int bitmask_sz; +int byte_num, bit_num; +int eod, len; /* end of data */ + + num_cols = mdb->pg_buf[row_start]; + + 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; + } + } + 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; + } + } + + 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]; + + /* data starts at 1 */ + col_start = 1; + + /* actual cols on this row */ + 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); + 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]; + if (col->col_type != MDB_BOOL) + col_start += col->col_size; + } + } + for (j=0;jnum_cols;j++) { + col = g_ptr_array_index(table->columns,j); + if (!mdb_is_fixed_col(col) && ++var_cols_found <= var_cols) { + if (var_cols_found==var_cols) { + len=eod - col_start; + //printf("len = %d eod %d col_start %d\n",len, eod, col_start); + } else { + var_entry_pos = + row_end - + bitmask_sz - + var_cols_found - 1; + len=mdb->pg_buf[var_entry_pos] - mdb->pg_buf[var_entry_pos+1]; + } /* if found==var_cols */ + if (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; + col_start += len; + } /* if !fixed */ + } /* for */ + + return num_cols; + +} +int +mdb_crack_row(MdbTableDef *table, int row_start, int row_end, MdbField *fields) +{ +MdbCatalogEntry *entry = table->entry; +MdbHandle *mdb = entry->mdb; + + if (IS_JET4(mdb)) { + return mdb_crack_row4(table, row_start, row_end, fields); + } else { + return mdb_crack_row3(table, row_start, row_end, fields); + } +} /* fields must be ordered with fixed columns first, then vars, subsorted by * column number */ int @@ -277,6 +358,20 @@ int rows, free_start, free_end; return (free_end - free_start + 1); } unsigned char * +mdb_new_leaf_pg(MdbCatalogEntry *entry) +{ + MdbHandle *mdb = entry->mdb; + unsigned char *new_pg; + + new_pg = (unsigned char *) g_malloc0(mdb->fmt->pg_size); + + new_pg[0]=0x04; + new_pg[1]=0x01; + _mdb_put_int32(new_pg, 4, entry->table_pg); + + return new_pg; +} +unsigned char * mdb_new_data_pg(MdbCatalogEntry *entry) { MdbHandle *mdb = entry->mdb; @@ -292,7 +387,7 @@ mdb_new_data_pg(MdbCatalogEntry *entry) } int -mdb_update_indexes(MdbTableDef *table, int num_fields, MdbField *fields) +mdb_update_indexes(MdbTableDef *table, int num_fields, MdbField *fields, guint32 pgnum, guint16 rownum) { int i; MdbIndex *idx; @@ -303,7 +398,7 @@ mdb_update_indexes(MdbTableDef *table, int num_fields, MdbField *fields) fprintf(stderr,"Updating %s (%d).\n", idx->name, idx->index_type); #endif if (idx->index_type==1) { - mdb_update_index(table, idx, num_fields, fields); + mdb_update_index(table, idx, num_fields, fields, pgnum, rownum); } } return 1; @@ -322,11 +417,15 @@ mdb_init_index_chain(MdbTableDef *table, MdbIndex *idx) return 1; } + int -mdb_update_index(MdbTableDef *table, MdbIndex *idx, int num_fields, MdbField *fields) +mdb_update_index(MdbTableDef *table, MdbIndex *idx, int num_fields, MdbField *fields, guint32 pgnum, guint16 rownum) { + MdbCatalogEntry *entry = table->entry; + MdbHandle *mdb = entry->mdb; int idx_xref[16]; int i, j; + MdbIndexChain *chain; for (i = 0; i < idx->num_keys; i++) { for (j = 0; j < num_fields; j++) { @@ -345,7 +444,13 @@ mdb_update_index(MdbTableDef *table, MdbIndex *idx, int num_fields, MdbField *fi i, fields[i].colnum, fields[i].siz); } - //mdb_find_leaf_pg(); + + chain = g_malloc0(sizeof(MdbIndexChain)); + + mdb_index_find_row(mdb, idx, chain, pgnum, rownum); + printf("chain depth = %d\n", chain->cur_depth); + printf("pg = %lu\n", chain->pages[chain->cur_depth-1].pg); + mdb_copy_index_pg(table, &chain->pages[chain->cur_depth-1]); return 1; } @@ -359,6 +464,8 @@ mdb_insert_row(MdbTableDef *table, int num_fields, MdbField *fields) MdbHandle *mdb = entry->mdb; 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"); @@ -374,7 +481,7 @@ mdb_insert_row(MdbTableDef *table, int num_fields, MdbField *fields) return 0; } - mdb_add_row_to_pg(table, row_buffer, new_row_size); + rownum = mdb_add_row_to_pg(table, row_buffer, new_row_size); #if MDB_DEBUG_WRITE buffer_dump(mdb->pg_buf, 0, 39); @@ -386,15 +493,15 @@ mdb_insert_row(MdbTableDef *table, int num_fields, MdbField *fields) exit(1); } - mdb_update_indexes(table, num_fields, fields); - + mdb_update_indexes(table, num_fields, fields, pgnum, rownum); + return 1; } /* * Assumes caller has verfied space is available on page and adds the new * row to the current pg_buf. */ -void +guint16 mdb_add_row_to_pg(MdbTableDef *table, unsigned char *row_buffer, int new_row_size) { unsigned char *new_pg; @@ -434,6 +541,8 @@ mdb_add_row_to_pg(MdbTableDef *table, unsigned char *row_buffer, int new_row_siz /* update the freespace */ _mdb_put_int16(mdb->pg_buf, 2, mdb_pg_get_freespace(mdb)); + + return num_rows; } int mdb_update_row(MdbTableDef *table) @@ -564,3 +673,26 @@ int i, pos; } return 0; } +int +mdb_copy_index_pg(MdbTableDef *table, MdbIndexPage *ipg) +{ + MdbCatalogEntry *entry = table->entry; + MdbHandle *mdb = entry->mdb; + guint32 pg; + unsigned char *new_pg; + + new_pg = mdb_new_leaf_pg(entry); + + mdb_index_page_reset(ipg); + mdb_read_pg(mdb, ipg->pg); + while (mdb_index_find_next_on_page(mdb, ipg)) { + pg = mdb_pg_get_int24_msb(mdb, ipg->offset + ipg->len - 3); + printf("length = %d\n", ipg->len); + buffer_dump(mdb->pg_buf, ipg->offset, ipg->offset + ipg->len - 1); + ipg->offset += ipg->len; + ipg->len = 0; + } + g_free(new_pg); + + return ipg->len; +} diff --git a/src/sql/lexer.c b/src/sql/lexer.c index 54ca9ae..21380d8 100644 --- a/src/sql/lexer.c +++ b/src/sql/lexer.c @@ -1,7 +1,7 @@ /* A lexical scanner generated by flex */ /* Scanner skeleton version: - * $Header: /Users/brian/cvs/mdbtools/mdbtools/src/sql/Attic/lexer.c,v 1.6 2003/01/20 16:04:31 brianb Exp $ + * $Header: /Users/brian/cvs/mdbtools/mdbtools/src/sql/Attic/lexer.c,v 1.7 2004/02/06 02:34:22 brianb Exp $ */ #define FLEX_SCANNER @@ -282,20 +282,20 @@ static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); *yy_cp = '\0'; \ yy_c_buf_p = yy_cp; -#define YY_NUM_RULES 24 -#define YY_END_OF_BUFFER 25 -static yyconst short int yy_accept[95] = +#define YY_NUM_RULES 25 +#define YY_END_OF_BUFFER 26 +static yyconst short int yy_accept[97] = { 0, - 21, 21, 25, 23, 17, 24, 23, 23, 22, 23, - 21, 23, 23, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 23, 0, 0, 20, 0, 22, - 0, 22, 22, 21, 14, 15, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 12, 19, 19, 5, 19, - 0, 18, 0, 21, 21, 11, 19, 19, 19, 19, - 19, 19, 13, 19, 19, 19, 19, 19, 19, 2, - 16, 6, 19, 19, 19, 19, 19, 19, 19, 9, - 7, 19, 19, 19, 1, 8, 3, 19, 19, 10, - 19, 19, 4, 0 + 22, 22, 26, 24, 18, 25, 24, 24, 23, 24, + 22, 24, 24, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 24, 0, 0, 21, 0, + 23, 0, 23, 23, 22, 15, 16, 20, 20, 20, + 20, 20, 20, 20, 14, 20, 20, 12, 20, 20, + 5, 20, 0, 19, 0, 22, 22, 11, 20, 20, + 20, 20, 20, 20, 13, 20, 20, 20, 20, 20, + 20, 2, 17, 6, 20, 20, 20, 20, 20, 20, + 20, 9, 7, 20, 20, 20, 1, 8, 3, 20, + 20, 10, 20, 20, 4, 0 } ; @@ -339,112 +339,116 @@ static yyconst int yy_meta[36] = 8, 8, 8, 8, 1 } ; -static yyconst short int yy_base[101] = +static yyconst short int yy_base[103] = { 0, - 0, 0, 158, 285, 285, 285, 0, 149, 29, 31, - 36, 132, 115, 41, 43, 45, 52, 51, 24, 39, - 53, 46, 62, 64, 81, 113, 90, 75, 86, 87, - 90, 95, 101, 0, 285, 285, 65, 0, 94, 91, - 85, 100, 103, 105, 102, 113, 115, 123, 118, 124, - 75, 285, 54, 53, 140, 126, 132, 135, 143, 138, - 144, 146, 149, 151, 156, 157, 159, 164, 166, 165, - 172, 173, 180, 179, 181, 188, 187, 189, 190, 195, - 196, 201, 207, 208, 210, 215, 217, 218, 220, 223, - 228, 225, 230, 285, 50, 258, 263, 267, 273, 276 + 0, 0, 177, 289, 289, 289, 0, 156, 29, 31, + 36, 126, 111, 41, 43, 45, 52, 51, 39, 24, + 44, 58, 59, 69, 67, 75, 114, 92, 75, 88, + 83, 91, 96, 102, 0, 289, 289, 86, 0, 95, + 92, 97, 103, 106, 105, 112, 118, 120, 121, 129, + 128, 131, 73, 289, 55, 54, 122, 134, 136, 139, + 147, 142, 148, 150, 153, 155, 160, 161, 163, 168, + 170, 169, 176, 177, 184, 183, 185, 192, 191, 193, + 194, 199, 200, 205, 211, 212, 214, 219, 221, 222, + 224, 227, 232, 229, 234, 289, 50, 262, 267, 271, + 277, 280 } ; -static yyconst short int yy_def[101] = +static yyconst short int yy_def[103] = { 0, - 94, 1, 94, 94, 94, 94, 95, 96, 97, 97, - 97, 94, 94, 98, 98, 98, 98, 17, 17, 17, - 17, 17, 17, 17, 11, 99, 96, 96, 94, 11, - 11, 11, 11, 11, 94, 94, 17, 100, 17, 17, + 96, 1, 96, 96, 96, 96, 97, 98, 99, 99, + 99, 96, 96, 100, 100, 100, 100, 17, 17, 17, + 17, 17, 17, 17, 17, 11, 101, 98, 98, 96, + 11, 11, 11, 11, 11, 96, 96, 17, 102, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 99, 94, 94, 94, 11, 17, 17, 17, 17, 17, + 17, 17, 101, 96, 96, 96, 11, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 0, 94, 94, 94, 94, 94, 94 + 17, 17, 17, 17, 17, 0, 96, 96, 96, 96, + 96, 96 } ; -static yyconst short int yy_nxt[321] = +static yyconst short int yy_nxt[325] = { 0, 4, 5, 6, 5, 7, 8, 4, 4, 4, 9, 10, 11, 12, 4, 13, 4, 14, 15, 16, 17, - 15, 18, 15, 15, 15, 15, 19, 15, 20, 21, - 15, 22, 23, 24, 25, 29, 29, 94, 94, 31, - 32, 94, 94, 94, 37, 33, 31, 34, 44, 32, - 30, 31, 30, 31, 30, 31, 38, 26, 38, 37, - 38, 30, 31, 37, 54, 54, 47, 38, 45, 39, - 37, 37, 41, 37, 40, 37, 42, 37, 48, 52, - 28, 43, 37, 46, 37, 37, 37, 50, 37, 37, - 30, 49, 30, 53, 53, 28, 30, 54, 30, 30, + 15, 18, 15, 15, 19, 15, 20, 15, 21, 22, + 15, 23, 24, 25, 26, 30, 30, 96, 96, 32, + 33, 96, 96, 96, 38, 34, 32, 35, 46, 33, + 31, 32, 31, 32, 31, 32, 39, 27, 39, 38, + 39, 31, 32, 38, 38, 56, 56, 39, 38, 40, + 45, 38, 42, 47, 41, 38, 43, 54, 38, 49, + 29, 44, 38, 38, 31, 50, 31, 38, 48, 38, + 52, 38, 31, 38, 31, 55, 55, 29, 51, 56, - 94, 30, 53, 53, 30, 37, 55, 29, 29, 37, - 30, 37, 32, 56, 37, 37, 58, 52, 37, 57, - 37, 32, 37, 37, 37, 37, 37, 37, 36, 37, - 61, 59, 60, 37, 63, 37, 62, 37, 37, 37, - 65, 64, 37, 37, 66, 35, 37, 37, 37, 30, - 37, 55, 37, 68, 28, 37, 37, 94, 37, 37, - 67, 69, 37, 37, 71, 70, 37, 37, 37, 37, - 37, 73, 94, 37, 94, 37, 37, 37, 72, 76, - 37, 37, 74, 37, 37, 37, 37, 75, 37, 37, - 37, 94, 37, 37, 77, 78, 37, 37, 79, 80, + 31, 96, 31, 55, 55, 31, 38, 57, 30, 30, + 38, 31, 38, 33, 58, 38, 38, 38, 54, 38, + 59, 38, 33, 38, 37, 38, 38, 38, 60, 38, + 38, 31, 38, 57, 61, 62, 38, 63, 38, 36, + 38, 38, 38, 64, 38, 38, 67, 66, 38, 38, + 65, 68, 38, 38, 38, 38, 38, 70, 38, 38, + 38, 29, 38, 38, 69, 71, 38, 38, 73, 72, + 38, 38, 38, 38, 38, 75, 96, 38, 96, 38, + 38, 38, 74, 78, 38, 38, 76, 38, 38, 38, + 38, 77, 38, 38, 38, 96, 38, 38, 79, 80, - 37, 81, 94, 37, 37, 37, 82, 37, 37, 37, - 37, 83, 37, 37, 37, 37, 37, 84, 94, 37, - 37, 37, 85, 94, 88, 37, 86, 37, 37, 94, - 37, 37, 37, 87, 37, 37, 89, 37, 90, 37, - 91, 37, 37, 37, 37, 37, 92, 37, 37, 37, - 37, 94, 37, 94, 37, 94, 94, 93, 27, 94, - 27, 27, 27, 27, 27, 27, 30, 30, 30, 94, - 30, 37, 37, 37, 37, 51, 94, 94, 51, 51, - 51, 38, 38, 38, 3, 94, 94, 94, 94, 94, - 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 38, 38, 81, 82, 38, 83, 96, 38, 38, 38, + 84, 38, 38, 38, 38, 85, 38, 38, 38, 38, + 38, 86, 96, 38, 38, 38, 87, 96, 90, 38, + 88, 38, 38, 96, 38, 38, 38, 89, 38, 38, + 91, 38, 92, 38, 93, 38, 38, 38, 38, 38, + 94, 38, 38, 38, 38, 96, 38, 96, 38, 96, + 96, 95, 28, 96, 28, 28, 28, 28, 28, 28, + 31, 31, 31, 96, 31, 38, 38, 38, 38, 53, + 96, 96, 53, 53, 53, 39, 39, 39, 3, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, - 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96 } ; -static yyconst short int yy_chk[321] = +static yyconst short int yy_chk[325] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 10, 10, 9, - 9, 10, 11, 11, 19, 11, 11, 11, 19, 9, - 14, 14, 15, 15, 16, 16, 14, 95, 15, 20, - 16, 17, 17, 20, 54, 53, 22, 17, 20, 14, - 22, 18, 17, 21, 16, 18, 17, 21, 23, 51, - 28, 18, 23, 21, 24, 37, 23, 24, 24, 37, - 25, 23, 25, 29, 29, 27, 30, 29, 30, 31, + 9, 10, 11, 11, 20, 11, 11, 11, 20, 9, + 14, 14, 15, 15, 16, 16, 14, 97, 15, 19, + 16, 17, 17, 19, 21, 56, 55, 17, 21, 14, + 19, 18, 17, 21, 16, 18, 17, 53, 22, 23, + 29, 18, 22, 23, 26, 24, 26, 25, 22, 24, + 25, 25, 31, 24, 31, 30, 30, 28, 24, 30, - 31, 31, 32, 32, 32, 41, 32, 33, 33, 41, - 33, 40, 33, 39, 39, 40, 41, 26, 39, 40, - 42, 33, 45, 43, 42, 44, 45, 43, 13, 44, - 44, 42, 43, 46, 45, 47, 44, 46, 49, 47, - 48, 47, 49, 48, 50, 12, 56, 48, 50, 55, - 56, 55, 57, 58, 8, 58, 57, 3, 60, 58, - 57, 59, 60, 59, 61, 60, 62, 59, 61, 63, - 62, 64, 0, 63, 0, 64, 65, 66, 62, 67, - 65, 66, 65, 67, 68, 70, 69, 66, 68, 70, - 69, 0, 71, 72, 68, 69, 71, 72, 73, 74, + 32, 32, 32, 33, 33, 33, 38, 33, 34, 34, + 38, 34, 41, 34, 40, 40, 41, 42, 27, 40, + 41, 42, 34, 43, 13, 45, 44, 43, 42, 45, + 44, 57, 46, 57, 43, 44, 46, 46, 47, 12, + 48, 49, 47, 46, 48, 49, 50, 49, 51, 50, + 47, 52, 51, 50, 58, 52, 59, 60, 58, 60, + 59, 8, 62, 60, 59, 61, 62, 61, 63, 62, + 64, 61, 63, 65, 64, 66, 3, 65, 0, 66, + 67, 68, 64, 69, 67, 68, 67, 69, 70, 72, + 71, 68, 70, 72, 71, 0, 73, 74, 70, 71, - 73, 75, 0, 74, 73, 75, 76, 77, 76, 78, - 79, 77, 76, 78, 79, 80, 81, 78, 0, 80, - 81, 82, 79, 0, 83, 82, 80, 83, 84, 0, - 85, 83, 84, 82, 85, 86, 84, 87, 88, 86, - 89, 87, 88, 90, 89, 92, 91, 90, 91, 92, - 93, 0, 91, 0, 93, 0, 0, 92, 96, 0, - 96, 96, 96, 96, 96, 96, 97, 97, 97, 0, - 97, 98, 98, 98, 98, 99, 0, 0, 99, 99, - 99, 100, 100, 100, 94, 94, 94, 94, 94, 94, - 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 73, 74, 75, 76, 75, 77, 0, 76, 75, 77, + 78, 79, 78, 80, 81, 79, 78, 80, 81, 82, + 83, 80, 0, 82, 83, 84, 81, 0, 85, 84, + 82, 85, 86, 0, 87, 85, 86, 84, 87, 88, + 86, 89, 90, 88, 91, 89, 90, 92, 91, 94, + 93, 92, 93, 94, 95, 0, 93, 0, 95, 0, + 0, 94, 98, 0, 98, 98, 98, 98, 98, 98, + 99, 99, 99, 0, 99, 100, 100, 100, 100, 101, + 0, 0, 101, 101, 101, 102, 102, 102, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, - 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96 } ; static yy_state_type yy_last_accepting_state; @@ -483,7 +487,7 @@ char *yytext; #include "mdbsql.h" #include "parser.h" -#line 487 "lexer.c" +#line 491 "lexer.c" /* Macros after this point can all be overridden by user definitions in * section 1. @@ -636,7 +640,7 @@ YY_DECL #line 26 "lexer.l" -#line 640 "lexer.c" +#line 644 "lexer.c" if ( yy_init ) { @@ -687,13 +691,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 95 ) + if ( yy_current_state >= 97 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 285 ); + while ( yy_base[yy_current_state] != 289 ); yy_find_action: yy_act = yy_accept[yy_current_state]; @@ -787,65 +791,70 @@ YY_RULE_SETUP case 14: YY_RULE_SETUP #line 40 "lexer.l" -{ return LTEQ; } +{ return IS; } YY_BREAK case 15: YY_RULE_SETUP #line 41 "lexer.l" -{ return GTEQ; } +{ return LTEQ; } YY_BREAK case 16: YY_RULE_SETUP #line 42 "lexer.l" -{ return LIKE; } +{ return GTEQ; } YY_BREAK case 17: YY_RULE_SETUP #line 43 "lexer.l" -; +{ return LIKE; } YY_BREAK case 18: YY_RULE_SETUP #line 44 "lexer.l" +; + YY_BREAK +case 19: +YY_RULE_SETUP +#line 45 "lexer.l" { yylval.name = strdup(&yytext[1]); yylval.name[strlen(yylval.name)-1]='\0'; return IDENT; } YY_BREAK -case 19: -YY_RULE_SETUP -#line 49 "lexer.l" -{ yylval.name = strdup(yytext); return NAME; } - YY_BREAK case 20: YY_RULE_SETUP -#line 51 "lexer.l" -{ yylval.name = strdup(yytext); return STRING; } +#line 50 "lexer.l" +{ yylval.name = strdup(yytext); return NAME; } YY_BREAK case 21: YY_RULE_SETUP #line 52 "lexer.l" +{ yylval.name = strdup(yytext); return STRING; } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 53 "lexer.l" { yylval.name = strdup(yytext); return NUMBER; } YY_BREAK -case 22: -YY_RULE_SETUP -#line 55 "lexer.l" -{ yylval.name = strdup(yytext); return PATH; } - YY_BREAK case 23: YY_RULE_SETUP #line 56 "lexer.l" -{ return yytext[0]; } +{ yylval.name = strdup(yytext); return PATH; } YY_BREAK case 24: YY_RULE_SETUP #line 57 "lexer.l" +{ return yytext[0]; } + YY_BREAK +case 25: +YY_RULE_SETUP +#line 58 "lexer.l" ECHO; YY_BREAK -#line 849 "lexer.c" +#line 858 "lexer.c" case YY_STATE_EOF(INITIAL): yyterminate(); @@ -1137,7 +1146,7 @@ static yy_state_type yy_get_previous_state() while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 95 ) + if ( yy_current_state >= 97 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -1172,11 +1181,11 @@ yy_state_type yy_current_state; while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 95 ) + if ( yy_current_state >= 97 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 94); + yy_is_jam = (yy_current_state == 96); return yy_is_jam ? 0 : yy_current_state; } @@ -1726,7 +1735,7 @@ int main() return 0; } #endif -#line 57 "lexer.l" +#line 58 "lexer.l" int yywrap() diff --git a/src/sql/lexer.l b/src/sql/lexer.l index f213f64..18e5c58 100644 --- a/src/sql/lexer.l +++ b/src/sql/lexer.l @@ -37,6 +37,7 @@ describe { return DESCRIBE; } and { return AND; } or { return OR; } not { return NOT; } +is { return IS; } (<=) { return LTEQ; } (>=) { return GTEQ; } like { return LIKE; } diff --git a/src/sql/parser.y b/src/sql/parser.y index 25607b3..9752d19 100644 --- a/src/sql/parser.y +++ b/src/sql/parser.y @@ -43,11 +43,12 @@ static MdbSQL *g_sql; %token IDENT NAME PATH STRING NUMBER %token SELECT FROM WHERE CONNECT DISCONNECT TO LIST TABLES WHERE AND OR NOT %token DESCRIBE TABLE -%token LTEQ GTEQ LIKE +%token LTEQ GTEQ LIKE IS NULL %type database %type constant %type operator +%type nulloperator %% @@ -98,6 +99,10 @@ sarg: free($1); free($3); } + | NAME nulloperator { + mdb_sql_add_sarg(_mdb_sql(NULL), $1, $2, NULL); + free($1); + } ; operator: @@ -108,6 +113,12 @@ operator: | GTEQ { $$ = MDB_GTEQ; } | LIKE { $$ = MDB_LIKE; } ; + +nulloperator: + IS NULL { $$ = MDB_ISNULL; } + | IS NOT NULL { $$ = MDB_NOTNULL; } + ; + constant: NUMBER { $$ = $1; } | STRING { $$ = $1; }