Merge branch 'master' into master

This commit is contained in:
leecher1337
2017-12-03 17:02:15 +01:00
committed by GitHub
18 changed files with 291 additions and 50 deletions

View File

@@ -1,3 +1,9 @@
Tue Aug 30 08:51:31 EDT 2016 Brian Bruns <brian@bruns.com>
* bug fix for 'bad' data with odd number of UCS-2 bytes
Tue Aug 30 08:40:00 EDT 2016 Brian Bruns <brian@bruns.com>
* add LIMIT clause to SQL engine
Tue May 23 19:40:55 CDT 2006 Jeff Smith <whydoubt@yahoo.com> Tue May 23 19:40:55 CDT 2006 Jeff Smith <whydoubt@yahoo.com>
* src/util/mdb-export.c: Fix typo in help text * src/util/mdb-export.c: Fix typo in help text
* configure.in: Clean up use of autoconf macros * configure.in: Clean up use of autoconf macros
@@ -900,7 +906,7 @@ Sun Feb 8 13:02:56 EST 2004 Brian Bruns <brian@bruns.com>
* include/mdbsql.h: * include/mdbsql.h:
* src/sql/parser.y: * src/sql/parser.y:
* src/sql/mdbsql.c: added mdb_sql_eval_expr() to support 0=1 literal comparison * src/sql/mdbsql.c: added mdb_sql_eval_expr() to support 0=1 literal comparison
* src/libmdb/sargs.c: check for null node->col (literal comparision) * src/libmdb/sargs.c: check for null node->col (literal comparison)
* src/sql/Makefile.am: change hardcoded bison reference to @YACC@ * src/sql/Makefile.am: change hardcoded bison reference to @YACC@
Fri Feb 6 18:08:59 EST 2004 Brian Bruns <brian@bruns.com> Fri Feb 6 18:08:59 EST 2004 Brian Bruns <brian@bruns.com>

View File

@@ -632,7 +632,7 @@ Indices are not completely understood but here is what we know.
+------+---------+-------------+------------------------------------------+ +------+---------+-------------+------------------------------------------+
| data | length | name | description | | data | length | name | description |
+------+---------+-------------+------------------------------------------+ +------+---------+-------------+------------------------------------------+
| 0x01 | 1 bytes | page_type | 0x03 indicate an index page | | 0x03 | 1 bytes | page_type | 0x03 indicate an index page |
| 0x01 | 1 bytes | unknown | | | 0x01 | 1 bytes | unknown | |
| ???? | 2 bytes | free_space | The free space at the end this page | | ???? | 2 bytes | free_space | The free space at the end this page |
| ???? | 4 bytes | parent_page | The page number of the TDEF for this idx | | ???? | 4 bytes | parent_page | The page number of the TDEF for this idx |

2
README
View File

@@ -14,7 +14,7 @@ pieces are:
scripts scripts
mdb-header -- generates a C header to be used in exporting mdb mdb-header -- generates a C header to be used in exporting mdb
data to a C prog. data to a C prog.
mdb-parsecvs -- generates a C program given a CSV file made with mdb-parsecsv -- generates a C program given a CSV file made with
mdb-export mdb-export
mdb-sql -- if --enable-sql is specified, a simple SQL engine mdb-sql -- if --enable-sql is specified, a simple SQL engine
(also used by ODBC and gmdb). (also used by ODBC and gmdb).

View File

@@ -18,8 +18,8 @@
Permission is granted to copy, distribute and/or modify this document Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.1 under the terms of the GNU Free Documentation License, Version 1.1
or any later version published by the Free Software Foundation; or any later version published by the Free Software Foundation;
with no Invariant Sections, with no with no Invariant Sections, no
Front-Cover Texts, and with no Back-Cover Texts. Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled <link linkend="gfdl">GNU A copy of the license is included in the section entitled <link linkend="gfdl">GNU
Free Documentation License</link>.</para> Free Documentation License</link>.</para>
</legalnotice> </legalnotice>

View File

@@ -44,4 +44,4 @@ AUTHORS
The mdb-tables utility was written by Brian Bruns. The mdb-tables utility was written by Brian Bruns.
BUGS BUGS
Access allows for tables to have spaces embeded in the table name. You must specify a delimiter (-d) if you intend on piping the output of mdb-tables to a program such as awk or cut. Access allows for tables to have spaces embedded in the table name. You must specify a delimiter (-d) if you intend on piping the output of mdb-tables to a program such as awk or cut.

View File

