mirror of
https://github.com/mdbtools/mdbtools.git
synced 2025-11-25 17:59:54 +08:00
Merge branch 'master' into master
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
2
HACKING
2
HACKING
@@ -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
2
README
@@ -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).
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
14
src/util/mdb-export.c
Normal file → Executable 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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user