mdb-export: handle MySQL blobs (#250)

* Refactor code so BLOBs are always correctly exported

Previously, BLOBs weren't exported from mdb-export correctly if the
backend had MDB_SHEXP_BULK_INSERT set.

* Export MySQL BLOBs correctly

MySQL BLOBs should be in the form 0x[hex values] when inserting them
with the mysql command line tool.

* MySQL needs a BLOB to store exported MDB_OLE values

MDB_OLE size always comes out as 256 bytes, but varbinary(256) is insufficient
to hold all possible OLE data.
This commit is contained in:
James Woodcock 2021-02-03 19:48:56 +00:00 committed by GitHub
parent 763716ecc6
commit a980d73447
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 45 additions and 21 deletions

View File

@ -114,7 +114,7 @@ static const MdbBackendType mdb_mysql_types[] = {
[MDB_DATETIME] = { .name = "datetime" }, [MDB_DATETIME] = { .name = "datetime" },
[MDB_BINARY] = { .name = "blob" }, [MDB_BINARY] = { .name = "blob" },
[MDB_TEXT] = { .name = "varchar", .needs_char_length = 1 }, [MDB_TEXT] = { .name = "varchar", .needs_char_length = 1 },
[MDB_OLE] = { .name = "varbinary", .needs_byte_length = 1 }, [MDB_OLE] = { .name = "blob" },
[MDB_MEMO] = { .name = "text" }, [MDB_MEMO] = { .name = "text" },
[MDB_REPID] = { .name = "char(38)" }, [MDB_REPID] = { .name = "char(38)" },
[MDB_NUMERIC] = { .name = "numeric", .needs_precision = 1, .needs_scale = 1 }, [MDB_NUMERIC] = { .name = "numeric", .needs_precision = 1, .needs_scale = 1 },

View File

@ -24,6 +24,7 @@
#define is_binary_type(x) (x==MDB_OLE || x==MDB_BINARY || x==MDB_REPID) #define is_binary_type(x) (x==MDB_OLE || x==MDB_BINARY || x==MDB_REPID)
static char *escapes(char *s); static char *escapes(char *s);
static void format_value(FILE *outfile, char *value, size_t length, int quote_text, int col_type, char *escape_char, char *quote_char, int bin_mode, int export_flags, char *backend_name);
int int
main(int argc, char **argv) main(int argc, char **argv)
@ -256,7 +257,11 @@ main(int argc, char **argv)
value = bound_values[i]; value = bound_values[i];
length = bound_lens[i]; length = bound_lens[i];
} }
mdb_print_col(outfile, value, quote_text, col->col_type, length, quote_char, escape_char, bin_mode | export_flags); format_value(outfile, value, length,
quote_text, col->col_type,
escape_char, quote_char,
bin_mode, export_flags,
mdb->backend_name);
if (col->col_type == MDB_OLE) if (col->col_type == MDB_OLE)
free(value); free(value);
} }
@ -308,25 +313,11 @@ main(int argc, char **argv)
value = bound_values[i]; value = bound_values[i];
length = bound_lens[i]; length = bound_lens[i];
} }
/* Correctly handle insertion of binary blobs into SQLite using the string literal notation of X'1234ABCD...' */ format_value(outfile, value, length,
if (!strcmp(mdb->backend_name, "sqlite") && is_binary_type(col->col_type) quote_text, col->col_type,
&& bin_mode == MDB_BINEXPORT_HEXADECIMAL) { escape_char, quote_char,
char *quote_char_binary_sqlite = (char *) g_strdup("'"); bin_mode, export_flags,
fputs("X", outfile); mdb->backend_name);
mdb_print_col(outfile, value, quote_text, col->col_type, length, quote_char_binary_sqlite, escape_char, bin_mode | export_flags);
g_free (quote_char_binary_sqlite);
/* Correctly handle insertion of binary blobs into PostgreSQL using the notation of decode('1234ABCD...', 'hex') */
} else if (!strcmp(mdb->backend_name, "postgres") && is_binary_type(col->col_type)
&& bin_mode == MDB_BINEXPORT_HEXADECIMAL) {
char *quote_char_binary_postgres = (char *) g_strdup("'");
fputs("decode(", outfile);
mdb_print_col(outfile, value, quote_text, col->col_type, length, quote_char_binary_postgres, escape_char, bin_mode | export_flags);
fputs(", 'hex')", outfile);
g_free (quote_char_binary_postgres);
/* No special treatment for other backends or when hexadecimal notation hasn't been selected with the -b hex command line option */
} else {
mdb_print_col(outfile, value, quote_text, col->col_type, length, quote_char, escape_char, bin_mode | export_flags);
}
if (col->col_type == MDB_OLE) if (col->col_type == MDB_OLE)
free(value); free(value);
} }
@ -360,6 +351,39 @@ main(int argc, char **argv)
return 0; return 0;
} }
static void format_value(FILE *outfile, char *value, size_t length, int quote_text, int col_type, char *escape_char, char *quote_char, int bin_mode, int export_flags, char *backend_name)
{
/* Correctly handle insertion of binary blobs into sqlite3 using the notation of X'1234ABCD...') */
if (!strcmp(backend_name, "sqlite")
&& is_binary_type(col_type)
&& bin_mode == MDB_BINEXPORT_HEXADECIMAL) {
char *quote_char_binary_sqlite = (char *) g_strdup("'");
fputs("X", outfile);
mdb_print_col(outfile, value, quote_text, col_type, length, quote_char_binary_sqlite, escape_char, bin_mode | export_flags);
g_free (quote_char_binary_sqlite);
/* Correctly handle insertion of binary blobs into MySQL using the notation of 0x1234ABCD...) */
} else if (!strcmp(backend_name, "mysql")
&& is_binary_type(col_type)
&& bin_mode == MDB_BINEXPORT_HEXADECIMAL) {
char *quote_char_binary_sqlite = (char *) g_strdup("");
fputs("0x", outfile);
mdb_print_col(outfile, value, quote_text, col_type, length, quote_char_binary_sqlite, escape_char, bin_mode | export_flags);
g_free (quote_char_binary_sqlite);
/* Correctly handle insertion of binary blobs into PostgreSQL using the notation of decode('1234ABCD...', 'hex') */
} else if (!strcmp(backend_name, "postgres")
&& is_binary_type(col_type)
&& bin_mode == MDB_BINEXPORT_HEXADECIMAL) {
char *quote_char_binary_postgres = (char *) g_strdup("'");
fputs("decode(", outfile);
mdb_print_col(outfile, value, quote_text, col_type, length, quote_char_binary_postgres, escape_char, bin_mode | export_flags);
fputs(", 'hex')", outfile);
g_free (quote_char_binary_postgres);
/* No special treatment for other backends or when hexadecimal notation hasn't been selected with the -b hex command line option */
} else {
mdb_print_col(outfile, value, quote_text, col_type, length, quote_char, escape_char, bin_mode | export_flags);
}
}
static char *escapes(char *s) static char *escapes(char *s)
{ {
char *d = (char *) g_strdup(s); char *d = (char *) g_strdup(s);