@@ -44,6 +44,8 @@ typedef struct {
unsigned char *kludge_ttable_pg; unsigned char *kludge_ttable_pg;
long max_rows; long max_rows;
char error_msg[1024]; char error_msg[1024];
int limit;
long row_count;
} MdbSQL; } MdbSQL;
typedef struct { typedef struct {
@@ -102,6 +104,7 @@ extern void mdb_sql_bind_all(MdbSQL *sql);
extern int mdb_sql_fetch_row(MdbSQL *sql, MdbTableDef *table); extern int mdb_sql_fetch_row(MdbSQL *sql, MdbTableDef *table);
extern int mdb_sql_add_temp_col(MdbSQL *sql, MdbTableDef *ttable, int col_num, char *name, int col_type, int col_size, int is_fixed); extern int mdb_sql_add_temp_col(MdbSQL *sql, MdbTableDef *ttable, int col_num, char *name, int col_type, int col_size, int is_fixed);
extern void mdb_sql_bind_column(MdbSQL *sql, int colnum, void *varaddr, int *len_ptr); extern void mdb_sql_bind_column(MdbSQL *sql, int colnum, void *varaddr, int *len_ptr);
extern int mdb_sql_add_limit(MdbSQL *sql, char *limit);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -498,6 +498,7 @@ 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 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_ole_read_full(MdbHandle *mdb, MdbColumn *col, size_t *size);
extern void mdb_set_date_fmt(const char *); extern void mdb_set_date_fmt(const char *);
extern void mdb_set_boolean_fmt_words();
extern int mdb_read_row(MdbTableDef *table, unsigned int row); extern int mdb_read_row(MdbTableDef *table, unsigned int row);
/* dump.c */ /* dump.c */

View File

@@ -54,7 +54,7 @@ if test "$gdu_cv_have_gdu" = "yes"; then
ifelse([$2],,[:],[$2]) ifelse([$2],,[:],[$2])
else else
AC_MSG_RESULT([no]) AC_MSG_RESULT([no])
ifelse([$3],,[AC_MSG_ERROR([gnome-doc-utils >= $gdu_cv_version_required not found])],[$3]) ifelse([$3],,[:],[$3])
fi fi
GNOME_DOC_DEFINES GNOME_DOC_DEFINES

View File

@@ -71,8 +71,8 @@ static MdbBackendType mdb_oracle_types[] = {
MdbBackendType_STRUCT_ELEMENT("TIMESTAMP",0,0,0), MdbBackendType_STRUCT_ELEMENT("TIMESTAMP",0,0,0),
MdbBackendType_STRUCT_ELEMENT("BINARY",0,0,0), MdbBackendType_STRUCT_ELEMENT("BINARY",0,0,0),
MdbBackendType_STRUCT_ELEMENT("VARCHAR2",1,0,1), MdbBackendType_STRUCT_ELEMENT("VARCHAR2",1,0,1),
MdbBackendType_STRUCT_ELEMENT("BLOB",1,0,1), MdbBackendType_STRUCT_ELEMENT("BLOB",0,0,0),
MdbBackendType_STRUCT_ELEMENT("CLOB",1,0,1), MdbBackendType_STRUCT_ELEMENT("CLOB",0,0,0),
MdbBackendType_STRUCT_ELEMENT("Oracle_Unknown 0x0d",0,0,0), MdbBackendType_STRUCT_ELEMENT("Oracle_Unknown 0x0d",0,0,0),
MdbBackendType_STRUCT_ELEMENT("Oracle_Unknown 0x0e",0,0,0), MdbBackendType_STRUCT_ELEMENT("Oracle_Unknown 0x0e",0,0,0),
MdbBackendType_STRUCT_ELEMENT("NUMBER",1,0,0), MdbBackendType_STRUCT_ELEMENT("NUMBER",1,0,0),
@@ -506,7 +506,9 @@ mdb_print_indexes(FILE* outfile, MdbTableDef *table, char *dbnamespace)
backend = MDB_BACKEND_POSTGRES; backend = MDB_BACKEND_POSTGRES;
} else if (!strcmp(mdb->backend_name, "mysql")) { } else if (!strcmp(mdb->backend_name, "mysql")) {
backend = MDB_BACKEND_MYSQL; backend = MDB_BACKEND_MYSQL;
} else { } else if (!strcmp(mdb->backend_name, "oracle")) {
backend = MDB_BACKEND_ORACLE;
} else {
fprintf(outfile, "-- Indexes are not implemented for %s\n\n", mdb->backend_name); fprintf(outfile, "-- Indexes are not implemented for %s\n\n", mdb->backend_name);
return; return;
} }
@@ -535,6 +537,7 @@ mdb_print_indexes(FILE* outfile, MdbTableDef *table, char *dbnamespace)
quoted_name = mdb->default_backend->quote_schema_name(dbnamespace, index_name); quoted_name = mdb->default_backend->quote_schema_name(dbnamespace, index_name);
if (idx->index_type==1) { if (idx->index_type==1) {
switch (backend) { switch (backend) {
case MDB_BACKEND_ORACLE:
case MDB_BACKEND_POSTGRES: case MDB_BACKEND_POSTGRES:
fprintf (outfile, "ALTER TABLE %s ADD CONSTRAINT %s PRIMARY KEY (", quoted_table_name, quoted_name); fprintf (outfile, "ALTER TABLE %s ADD CONSTRAINT %s PRIMARY KEY (", quoted_table_name, quoted_name);
break; break;
@@ -544,6 +547,7 @@ mdb_print_indexes(FILE* outfile, MdbTableDef *table, char *dbnamespace)
} }
} else { } else {
switch (backend) { switch (backend) {
case MDB_BACKEND_ORACLE:
case MDB_BACKEND_POSTGRES: case MDB_BACKEND_POSTGRES:
fprintf(outfile, "CREATE"); fprintf(outfile, "CREATE");
if (idx->flags & MDB_IDX_UNIQUE) if (idx->flags & MDB_IDX_UNIQUE)
@@ -691,6 +695,15 @@ mdb_get_relationships(MdbHandle *mdb, const gchar *dbnamespace, const char* tabl
} else { } else {
switch (backend) { switch (backend) {
case MDB_BACKEND_ORACLE: case MDB_BACKEND_ORACLE:
text = g_strconcat(
"ALTER TABLE ", quoted_table_1,
" ADD CONSTRAINT ", quoted_constraint_name,
" FOREIGN KEY (", quoted_column_1, ")"
" REFERENCES ", quoted_table_2, "(", quoted_column_2, ")",
(grbit & 0x00001000) ? " ON DELETE CASCADE" : "",
";\n", NULL);
break;
case MDB_BACKEND_POSTGRES: case MDB_BACKEND_POSTGRES:
case MDB_BACKEND_SQLITE: case MDB_BACKEND_SQLITE:
text = g_strconcat( text = g_strconcat(

View File

@@ -48,6 +48,25 @@ void mdb_set_date_fmt(const char *fmt)
strncpy(date_fmt, fmt, 63); strncpy(date_fmt, fmt, 63);
} }
/* Some databases (eg PostgreSQL) do not understand integer 0/1 values
* as TRUE/FALSE, so provide a means to override the values used to be
* the SQL Standard TRUE/FALSE values.
*/
static char boolean_false_number[] = "0";
static char boolean_true_number[] = "1";
static char boolean_false_word[] = "FALSE";
static char boolean_true_word[] = "TRUE";
static char *boolean_false_value = boolean_false_number;
static char *boolean_true_value = boolean_true_number;
void mdb_set_boolean_fmt_words()
{
boolean_false_value = boolean_false_word;
boolean_true_value = boolean_true_word;
}
void mdb_bind_column(MdbTableDef *table, int col_num, void *bind_ptr, int *len_ptr) void mdb_bind_column(MdbTableDef *table, int col_num, void *bind_ptr, int *len_ptr)
{ {
MdbColumn *col; MdbColumn *col;
@@ -172,10 +191,11 @@ mdb_xfer_bound_bool(MdbHandle *mdb, MdbColumn *col, int value)
{ {
col->cur_value_len = value; col->cur_value_len = value;
if (col->bind_ptr) { if (col->bind_ptr) {
strcpy(col->bind_ptr, value ? "0" : "1"); strcpy(col->bind_ptr,
value ? boolean_false_value : boolean_true_value);
} }
if (col->len_ptr) { if (col->len_ptr) {
*col->len_ptr = 1; *col->len_ptr = strlen(col->bind_ptr);
} }
return 1; return 1;

View File

@@ -70,6 +70,13 @@ mdb_unicode2ascii(MdbHandle *mdb, char *src, size_t slen, char *dest, size_t dle
//printf("1 len_in %d len_out %d\n",len_in, len_out); //printf("1 len_in %d len_out %d\n",len_in, len_out);
while (1) { while (1) {
iconv(mdb->iconv_in, &in_ptr, &len_in, &out_ptr, &len_out); iconv(mdb->iconv_in, &in_ptr, &len_in, &out_ptr, &len_out);
/*
* Have seen database with odd number of bytes in UCS-2, shouldn't happen but protect against it
*/
if (!IS_JET3(mdb) && len_in<=1) {
//fprintf(stderr, "Detected invalid number of UCS-2 bytes\n");
break;
}
if ((!len_in) || (errno == E2BIG)) break; if ((!len_in) || (errno == E2BIG)) break;
/* Don't bail if impossible conversion is encountered */ /* Don't bail if impossible conversion is encountered */
in_ptr += (IS_JET3(mdb)) ? 1 : 2; in_ptr += (IS_JET3(mdb)) ? 1 : 2;

View File

@@ -60,6 +60,112 @@ char idx_to_text[] = {
0x81, 0x00, 0x00, 0x00, 'x', 0x00, 0x00, 0x00, /* 0xf8-0xff */ 0x81, 0x00, 0x00, 0x00, 'x', 0x00, 0x00, 0x00, /* 0xf8-0xff */
}; };
/* JET Red (v4) Index definition byte layouts
*
* Based on:
*
* http://jabakobob.net/mdb/table-page.html
* https://github.com/jahlborn/jackcess
*
* plus inspection of JET (Red) 4 databases. (JET 3 format has fewer
* fields -- some of the ones below omitted, and others narrower.)
*
* See also JET Blue (Extensible Storage Engine) format information:
*
* https://github.com/libyal/libesedb/blob/master/documentation/Extensible%20Storage%20Engine%20%28ESE%29%20Database%20File%20%28EDB%29%20format.asciidoc
*
* which is a later Microsoft embedded database format with the same
* early base format.
*
* ----------------------------------------------------------------------
* Index Column Definitions:
* - for each "non foreign key" index (ie pidx->index_type!=2), a list
* of columns indexed
*
* Repeated table->num_real_idxs times:
*
* Offset Bytes Meaning
* 0x0000 4 UNKNOWN; seems to be type marker, usually 1923 or 0
*
* 0x0004 2 Column 1 ID
* 0x0006 1 Column 1 Flags
* 0x0007 2 Column 2 ID
* 0x0009 1 Column 2 Flags
* 0x000A 2 Column 3 ID
* 0x000C 1 Column 3 Flags
* 0x000D 2 Column 4 ID
* 0x000F 1 Column 4 Flags
* 0x0010 2 Column 5 ID
* 0x0012 1 Column 5 Flags
* 0x0013 2 Column 6 ID
* 0x0015 1 Column 6 Flags
* 0x0016 2 Column 7 ID
* 0x0018 1 Column 7 Flags
* 0x0019 2 Column 8 ID
* 0x001B 1 Column 8 Flags
* 0x001C 2 Column 9 ID
* 0x001E 1 Column 9 Flags
* 0x001F 2 Column 10 ID
* 0x0021 1 Column 10 Flags
*
* 0x0022 1 Usage Map row
* 0x0023 3 Usage Map page (24-bit)
* 0x0026 4 First index page
* 0x002A 4 UNKNOWN
* 0x002E 2 Index Flags
* 0x0030 4 UNKNOWN; seems to always be 0
* 0x0034
*
* Column ID of 0xFFFF (-1) means "not used" or "end of used columns".
* Column Flags:
* - 0x01 = Ascending
*
* Index Flags:
* - 0x0001 = Unique index
* - 0x0002 = Ignore NULLs
* - 0x0008 = Required Index
*
* ----------------------------------------------------------------------
* Index Definitions
* - for each index (normal, primary key, foreign key), details on the
* index.
*
* - this appears to be the union of information required for normal/
* primary key indexes, and the information required for foreign key
* indexes.
*
* Repeated table->num_idxs times:
*
* Offset Bytes Meaning
* 0x0000 4 UNKNOWN; apparently a type marker, usually 1625 or 0
* 0x0004 4 Logical Index Number
* 0x0008 4 Index Column Definition Entry
* 0x000C 1 FK Index Type
* 0x000D 4 FK Index Number
* 0x0011 4 FK Index Table Page Number
* 0x0015 1 Flags: Update Action
* 0x0016 1 Flags: Delete Action
* 0x0017 1 Index Type
* 0x0018 4 UNKNNOWN; seems to always be 0
* 0x001B
*
* Where Index Type is:
* 0x01 = normal
* 0x01 = primary key
* 0x02 = foreign key index reference
*/
/* Debugging helper to dump out raw hex values of index definition */
/*
static void hexdump(unsigned char *tmpbuf, int size) {
int i;
for (i = 0; i < size; ++i) {
fprintf(stderr, "%02x ", tmpbuf[i]);
}
fprintf(stderr, "\n");
}
*/
GPtrArray * GPtrArray *
mdb_read_indices(MdbTableDef *table) mdb_read_indices(MdbTableDef *table)
@@ -86,14 +192,19 @@ mdb_read_indices(MdbTableDef *table)
type_offset = 23; type_offset = 23;
} }
//fprintf(stderr, "num_idxs:%d num_real_idxs:%d\n", table->num_idxs, table->num_real_idxs); /* Read in the definitions of table indexes, into table->indices */
/* num_real_idxs should be the number of indexes of type 2.
/* num_real_idxs should be the number of indexes other than type 2.
* It's not always the case. Happens on Northwind Orders table. * It's not always the case. Happens on Northwind Orders table.
*/ */
//fprintf(stderr, "num_idxs:%d num_real_idxs:%d\n", table->num_idxs, table->num_real_idxs);
table->num_real_idxs = 0; table->num_real_idxs = 0;
tmpbuf = (gchar *) g_malloc(idx2_sz); tmpbuf = (gchar *) g_malloc(idx2_sz);
for (i=0;i<table->num_idxs;i++) { for (i=0;i<table->num_idxs;i++) {
read_pg_if_n(mdb, tmpbuf, &cur_pos, idx2_sz); read_pg_if_n(mdb, tmpbuf, &cur_pos, idx2_sz);
//fprintf(stderr, "Index defn: ");
//hexdump((unsigned char *)tmpbuf, idx2_sz);
pidx = (MdbIndex *) g_malloc0(sizeof(MdbIndex)); pidx = (MdbIndex *) g_malloc0(sizeof(MdbIndex));
pidx->table = table; pidx->table = table;
pidx->index_num = mdb_get_int16(tmpbuf, 4); pidx->index_num = mdb_get_int16(tmpbuf, 4);
@@ -101,13 +212,15 @@ mdb_read_indices(MdbTableDef *table)
g_ptr_array_add(table->indices, pidx); g_ptr_array_add(table->indices, pidx);
/* /*
{ {
gint32 dumy0 = mdb_get_int32(tmpbuf, 0); gint32 idx_marker = mdb_get_int32(tmpbuf, 0);
gint8 dumy1 = tmpbuf[8]; gint32 index_col_def_num = mdb_get_int16(tmpbuf, 8);
gint32 dumy2 = mdb_get_int32(tmpbuf, 9); gint8 rel_idx_type = tmpbuf[0x0c];
gint32 dumy3 = mdb_get_int32(tmpbuf, 13); gint32 rel_idx_number = mdb_get_int32(tmpbuf, 0x0d);
gint16 dumy4 = mdb_get_int16(tmpbuf, 17); gint32 rel_idx_page = mdb_get_int32(tmpbuf, 0x11);
fprintf(stderr, "idx #%d: num2:%d type:%d\n", i, pidx->index_num, pidx->index_type); gint8 update_action_flags = tmpbuf[0x15];
fprintf(stderr, "idx #%d: %d %d %d %d %d\n", i, dumy0, dumy1, dumy2, dumy3, dumy4); gint8 delete_action_flags = tmpbuf[0x16];
fprintf(stderr, "idx #%d: num2:%d num3:%d type:%d\n", i, pidx->index_num, index_col_def_num, pidx->index_type);
fprintf(stderr, "idx #%d: %d %d %d %d %d/%d\n", i, idx_marker, rel_idx_type, rel_idx_number, rel_idx_page, update_action_flags, delete_action_flags);
}*/ }*/
if (pidx->index_type!=2) if (pidx->index_type!=2)
table->num_real_idxs++; table->num_real_idxs++;
@@ -115,6 +228,7 @@ mdb_read_indices(MdbTableDef *table)
//fprintf(stderr, "num_idxs:%d num_real_idxs:%d\n", table->num_idxs, table->num_real_idxs); //fprintf(stderr, "num_idxs:%d num_real_idxs:%d\n", table->num_idxs, table->num_real_idxs);
g_free(tmpbuf); g_free(tmpbuf);
/* Pick up the names of each index */
for (i=0;i<table->num_idxs;i++) { for (i=0;i<table->num_idxs;i++) {
pidx = g_ptr_array_index (table->indices, i); pidx = g_ptr_array_index (table->indices, i);
if (IS_JET3(mdb)) { if (IS_JET3(mdb)) {
@@ -129,10 +243,25 @@ mdb_read_indices(MdbTableDef *table)
//fprintf(stderr, "index %d type %d name %s\n", pidx->index_num, pidx->index_type, pidx->name); //fprintf(stderr, "index %d type %d name %s\n", pidx->index_num, pidx->index_type, pidx->name);
} }
/* Pick up the column definitions for normal/primary key indexes */
/* NOTE: Match should possibly be by index_col_def_num, rather
* than index_num; but in files encountered both seem to be the
* same (so left with index_num until a counter example is found).
*/
mdb_read_alt_pg(mdb, entry->table_pg); mdb_read_alt_pg(mdb, entry->table_pg);
mdb_read_pg(mdb, index_start_pg); mdb_read_pg(mdb, index_start_pg);
cur_pos = table->index_start; cur_pos = table->index_start;
for (i=0;i<table->num_real_idxs;i++) { for (i=0;i<table->num_real_idxs;i++) {
/* Debugging print out, commented out
{
gchar *tmpbuf = (gchar *) g_malloc(0x34);
int now_pos = cur_pos;
read_pg_if_n(mdb, tmpbuf, &now_pos, 0x34);
fprintf(stderr, "Index defn: ");
hexdump((unsigned char *)tmpbuf, 0x34);
g_free(tmpbuf);
}*/
if (!IS_JET3(mdb)) cur_pos += 4; if (!IS_JET3(mdb)) cur_pos += 4;
/* look for index number i */ /* look for index number i */
for (j=0; j<table->num_idxs; ++j) { for (j=0; j<table->num_idxs; ++j) {
@@ -152,12 +281,13 @@ mdb_read_indices(MdbTableDef *table)
/* /*
fprintf(stderr, "ridx block1 i:%d data1:0x%08x data2:0x%08x\n", fprintf(stderr, "ridx block1 i:%d data1:0x%08x data2:0x%08x\n",
i, i,
mdb_get_int32(mdb->pg_buf, (unsigned int)mdb_get_int32(mdb->pg_buf,
fmt->tab_cols_start_offset + pidx->index_num * fmt->tab_ridx_entry_size), fmt->tab_cols_start_offset + pidx->index_num * fmt->tab_ridx_entry_size),
mdb_get_int32(mdb->pg_buf, (unsigned int)mdb_get_int32(mdb->pg_buf,
fmt->tab_cols_start_offset + pidx->index_num * fmt->tab_ridx_entry_size +4)); fmt->tab_cols_start_offset + pidx->index_num * fmt->tab_ridx_entry_size +4));
fprintf(stderr, "pidx->num_rows:%d\n", pidx->num_rows);*/ fprintf(stderr, "pidx->num_rows:%d\n", pidx->num_rows);*/
/* Read columns in each index */
key_num=0; key_num=0;
for (j=0;j<MDB_MAX_IDX_COLS;j++) { for (j=0;j<MDB_MAX_IDX_COLS;j++) {
col_num=read_pg_if_16(mdb,&cur_pos); col_num=read_pg_if_16(mdb,&cur_pos);
@@ -190,12 +320,20 @@ mdb_read_indices(MdbTableDef *table)
} }
pidx->num_keys = key_num; pidx->num_keys = key_num;
cur_pos += 4; if (0) // DEBUGGING ONLY
//fprintf(stderr, "pidx->unknown_pre_first_pg:0x%08x\n", read_pg_if_32(mdb, &cur_pos)); {
gint32 usage_map = read_pg_if_32(mdb, &cur_pos);
fprintf(stderr, "pidx->unknown_pre_first_pg:0x%08x\n", usage_map);
} else {
cur_pos += 4; // Skip Usage map information
}
pidx->first_pg = read_pg_if_32(mdb, &cur_pos); pidx->first_pg = read_pg_if_32(mdb, &cur_pos);
if (!IS_JET3(mdb)) cur_pos += 4;
pidx->flags = read_pg_if_8(mdb, &cur_pos); pidx->flags = read_pg_if_8(mdb, &cur_pos);
//fprintf(stderr, "pidx->first_pg:%d pidx->flags:0x%02x\n", pidx->first_pg, pidx->flags); //fprintf(stderr, "pidx->first_pg:%d pidx->flags:0x%02x\n", pidx->first_pg, pidx->flags);
if (!IS_JET3(mdb)) cur_pos += 9; if (!IS_JET3(mdb)) cur_pos += 5;
} }
return NULL; return NULL;
} }

View File

@@ -84,6 +84,7 @@ typedef struct {
TypeInfo type_info[] = { TypeInfo type_info[] = {
{(SQLCHAR*)"text", SQL_VARCHAR, 255, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 255, SQL_VARCHAR, NULL, NULL, NULL}, {(SQLCHAR*)"text", SQL_VARCHAR, 255, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 255, SQL_VARCHAR, NULL, NULL, NULL},
{(SQLCHAR*)"memo", SQL_VARCHAR, 4096, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 4096, SQL_VARCHAR, NULL, NULL, NULL}, {(SQLCHAR*)"memo", SQL_VARCHAR, 4096, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 4096, SQL_VARCHAR, NULL, NULL, NULL},
{(SQLCHAR*)"ole", SQL_VARCHAR, MDB_BIND_SIZE, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, MDB_BIND_SIZE, SQL_VARCHAR, NULL, NULL, NULL},
{(SQLCHAR*)"text", SQL_CHAR, 255, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 255, SQL_CHAR, NULL, NULL, NULL}, {(SQLCHAR*)"text", SQL_CHAR, 255, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 255, SQL_CHAR, NULL, NULL, NULL},
{(SQLCHAR*)"numeric", SQL_NUMERIC, 255, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 255, SQL_NUMERIC, NULL, NULL, NULL}, {(SQLCHAR*)"numeric", SQL_NUMERIC, 255, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 255, SQL_NUMERIC, NULL, NULL, NULL},
{(SQLCHAR*)"numeric", SQL_DECIMAL, 255, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 255, SQL_DECIMAL, NULL, NULL, NULL}, {(SQLCHAR*)"numeric", SQL_DECIMAL, 255, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 255, SQL_DECIMAL, NULL, NULL, NULL},
@@ -1719,7 +1720,7 @@ static SQLRETURN SQL_API _SQLGetData(
break; break;
case SQL_C_LONG: case SQL_C_LONG:
case SQL_C_SLONG: case SQL_C_SLONG:
if (intValue<LONG_MIN || intValue>LONG_MAX) { if (intValue<INT_MIN || intValue>INT_MAX) {
strcpy(sqlState, "22003"); // Numeric value out of range strcpy(sqlState, "22003"); // Numeric value out of range
return SQL_ERROR; return SQL_ERROR;
} }
@@ -1779,35 +1780,48 @@ static SQLRETURN SQL_API _SQLGetData(
default: /* FIXME here we assume fCType == SQL_C_CHAR */ default: /* FIXME here we assume fCType == SQL_C_CHAR */
to_c_char: to_c_char:
{ {
char *str = mdb_col_to_string(mdb, mdb->pg_buf, static size_t len = 0;
col->cur_value_start, col->col_type, col->cur_value_len); static char *str = NULL;
int len = strlen(str);
if (col->col_type == MDB_OLE) {
if (stmt->pos == 0) {
str = mdb_ole_read_full(mdb, col, &len);
}
} else {
str = mdb_col_to_string(mdb, mdb->pg_buf,
col->cur_value_start, col->col_type, col->cur_value_len);
len = strlen(str);
}
if (stmt->pos >= len) { if (stmt->pos >= len) {
free(str); free(str);
str = NULL;
return SQL_NO_DATA; return SQL_NO_DATA;
} }
if (pcbValue) {
*pcbValue = len;
}
if (!cbValueMax) { if (!cbValueMax) {
if (pcbValue)
*pcbValue = len;
free(str); free(str);
str = NULL;
return SQL_SUCCESS_WITH_INFO; return SQL_SUCCESS_WITH_INFO;
} }
if (len - stmt->pos > cbValueMax) { if (len - stmt->pos > cbValueMax) {
/* the buffer we were given is too small, so /* the buffer we were given is too small, so
truncate it to the size of the buffer */ truncate it to the size of the buffer */
strncpy(rgbValue, str, cbValueMax); memcpy(rgbValue, str, cbValueMax);
if (pcbValue) stmt->pos += cbValueMax - 1;
*pcbValue = cbValueMax; if (col->col_type != MDB_OLE) { free(str); str = NULL; }
stmt->pos += cbValueMax;
free(str);
strcpy(sqlState, "01004"); // trunctated strcpy(sqlState, "01004"); // trunctated
return SQL_SUCCESS_WITH_INFO; return SQL_SUCCESS_WITH_INFO;
} }
strncpy(rgbValue, str + stmt->pos, len - stmt->pos);
memcpy(rgbValue, str + stmt->pos, len - stmt->pos);
if (pcbValue) if (pcbValue)
*pcbValue = len - stmt->pos; *pcbValue = len - stmt->pos;
stmt->pos += len - stmt->pos; stmt->pos += len - stmt->pos;
free(str); free(str);
str = NULL;
break; break;
} }
} }
@@ -2458,6 +2472,8 @@ static SQLSMALLINT _odbc_get_client_type(MdbColumn *col)
return SQL_TYPE_TIMESTAMP; return SQL_TYPE_TIMESTAMP;
#endif // returns text otherwise #endif // returns text otherwise
case MDB_TEXT: case MDB_TEXT:
case MDB_MEMO:
case MDB_OLE:
return SQL_VARCHAR; return SQL_VARCHAR;
default: default:
// fprintf(stderr,"Unknown type %d\n",srv_type); // fprintf(stderr,"Unknown type %d\n",srv_type);

View File

@@ -45,6 +45,7 @@ null { return NUL; }
(<=) { return LTEQ; } (<=) { return LTEQ; }
(>=) { return GTEQ; } (>=) { return GTEQ; }
like { return LIKE; } like { return LIKE; }
limit { return LIMIT; }
count { return COUNT; } count { return COUNT; }
strptime { return STRPTIME; } strptime { return STRPTIME; }
[ \t\r] ; [ \t\r] ;
@@ -53,6 +54,7 @@ strptime { return STRPTIME; }
yyless(yyleng-1); yyless(yyleng-1);
yymore(); yymore();
} }
\"[^"]*\" { \"[^"]*\" {
int ip, op, ilen; int ip, op, ilen;
ilen = strlen(yytext); ilen = strlen(yytext);

View File

@@ -422,7 +422,7 @@ mdb_sql_eval_expr(MdbSQL *sql, char *const1, int op, char *const2)
return 1; return 1;
} }
if (illop) { if (illop) {
mdb_sql_error(sql, "Illegal operator used for comparision of literals."); mdb_sql_error(sql, "Illegal operator used for comparison of literals.");
/* the column and table names are no good now */ /* the column and table names are no good now */
mdb_sql_reset(sql); mdb_sql_reset(sql);
return 1; return 1;
@@ -493,6 +493,17 @@ int mdb_sql_add_column(MdbSQL *sql, char *column_name)
sql->num_columns++; sql->num_columns++;
return 0; return 0;
} }
int mdb_sql_add_limit(MdbSQL *sql, char *limit)
{
sql->limit = atoi(limit);
return 0;
}
int mdb_sql_add_function1(MdbSQL *sql, char *func_name, char *arg1)
{
fprintf(stderr, "calling function %s with %s", func_name, arg1);
return 0;
}
int mdb_sql_add_table(MdbSQL *sql, char *table_name) int mdb_sql_add_table(MdbSQL *sql, char *table_name)
{ {
MdbSQLTable *t; MdbSQLTable *t;
@@ -575,6 +586,8 @@ void mdb_sql_reset(MdbSQL *sql)
sql->all_columns = 0; sql->all_columns = 0;
sql->sel_count = 0; sql->sel_count = 0;
sql->max_rows = -1; sql->max_rows = -1;
sql->row_count = 0;
sql->limit = 0;
} }
static void print_break(int sz, int first) static void print_break(int sz, int first)
{ {
@@ -865,7 +878,14 @@ mdb_sql_bind_all(MdbSQL *sql)
int int
mdb_sql_fetch_row(MdbSQL *sql, MdbTableDef *table) mdb_sql_fetch_row(MdbSQL *sql, MdbTableDef *table)
{ {
return mdb_fetch_row(table); int rc = mdb_fetch_row(table);
if (rc) {
if (sql->row_count + 1 > sql->limit) {
return 0;
}
sql->row_count++;
}
return rc;
} }
void void

View File

@@ -42,7 +42,7 @@ static MdbSQL *g_sql;
%token <name> IDENT NAME PATH STRING NUMBER %token <name> IDENT NAME PATH STRING NUMBER
%token SELECT FROM WHERE CONNECT DISCONNECT TO LIST TABLES AND OR NOT COUNT STRPTIME %token SELECT FROM WHERE CONNECT DISCONNECT TO LIST TABLES AND OR NOT LIMIT COUNT STRPTIME
%token DESCRIBE TABLE %token DESCRIBE TABLE
%token LTEQ GTEQ LIKE IS NUL %token LTEQ GTEQ LIKE IS NUL
@@ -60,7 +60,7 @@ stmt:
; ;
query: query:
SELECT column_list FROM table where_clause { SELECT column_list FROM table where_clause limit_clause {
mdb_sql_select(_mdb_sql(NULL)); mdb_sql_select(_mdb_sql(NULL));
} }
| CONNECT TO database { | CONNECT TO database {
@@ -82,6 +82,11 @@ where_clause:
| WHERE sarg_list | WHERE sarg_list
; ;
limit_clause:
/* empty */
| LIMIT NUMBER { mdb_sql_add_limit(_mdb_sql(NULL), $2); free($2); }
;
sarg_list: sarg_list:
sarg sarg
| '(' sarg_list ')' | '(' sarg_list ')'

14
src/util/mdb-export.c Normal file → Executable file
View File

@@ -89,10 +89,12 @@ main(int argc, char **argv)
char *escape_char = NULL; char *escape_char = NULL;
int header_row = 1; int header_row = 1;
int quote_text = 1; int quote_text = 1;
int boolean_words = 0;
char *insert_dialect = NULL; char *insert_dialect = NULL;
char *date_fmt = NULL; char *date_fmt = NULL;
char *namespace = NULL; char *namespace = NULL;
char *str_bin_mode = NULL; char *str_bin_mode = NULL;
char *null_text = NULL;
int bin_mode = MDB_BINEXPORT_RAW; int bin_mode = MDB_BINEXPORT_RAW;
char *value; char *value;
size_t length; size_t length;
@@ -107,7 +109,9 @@ main(int argc, char **argv)
{ "date_format", 'D', 0, G_OPTION_ARG_STRING, &date_fmt, "Set the date format (see strftime(3) for details)", "format"}, { "date_format", 'D', 0, G_OPTION_ARG_STRING, &date_fmt, "Set the date format (see strftime(3) for details)", "format"},
{ "escape", 'X', 0, G_OPTION_ARG_STRING, &escape_char, "Use <char> to escape quoted characters within a field. Default is doubling.", "format"}, { "escape", 'X', 0, G_OPTION_ARG_STRING, &escape_char, "Use <char> to escape quoted characters within a field. Default is doubling.", "format"},
{ "namespace", 'N', 0, G_OPTION_ARG_STRING, &namespace, "Prefix identifiers with namespace", "namespace"}, { "namespace", 'N', 0, G_OPTION_ARG_STRING, &namespace, "Prefix identifiers with namespace", "namespace"},
{ "null", '0', 0, G_OPTION_ARG_STRING, &null_text, "Use <char> to represent a NULL value", "char"},
{ "bin", 'b', 0, G_OPTION_ARG_STRING, &str_bin_mode, "Binary export mode", "strip|raw|octal"}, { "bin", 'b', 0, G_OPTION_ARG_STRING, &str_bin_mode, "Binary export mode", "strip|raw|octal"},
{ "boolean-words", 'B', 0, G_OPTION_ARG_NONE, &boolean_words, "Use TRUE/FALSE in Boolean fields (default is 0/1)", NULL},
{ NULL }, { NULL },
}; };
GError *error = NULL; GError *error = NULL;
@@ -154,6 +158,14 @@ main(int argc, char **argv)
if (date_fmt) if (date_fmt)
mdb_set_date_fmt(date_fmt); mdb_set_date_fmt(date_fmt);
if (null_text)
null_text = escapes(null_text);
else
null_text = g_strdup("");
if (boolean_words)
mdb_set_boolean_fmt_words();
if (str_bin_mode) { if (str_bin_mode) {
if (!strcmp(str_bin_mode, "strip")) if (!strcmp(str_bin_mode, "strip"))
bin_mode = MDB_BINEXPORT_STRIP; bin_mode = MDB_BINEXPORT_STRIP;
@@ -233,6 +245,8 @@ main(int argc, char **argv)
/* Don't quote NULLs */ /* Don't quote NULLs */
if (insert_dialect) if (insert_dialect)
fputs("NULL", outfile); fputs("NULL", outfile);
else
fputs(null_text, outfile);
} else { } else {
if (col->col_type == MDB_OLE) { if (col->col_type == MDB_OLE) {
value = mdb_ole_read_full(mdb, col, &length); value = mdb_ole_read_full(mdb, col, &length);

View File

@@ -253,7 +253,6 @@ dump_results(FILE *out, MdbSQL *sql, char *delimiter)
{ {
unsigned int j; unsigned int j;
MdbSQLColumn *sqlcol; MdbSQLColumn *sqlcol;
unsigned long row_count = 0;
if (headers) { if (headers) {
for (j=0;j<sql->num_columns-1;j++) { for (j=0;j<sql->num_columns-1;j++) {
@@ -266,8 +265,7 @@ dump_results(FILE *out, MdbSQL *sql, char *delimiter)
fprintf(out,"\n"); fprintf(out,"\n");
fflush(out); fflush(out);
} }
while(mdb_fetch_row(sql->cur_table)) { while(mdb_sql_fetch_row(sql, sql->cur_table)) {
row_count++;
for (j=0;j<sql->num_columns-1;j++) { for (j=0;j<sql->num_columns-1;j++) {
sqlcol = g_ptr_array_index(sql->columns,j); sqlcol = g_ptr_array_index(sql->columns,j);
fprintf(out, "%s%s", (char*)(sql->bound_values[j]), fprintf(out, "%s%s", (char*)(sql->bound_values[j]),
@@ -279,7 +277,7 @@ dump_results(FILE *out, MdbSQL *sql, char *delimiter)
fflush(out); fflush(out);
} }
if (footers) { if (footers) {
print_rows_retrieved(out, row_count); print_rows_retrieved(out, sql->row_count);
} }
} }
@@ -288,7 +286,6 @@ dump_results_pp(FILE *out, MdbSQL *sql)
{ {
unsigned int j; unsigned int j;
MdbSQLColumn *sqlcol; MdbSQLColumn *sqlcol;
unsigned long row_count = 0;
/* print header */ /* print header */
if (headers) { if (headers) {
@@ -316,8 +313,7 @@ dump_results_pp(FILE *out, MdbSQL *sql)
fflush(out); fflush(out);
/* print each row */ /* print each row */
while(mdb_fetch_row(sql->cur_table)) { while(mdb_sql_fetch_row(sql, sql->cur_table)) {
row_count++;
for (j=0;j<sql->num_columns;j++) { for (j=0;j<sql->num_columns;j++) {
sqlcol = g_ptr_array_index(sql->columns,j); sqlcol = g_ptr_array_index(sql->columns,j);
print_value(out, sql->bound_values[j],sqlcol->disp_size,!j); print_value(out, sql->bound_values[j],sqlcol->disp_size,!j);
@@ -334,7 +330,7 @@ dump_results_pp(FILE *out, MdbSQL *sql)
fprintf(out,"\n"); fprintf(out,"\n");
fflush(out); fflush(out);
if (footers) { if (footers) {
print_rows_retrieved(out, row_count); print_rows_retrieved(out, sql->row_count);
} }
} }