diff --git a/include/mdbtools.h b/include/mdbtools.h index 9ba3c69..bd3c582 100644 --- a/include/mdbtools.h +++ b/include/mdbtools.h @@ -151,6 +151,15 @@ enum { MDB_IDX_REQUIRED = 0x08 }; +/* export schema options */ +enum { + MDB_SHEXP_DROPTABLE = 0x01, + MDB_SHEXP_INDEXES = 0x02, + MDB_SHEXP_RELATIONS = 0x04, + MDB_SHEXP_SANITIZE = 0x08 +}; +#define MDB_SHEXP_DEFAULT (MDB_SHEXP_DROPTABLE | MDB_SHEXP_INDEXES | MDB_SHEXP_RELATIONS) + #define IS_JET4(mdb) (mdb->f->jet_version==MDB_VER_JET4) #define IS_JET3(mdb) (mdb->f->jet_version==MDB_VER_JET3) @@ -462,8 +471,7 @@ extern void mdb_init_backends(); 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_sequences(MdbCatalogEntry *entry, char *namespace, int sanitize); -extern char *mdb_get_relationships(MdbHandle *mdb); +extern void mdb_print_schema(MdbHandle *mdb, FILE *outfile, char *tabname, char *namespace, guint32 export_options); /* sargs.c */ extern int mdb_test_sargs(MdbTableDef *table, MdbField *fields, int num_fields); diff --git a/src/gmdb2/schema.c b/src/gmdb2/schema.c index e416daf..1b805ce 100644 --- a/src/gmdb2/schema.c +++ b/src/gmdb2/schema.c @@ -26,10 +26,11 @@ extern MdbHandle *mdb; GladeXML *schemawin_xml; static gchar backend[100]; -static gchar tabname[100]; -static gchar file_path[256]; +static gchar tabname[MDB_MAX_OBJ_NAME+1]; +static gchar file_path[PATH_MAX+1]; static gchar relation; static gchar drops; +static guint32 export_options; #define ALL_TABLES "(All Tables)" @@ -37,18 +38,6 @@ static void gmdb_schema_export() { FILE *outfile; -MdbTableDef *table; -MdbCatalogEntry *entry; -MdbColumn *col; -int i,k; -int need_headers = 0; -int need_quote = 0; -gchar delimiter[11]; -gchar quotechar; -gchar lineterm[5]; -gchar *str; -int rows=0; -char *the_relation; GtkWidget *dlg; @@ -63,62 +52,7 @@ char *the_relation; } mdb_set_default_backend(mdb,backend); - for (i=0; i < mdb->num_catalog; i++) { - entry = g_ptr_array_index (mdb->catalog, i); - - if (entry->object_type != MDB_TABLE) - continue; - /* Do not show system tables if table name is not specified */ - if (mdb_is_system_table(entry) && !strlen(tabname)) - continue; - /* If object name does not match the table specified */ - if (strlen(tabname) && strcmp(entry->object_name, tabname)) - continue; - - /* drop the table if it exists */ - if (drops=='Y') - fprintf(outfile, "DROP TABLE %s;\n", entry->object_name); - - /* create the table */ - fprintf (outfile, "CREATE TABLE %s\n", entry->object_name); - fprintf (outfile, " (\n"); - - table = mdb_read_table (entry); - - /* get the columns */ - mdb_read_columns (table); - - /* loop over the columns, dumping the names and types */ - - for (k = 0; k < table->num_cols; k++) { - col = g_ptr_array_index (table->columns, k); - - fprintf (outfile, "\t%s\t\t\t%s", col->name, - mdb_get_coltype_string (mdb->default_backend, col->col_type)); - - if (col->col_size != 0) - fprintf (outfile, " (%d)", col->col_size); - - if (k < table->num_cols - 1) - fprintf (outfile, ", \n"); - else - fprintf (outfile, "\n"); - } - - fprintf (outfile, "\n);\n"); - fprintf (outfile, "-- CREATE ANY INDEXES ...\n"); - fprintf (outfile, "\n"); - } - fprintf (outfile, "\n\n"); - - if (relation=='Y') { - fprintf (outfile, "-- CREATE ANY Relationships ...\n"); - fprintf (outfile, "\n"); - while ((the_relation=mdb_get_relationships(mdb)) != NULL) { - fprintf(outfile,"%s\n",the_relation); - g_free(the_relation); - } - } + mdb_print_schema(mdb, outfile, *tabname?tabname:NULL, NULL, export_options); fclose(outfile); dlg = gtk_message_dialog_new (NULL, @@ -135,10 +69,14 @@ GtkWidget *schemawin, *combo, *checkbox, *entry; schemawin = glade_xml_get_widget (schemawin_xml, "schema_dialog"); entry = glade_xml_get_widget (schemawin_xml, "filename_entry"); - strncpy(file_path,gtk_entry_get_text(GTK_ENTRY(entry)),255); + strncpy(file_path,gtk_entry_get_text(GTK_ENTRY(entry)),PATH_MAX); + file_path[PATH_MAX]=0; + combo = glade_xml_get_widget (schemawin_xml, "table_combo"); - strncpy(tabname,gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry)),99); + strncpy(tabname,gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry)),MDB_MAX_OBJ_NAME); + tabname[MDB_MAX_OBJ_NAME]=0; if (!strcmp(tabname,ALL_TABLES)) tabname[0]='\0'; + combo = glade_xml_get_widget (schemawin_xml, "backend_combo"); if (!strcmp(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry)),"Oracle")) strcpy(backend,"oracle"); else if (!strcmp(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry)),"Sybase")) strcpy(backend,"sybase"); @@ -146,17 +84,16 @@ GtkWidget *schemawin, *combo, *checkbox, *entry; else if (!strcmp(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry)),"PostgreSQL")) strcpy(backend,"postgres"); else if (!strcmp(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry)),"MySQL")) strcpy(backend,"mysql"); else strcpy(backend,"access"); + + export_options = MDB_SHEXP_DEFAULT & ~ (MDB_SHEXP_RELATIONS|MDB_SHEXP_DROPTABLE); checkbox = glade_xml_get_widget (schemawin_xml, "rel_checkbox"); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox))) - relation = 'Y'; - else - relation = 'N'; + export_options |= MDB_SHEXP_RELATIONS; checkbox = glade_xml_get_widget (schemawin_xml, "drop_checkbox"); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox))) - drops = 'Y'; - else - drops = 'N'; - //printf("%s %s %c\n",tabname,backend,relation); + export_options |= MDB_SHEXP_DROPTABLE; + // TODO add support for other options + //printf("%s %s %02X\n",tabname,backend,export_options); gtk_widget_destroy(schemawin); gmdb_schema_export(); diff --git a/src/libmdb/backend.c b/src/libmdb/backend.c index bfe6325..99092f0 100644 --- a/src/libmdb/backend.c +++ b/src/libmdb/backend.c @@ -279,7 +279,9 @@ int mdb_set_default_backend(MdbHandle *mdb, const char *backend_name) /** * mdb_get_sequences - * @mdb: Handle to open MDB database file + * @entry: Handle to open MDB database file + * @namespace: Prefix for output names + * @sanitize: Remove weird characters if true * * Generates sequences and set default values * @@ -289,7 +291,8 @@ int mdb_set_default_backend(MdbHandle *mdb, const char *backend_name) * Returns NULL on last iteration. * The caller is responsible for freeing this string. */ -char *mdb_get_sequences(MdbCatalogEntry *entry, char *namespace, int sanitize) +static char * +mdb_get_sequences(MdbCatalogEntry *entry, char *namespace, int sanitize) { MdbTableDef *table; MdbHandle *mdb = entry->mdb; @@ -311,8 +314,8 @@ char *mdb_get_sequences(MdbCatalogEntry *entry, char *namespace, int sanitize) backend = 2; } else { return (char *) g_strconcat( - "-- sequences are not supported for ", - mdb->backend_name, NULL); + "-- sequences are not implemented for ", + mdb->backend_name, "\n", NULL); } /* get the columns */ @@ -360,9 +363,90 @@ char *mdb_get_sequences(MdbCatalogEntry *entry, char *namespace, int sanitize) } +/** + * mdb_print_indexes + * @output: Where to print the sql + * @table: Table to process + */ +static void +mdb_print_indexes(FILE* outfile, MdbTableDef *table, char *namespace, int sanitize) +{ + unsigned int i, j; + char* quoted_table_name; + char* index_name; + char* quoted_name; + MdbHandle* mdb = table->entry->mdb; + MdbIndex *idx; + MdbColumn *col; + + if (strcmp(mdb->backend_name, "postgres")) { + fprintf(outfile, "-- Indexes are not implemented for %s\n\n", mdb->backend_name); + return; + } + + /* read indexes */ + mdb_read_indices(table); + + fprintf (outfile, "-- CREATE ANY INDEXES ...\n"); + + if (sanitize) + quoted_table_name = sanitize_name(table->name); + else + quoted_table_name = mdb->default_backend->quote_name(table->name); + + for (i=0;inum_idxs;i++) { + idx = g_ptr_array_index (table->indices, i); + if (idx->index_type==2) + continue; + + index_name = malloc(strlen(table->name)+strlen(idx->name)+4+1); + strcpy(index_name, table->name); + strcat(index_name, idx->name); + if (idx->index_type==1) + strcat(index_name, "_pk"); + else + strcat(index_name, "_idx"); + if (sanitize) + quoted_name = sanitize_name(index_name); + else + quoted_name = mdb->default_backend->quote_name(index_name); + if (idx->index_type==1) { + fprintf (outfile, "ALTER TABLE %s ADD CONSTRAINT %s PRIMARY KEY (", quoted_table_name, quoted_name); + } else { + fprintf(outfile, "CREATE"); + if (idx->flags & MDB_IDX_UNIQUE) + fprintf (outfile, " UNIQUE"); + fprintf(outfile, " INDEX %s ON %s (", quoted_name, quoted_table_name); + } + free(quoted_name); + free(index_name); + + for (j=0;jnum_keys;j++) { + if (j) + fprintf(outfile, ", "); + col=g_ptr_array_index(table->columns,idx->key_col_num[j]-1); + if (sanitize) + quoted_name = sanitize_name(col->name); + else + quoted_name = mdb->default_backend->quote_name(col->name); + fprintf (outfile, "%s", quoted_name); + if (idx->index_type!=1 && idx->key_col_order[j]) + /* no DESC for primary keys */ + fprintf(outfile, " DESC"); + + free(quoted_name); + + } + fprintf (outfile, ");\n"); + } + fprintf (outfile, "\n"); + fprintf (outfile, "\n"); +} + /** * mdb_get_relationships * @mdb: Handle to open MDB database file + * @tablename: Name of the table to process. Process all tables if NULL. * * Generates relationships by reading the MSysRelationships table. * 'szColumn' contains the column name of the child table. @@ -377,7 +461,8 @@ char *mdb_get_sequences(MdbCatalogEntry *entry, char *namespace, int sanitize) * Returns NULL on last iteration. * The caller is responsible for freeing this string. */ -char *mdb_get_relationships(MdbHandle *mdb) +static char * +mdb_get_relationships(MdbHandle *mdb, const char* tablename) { unsigned int i; gchar *text = NULL; /* String to be returned */ @@ -386,7 +471,6 @@ char *mdb_get_relationships(MdbHandle *mdb) int backend = 0; /* Backends: 1=oracle, 2=postgres */ char *quoted_table_1, *quoted_column_1, *quoted_table_2, *quoted_column_2, - *index_name, *quoted_index_name, *constraint_name, *quoted_constraint_name; long grbit; @@ -398,8 +482,8 @@ char *mdb_get_relationships(MdbHandle *mdb) if (is_init == 0) { /* the first time through */ is_init = 1; return (char *) g_strconcat( - "-- relationships are not supported for ", - mdb->backend_name, NULL); + "-- relationships are not implemented for ", + mdb->backend_name, "\n", NULL); } else { /* the second time through */ is_init = 0; return NULL; @@ -438,11 +522,15 @@ char *mdb_get_relationships(MdbHandle *mdb) } } - if (!mdb_fetch_row(table)) { - for (i=0;i<5;i++) - g_free(bound[i]); - is_init = 0; - return NULL; + while (1) { + if (!mdb_fetch_row(table)) { + for (i=0;i<5;i++) + g_free(bound[i]); + is_init = 0; + return NULL; + } + if (!tablename || !strcmp(bound[1], tablename)) + break; } quoted_table_1 = mdb->default_backend->quote_name(bound[1]); @@ -453,9 +541,6 @@ char *mdb_get_relationships(MdbHandle *mdb) constraint_name = g_strconcat(bound[1], "_", bound[0], "_fk", NULL); quoted_constraint_name = mdb->default_backend->quote_name(constraint_name); free(constraint_name); - index_name = g_strconcat(bound[3], "_", bound[2], "_idx", NULL); - quoted_index_name = mdb->default_backend->quote_name(index_name); - free(index_name); if (grbit & 0x00000002) { text = g_strconcat( @@ -484,8 +569,132 @@ char *mdb_get_relationships(MdbHandle *mdb) free(quoted_table_2); free(quoted_column_2); free(quoted_constraint_name); - free(quoted_index_name); return (char *)text; } + +static void +generate_table_schema(FILE *outfile, MdbCatalogEntry *entry, char *namespace, guint32 export_options) +{ + MdbTableDef *table; + MdbHandle *mdb = entry->mdb; + MdbColumn *col; + unsigned int i; + char* table_name; + char* quoted_table_name; + char* quoted_name; + char* sql_sequences; + int sanitize = export_options & MDB_SHEXP_SANITIZE; + + if (sanitize) + quoted_table_name = sanitize_name(entry->object_name); + else + quoted_table_name = mdb->default_backend->quote_name(entry->object_name); + + if (namespace) { + table_name = malloc(strlen(namespace)+strlen(quoted_table_name)+1); + strcpy(table_name, namespace); + strcat(table_name, quoted_table_name); + free(quoted_table_name); + quoted_table_name = table_name; + } + + /* drop the table if it exists */ + if (export_options & MDB_SHEXP_DROPTABLE) + fprintf (outfile, "DROP TABLE %s;\n", quoted_table_name); + + /* create the table */ + fprintf (outfile, "CREATE TABLE %s\n", quoted_table_name); + fprintf (outfile, " (\n"); + + table = mdb_read_table (entry); + + /* get the columns */ + mdb_read_columns (table); + + /* loop over the columns, dumping the names and types */ + + for (i = 0; i < table->num_cols; i++) { + col = g_ptr_array_index (table->columns, i); + + if (sanitize) + quoted_name = sanitize_name(col->name); + else + quoted_name = mdb->default_backend->quote_name(col->name); + fprintf (outfile, "\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)) { + + /* more portable version from DW patch */ + if (col->col_size == 0) + fputs(" (255)", outfile); + else + fprintf(outfile, " (%d)", col->col_size); + } + + if (i < table->num_cols - 1) + fputs(", \n", outfile); + else + fputs("\n", outfile); + } /* for */ + + fputs(");\n", outfile); + + fputs("-- CREATE SEQUENCES ...\n", outfile); + fputs("\n", outfile); + while ((sql_sequences = mdb_get_sequences(entry, namespace, sanitize))) { + fputs(sql_sequences, outfile); + free(sql_sequences); + } + + if (export_options & MDB_SHEXP_INDEXES) + // prints all the indexes of that table + mdb_print_indexes(outfile, table, namespace, sanitize); + + free(quoted_table_name); + + mdb_free_tabledef (table); +} + + +void +mdb_print_schema(MdbHandle *mdb, FILE *outfile, char *tabname, char *namespace, guint32 export_options) +{ + unsigned int i; + char *the_relation; + MdbCatalogEntry *entry; + + /* Print out a little message to show that this came from mdb-tools. + I like to know how something is generated. DW */ + fputs("-------------------------------------------------------------\n" + "-- MDB Tools - A library for reading MS Access database files\n" + "-- Copyright (C) 2000-2011 Brian Bruns and others.\n" + "-- Files in libmdb are licensed under LGPL and the utilities under\n" + "-- the GPL, see COPYING.LIB and COPYING files respectively.\n" + "-- Check out http://mdbtools.sourceforge.net\n" + "-------------------------------------------------------------\n\n", + outfile); + + for (i=0; i < mdb->num_catalog; i++) { + entry = g_ptr_array_index (mdb->catalog, i); + if (entry->object_type == MDB_TABLE) { + if ((tabname && !strcmp(entry->object_name, tabname)) + || (!tabname && mdb_is_user_table(entry))) { + generate_table_schema(outfile, entry, namespace, export_options); + } + } + } + fprintf (outfile, "\n"); + + if (export_options & MDB_SHEXP_RELATIONS) { + fputs ("-- CREATE Relationships ...\n", outfile); + while ((the_relation=mdb_get_relationships(mdb, tabname)) != NULL) { + fputs(the_relation, outfile); + g_free(the_relation); + } + } +} #endif diff --git a/src/util/mdb-schema.c b/src/util/mdb-schema.c index fe68c7b..4246aa2 100644 --- a/src/util/mdb-schema.c +++ b/src/util/mdb-schema.c @@ -24,18 +24,13 @@ #include "dmalloc.h" #endif -static void generate_table_schema(MdbCatalogEntry *entry, char *namespace, int sanitize); - int main (int argc, char **argv) { - unsigned int i; MdbHandle *mdb; - MdbCatalogEntry *entry; - char *the_relation; char *tabname = NULL; char *namespace = NULL; - int s = 0; + guint32 export_options = MDB_SHEXP_DEFAULT; int opt; if (argc < 2) { @@ -56,7 +51,7 @@ main (int argc, char **argv) namespace = (char *) g_strdup(optarg); break; case 'S': - s = 1; + export_options |= MDB_SHEXP_SANITIZE; break; } } @@ -81,142 +76,17 @@ main (int argc, char **argv) /* read the catalog */ if (!mdb_read_catalog (mdb, MDB_TABLE)) { - fprintf(stderr,"File does not appear to be an Access database\n"); + fprintf(stderr, "File does not appear to be an Access database\n"); exit(1); } - /* Print out a little message to show that this came from mdb-tools. - I like to know how something is generated. DW */ - fprintf(stdout,"-------------------------------------------------------------\n"); - fprintf(stdout,"-- MDB Tools - A library for reading MS Access database files\n"); - fprintf(stdout,"-- Copyright (C) 2000-2004 Brian Bruns\n"); - fprintf(stdout,"-- Files in libmdb are licensed under LGPL and the utilities under\n"); - fprintf(stdout,"-- the GPL, see COPYING.LIB and COPYING files respectively.\n"); - fprintf(stdout,"-- Check out http://mdbtools.sourceforge.net\n"); - fprintf(stdout,"-------------------------------------------------------------\n\n"); + mdb_print_schema(mdb, stdout, tabname, namespace, export_options); - for (i=0; i < mdb->num_catalog; i++) { - entry = g_ptr_array_index (mdb->catalog, i); - if (entry->object_type == MDB_TABLE) { - if ((tabname && !strcmp(entry->object_name, tabname)) - || (!tabname && mdb_is_user_table(entry))) { - generate_table_schema(entry, namespace, s); - } - } - } - - fprintf (stdout, "\n\n"); - fprintf (stdout, "-- CREATE ANY Relationships ...\n"); - fprintf (stdout, "\n"); - while ((the_relation=mdb_get_relationships(mdb)) != NULL) { - fprintf(stdout,"%s\n",the_relation); - g_free(the_relation); - } - g_free(namespace); g_free(tabname); mdb_close (mdb); mdb_exit(); - exit(0); + return 0; } -static void -generate_table_schema(MdbCatalogEntry *entry, char *namespace, int sanitize) -{ - MdbTableDef *table; - MdbHandle *mdb = entry->mdb; - unsigned int i; - MdbColumn *col; - char* table_name; - char* quoted_table_name; - char* quoted_name; - char* sql_sequences; - if (sanitize) - quoted_table_name = sanitize_name(entry->object_name); - else - quoted_table_name = mdb->default_backend->quote_name(entry->object_name); - - if (namespace) { - table_name = malloc(strlen(namespace)+strlen(quoted_table_name)+1); - strcpy(table_name, namespace); - strcat(table_name, quoted_table_name); - free(quoted_table_name); - quoted_table_name = table_name; - } - - /* drop the table if it exists */ - fprintf (stdout, "DROP TABLE %s;\n", quoted_table_name); - - /* create the table */ - fprintf (stdout, "CREATE TABLE %s\n", quoted_table_name); - fprintf (stdout, " (\n"); - - table = mdb_read_table (entry); - - /* get the columns */ - mdb_read_columns (table); - - /* loop over the columns, dumping the names and types */ - - for (i = 0; i < table->num_cols; i++) { - col = g_ptr_array_index (table->columns, i); - - 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)) { - - /* more portable version from DW patch */ - if (col->col_size == 0) - fprintf (stdout, " (255)"); - else - fprintf (stdout, " (%d)", col->col_size); - } - - if (i < table->num_cols - 1) - fprintf (stdout, ", \n"); - else - fprintf (stdout, "\n"); - } /* for */ - - fprintf (stdout, ");\n"); - - fprintf (stdout, "-- CREATE SEQUENCES ...\n"); - fprintf (stdout, "\n"); - - while ((sql_sequences = mdb_get_sequences(entry, namespace, sanitize))) - fprintf(stdout, sql_sequences); - - /* - for (i = 0; i < table->num_cols; i++) { - col = g_ptr_array_index (table->columns, i); - if (col->is_long_auto) { - char sequence_name[256+1+256+4]; // FIXME - char *quoted_column_name; - quoted_column_name = mdb->default_backend->quote_name(col->name); - sprintf(sequence_name, "%s_%s_seq", entry->object_name, col->name); - quoted_name = mdb->default_backend->quote_name(sequence_name); - fprintf (stdout, "CREATE SEQUENCE %s;\n", quoted_name); - fprintf (stdout, "ALTER TABLE %s ALTER COLUMN %s SET DEFAULT pg_catalog.nextval('%s');\n", - quoted_table_name, quoted_column_name, quoted_name); - free(quoted_column_name); - free(quoted_name); - } - - } - */ - - fprintf (stdout, "-- CREATE ANY INDEXES ...\n"); - fprintf (stdout, "\n"); - - free(quoted_table_name); - - mdb_free_tabledef (table); -}