diff --git a/doc/mdb-export.txt b/doc/mdb-export.txt index e4bd0cb..01afe4c 100644 --- a/doc/mdb-export.txt +++ b/doc/mdb-export.txt @@ -13,7 +13,7 @@ OPTIONS -Q Don't wrap text-like fields (text, memo, date) in quotes. If not specified text fiels will be surrounded by " (double quote) characters. -d Specify an alternative column delimiter If no delimiter is specified, table names will be delimited by a , (comma) character. -R Specify a row delimiter - -I INSERT statements (instead of CSV) + -I INSERT statements (instead of CSV). You must specify the SQL dialect. -D Set the date format (see strftime(3) for details) -S Sanitize names (replace spaces etc. with underscore) -q Use to wrap text-like fields. Default is ". diff --git a/include/mdbtools.h b/include/mdbtools.h index 5508e9b..306ebce 100644 --- a/include/mdbtools.h +++ b/include/mdbtools.h @@ -167,6 +167,7 @@ typedef struct { typedef struct { MdbBackendType *types_table; + char* (*quote_name)(const char*); } MdbBackend; typedef struct { @@ -452,10 +453,11 @@ extern int mdb_read_row(MdbTableDef *table, unsigned int row); extern void buffer_dump(const void *buf, int start, size_t len); /* backend.c */ +extern char* sanitize_name(const char* name); extern char *mdb_get_coltype_string(MdbBackend *backend, int col_type); extern int mdb_coltype_takes_length(MdbBackend *backend, int col_type); extern void mdb_init_backends(); -extern void mdb_register_backend(MdbBackendType *backend, char *backend_name); +extern void mdb_register_backend(MdbBackendType *backend, char* (*quote_name)(const char*), char *backend_name); extern void mdb_remove_backends(); extern int mdb_set_default_backend(MdbHandle *mdb, const char *backend_name); extern char *mdb_get_relationships(MdbHandle *mdb); diff --git a/src/libmdb/backend.c b/src/libmdb/backend.c index dd45538..8bac6a6 100644 --- a/src/libmdb/backend.c +++ b/src/libmdb/backend.c @@ -143,6 +143,54 @@ static MdbBackendType mdb_mysql_types[] = { #ifndef JAVA static gboolean mdb_drop_backend(gpointer key, gpointer value, gpointer data); +char* sanitize_name(const char* str) +{ + char *result = malloc(256); + char *p = result; + + if (*str) { + *p = isalpha(*str) ? *str : '_'; + p++; + str++; + } + while (*str) { + *p = isalnum(*str) ? *str : '_'; + p++; + str++; + } + + *p = 0; + return result; +} + +static char* quote_name_with_brackets(const char* name) +{ + char *result = malloc(strlen(name)+3); + sprintf(result, "[%s]", name); + return result; +} + +static char* quote_name_with_dquotes(const char* name) +{ + char *result = malloc(2*strlen(name)+3); + char *p = result; + *p++ = '"'; + while (*name) { + *p++ = *name; + if (*name == '"') + *p++ = *name; /* double it */ + name ++; + } + *p++ = '"'; + *p++ = 0; + return result; +} + +static char* quote_name_with_rquotes(const char* name) +{ + return (char*)g_strconcat("`", name, "`", NULL); +} + char *mdb_get_coltype_string(MdbBackend *backend, int col_type) { static char buf[16]; @@ -171,16 +219,17 @@ void mdb_init_backends() { mdb_backends = g_hash_table_new(g_str_hash, g_str_equal); - mdb_register_backend(mdb_access_types, "access"); - mdb_register_backend(mdb_sybase_types, "sybase"); - mdb_register_backend(mdb_oracle_types, "oracle"); - mdb_register_backend(mdb_postgres_types, "postgres"); - mdb_register_backend(mdb_mysql_types, "mysql"); + mdb_register_backend(mdb_access_types, quote_name_with_brackets, "access"); + mdb_register_backend(mdb_sybase_types, quote_name_with_dquotes, "sybase"); + mdb_register_backend(mdb_oracle_types, quote_name_with_dquotes, "oracle"); + mdb_register_backend(mdb_postgres_types, quote_name_with_dquotes, "postgres"); + mdb_register_backend(mdb_mysql_types, quote_name_with_rquotes, "mysql"); } -void mdb_register_backend(MdbBackendType *backend_type, char *backend_name) +void mdb_register_backend(MdbBackendType *backend_type, char* (*quote_name)(const char*), char *backend_name) { MdbBackend *backend = (MdbBackend *) g_malloc0(sizeof(MdbBackend)); backend->types_table = backend_type; + backend->quote_name = quote_name; g_hash_table_insert(mdb_backends, backend_name, backend); } @@ -247,6 +296,9 @@ char *mdb_get_relationships(MdbHandle *mdb) static char *bound[4]; /* Bound values */ static MdbTableDef *table; /* Relationships table */ int backend = 0; /* Backends: 1=oracle */ + char *quoted_table_1, *quoted_column_1, + *quoted_table_2, *quoted_column_2, + *constraint_name, *quoted_constraint_name; if (strncmp(mdb->backend_name,"oracle",6) == 0) { backend = 1; @@ -296,10 +348,22 @@ char *mdb_get_relationships(MdbHandle *mdb) switch (backend) { case 1: /* oracle */ - text = g_strconcat("alter table ", bound[1], - " add constraint ", bound[3], "_", bound[1], - " foreign key (", bound[0], ")" - " references ", bound[3], "(", bound[2], ")", NULL); + quoted_table_1 = mdb->default_backend->quote_name(bound[1]); + quoted_column_1 = mdb->default_backend->quote_name(bound[0]); + quoted_table_2 = mdb->default_backend->quote_name(bound[3]); + quoted_column_2 = mdb->default_backend->quote_name(bound[2]); + constraint_name = g_strconcat(bound[3], "_", bound[1], NULL); + quoted_constraint_name = mdb->default_backend->quote_name(constraint_name); + free(constraint_name); + 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, ");", NULL); + free(quoted_table_1); + free(quoted_column_1); + free(quoted_table_2); + free(quoted_column_2); + free(quoted_constraint_name); break; } diff --git a/src/util/mdb-export.c b/src/util/mdb-export.c index 395d79e..a5ff4d5 100644 --- a/src/util/mdb-export.c +++ b/src/util/mdb-export.c @@ -28,7 +28,6 @@ #define is_text_type(x) (x==MDB_TEXT || x==MDB_MEMO || x==MDB_SDATETIME || x==MDB_BINARY) -static char *sanitize_name(char *str, int sanitize); static char *escapes(char *s); void @@ -71,11 +70,11 @@ main(int argc, char **argv) char *escape_char = NULL; char header_row = 1; char quote_text = 1; - char insert_statements = 0; + char *insert_dialect = NULL; char sanitize = 0; int opt; - while ((opt=getopt(argc, argv, "HQq:X:d:D:R:IS"))!=-1) { + while ((opt=getopt(argc, argv, "HQq:X:d:D:R:I:S"))!=-1) { switch (opt) { case 'H': header_row = 0; @@ -93,7 +92,7 @@ main(int argc, char **argv) row_delimiter = escapes(optarg); break; case 'I': - insert_statements = 1; + insert_dialect = (char*) g_strdup(optarg); header_row = 0; break; case 'S': @@ -130,7 +129,7 @@ main(int argc, char **argv) fprintf(stderr," -Q don't wrap text-like fields in quotes\n"); fprintf(stderr," -d specify a column delimiter\n"); fprintf(stderr," -R specify a row delimiter\n"); - fprintf(stderr," -I INSERT statements (instead of CSV)\n"); + fprintf(stderr," -I INSERT statements (instead of CSV)\n"); fprintf(stderr," -D set the date format (see strftime(3) for details)\n"); fprintf(stderr," -S Sanitize names (replace spaces etc. with underscore)\n"); fprintf(stderr," -q Use to wrap text-like fields. Default is \".\n"); @@ -153,6 +152,13 @@ main(int argc, char **argv) exit(1); } + if (insert_dialect) + if (!mdb_set_default_backend(mdb, insert_dialect)) { + fprintf(stderr, "Invalid backend type\n"); + mdb_exit(); + exit(1); + } + table = mdb_read_table_by_name(mdb, argv[argc-1], MDB_TABLE); if (!table) { fprintf(stderr, "Error: Table %s does not exist in this database.\n", argv[argc-1]); @@ -175,25 +181,34 @@ main(int argc, char **argv) mdb_bind_column(table, j+1, bound_values[j], &bound_lens[j]); } if (header_row) { - col=g_ptr_array_index(table->columns,0); - fprintf(stdout,"%s",sanitize_name(col->name,sanitize)); - for (j=1;jnum_cols;j++) { + for (j=0; jnum_cols; j++) { col=g_ptr_array_index(table->columns,j); - fprintf(stdout,delimiter); - fprintf(stdout,"%s",sanitize_name(col->name,sanitize)); + if (j) + fprintf(stdout,delimiter); + fprintf(stdout,"%s", sanitize ? sanitize_name(col->name) : col->name); } fprintf(stdout,"\n"); } while(mdb_fetch_row(table)) { - if (insert_statements) { - fprintf(stdout, "INSERT INTO %s (", - sanitize_name(argv[optind + 1],sanitize)); + if (insert_dialect) { + char *quoted_name; + if (sanitize) + quoted_name = sanitize_name(argv[optind + 1]); + else + quoted_name = mdb->default_backend->quote_name(argv[optind + 1]); + fprintf(stdout, "INSERT INTO %s (", quoted_name); + free(quoted_name); for (j=0;jnum_cols;j++) { if (j>0) fprintf(stdout, ", "); col=g_ptr_array_index(table->columns,j); - fprintf(stdout,"%s", sanitize_name(col->name,sanitize)); + if (sanitize) + quoted_name = sanitize_name(col->name); + else + quoted_name = mdb->default_backend->quote_name(col->name); + fprintf(stdout,"%s", quoted_name); + free(quoted_name); } fprintf(stdout, ") VALUES ("); } @@ -208,12 +223,12 @@ main(int argc, char **argv) fprintf(stdout,delimiter); } if (!bound_lens[j]) { - print_col(insert_statements?"NULL":"",0,col->col_type, quote_char, escape_char); + print_col(insert_dialect?"NULL":"",0,col->col_type, quote_char, escape_char); } else { print_col(bound_values[j], quote_text, col->col_type, quote_char, escape_char); } } - if (insert_statements) fprintf(stdout,")"); + if (insert_dialect) fprintf(stdout,");"); fprintf(stdout, row_delimiter); } for (j=0;jnum_cols;j++) { @@ -233,25 +248,6 @@ main(int argc, char **argv) exit(0); } -static char *sanitize_name(char *str, int sanitize) -{ - static char namebuf[256]; - char *p = namebuf; - - if (!sanitize) - return str; - - while (*str) { - *p = isalnum(*str) ? *str : '_'; - p++; - str++; - } - - *p = 0; - - return namebuf; -} - static char *escapes(char *s) { char *d = (char *) g_strdup(s); diff --git a/src/util/mdb-schema.c b/src/util/mdb-schema.c index 012bb2f..6fd36db 100644 --- a/src/util/mdb-schema.c +++ b/src/util/mdb-schema.c @@ -24,7 +24,6 @@ #include "dmalloc.h" #endif -static char *sanitize_name(char *str, int sanitize); static void generate_table_schema(MdbCatalogEntry *entry, char *namespace, int sanitize); int @@ -128,16 +127,32 @@ generate_table_schema(MdbCatalogEntry *entry, char *namespace, int sanitize) MdbHandle *mdb = entry->mdb; unsigned int i; MdbColumn *col; + char* table_name; + char* quoted_name; + + if (namespace) { + table_name = malloc(strlen(namespace)+strlen(entry->object_name)+1); + strcpy(table_name, namespace); + strcat(table_name, entry->object_name); + } else + { + table_name = strdup(entry->object_name); + } + if (sanitize) + quoted_name = sanitize_name(table_name); + else + quoted_name = mdb->default_backend->quote_name(table_name); + free(table_name); /* drop the table if it exists */ - fprintf (stdout, "DROP TABLE %s%s;\n", (namespace) ? namespace : "", - sanitize_name(entry->object_name, sanitize)); + fprintf (stdout, "DROP TABLE %s;\n", quoted_name); /* create the table */ - fprintf (stdout, "CREATE TABLE %s%s\n", (namespace) ? namespace : "", - sanitize_name(entry->object_name, sanitize)); + fprintf (stdout, "CREATE TABLE %s\n", quoted_name); fprintf (stdout, " (\n"); - + + free(quoted_name); + table = mdb_read_table (entry); /* get the columns */ @@ -147,9 +162,14 @@ generate_table_schema(MdbCatalogEntry *entry, char *namespace, int sanitize) for (i = 0; i < table->num_cols; i++) { col = g_ptr_array_index (table->columns, i); - - fprintf (stdout, "\t%s\t\t\t%s", sanitize_name(col->name,sanitize), - mdb_get_coltype_string (mdb->default_backend, col->col_type)); + + if (sanitize) + quoted_name = sanitize_name(col->name); + else + quoted_name = mdb->default_backend->quote_name(col->name); + fprintf (stdout, "\t%s\t\t\t%s", quoted_name, + mdb_get_coltype_string (mdb->default_backend, col->col_type)); + free(quoted_name); if (mdb_coltype_takes_length(mdb->default_backend, col->col_type)) { @@ -173,23 +193,3 @@ generate_table_schema(MdbCatalogEntry *entry, char *namespace, int sanitize) mdb_free_tabledef (table); } - -static char *sanitize_name(char *str, int sanitize) -{ - static char namebuf[256]; - char *p = namebuf; - - if (!sanitize) - return str; - - while (*str) { - *p = isalnum(*str) ? *str : '_'; - p++; - str++; - } - - *p = 0; - - return namebuf; -} -