diff --git a/include/mdbtools.h b/include/mdbtools.h index 68c18fd..6fc7c1b 100644 --- a/include/mdbtools.h +++ b/include/mdbtools.h @@ -538,6 +538,7 @@ extern LIBMDB_DLL MDB_DEPRECATED(void, mdb_init_backends()); extern LIBMDB_DLL void mdb_register_backend(char *backend_name, guint32 capabilities, MdbBackendType *backend_type, MdbBackendType *type_shortdate, MdbBackendType *type_autonum, const char *short_now, const char *long_now, const char *charset_statement, const char *drop_statement, const char *constaint_not_empty_statement, const char *column_comment_statement, const char *table_comment_statement, gchar* (*quote_schema_name)(const gchar*, const gchar*)); extern LIBMDB_DLL MDB_DEPRECATED(void, mdb_remove_backends()); extern LIBMDB_DLL int mdb_set_default_backend(MdbHandle *mdb, const char *backend_name); +extern LIBMDB_DLL void generate_table_schemas(char *buf, unsigned int *bi, unsigned int *bsize, MdbCatalogEntry *entry, char *dbnamespace, guint32 export_options); extern LIBMDB_DLL void mdb_print_schema(MdbHandle *mdb, FILE *outfile, char *tabname, char *dbnamespace, guint32 export_options); /* sargs.c */ diff --git a/src/libmdb/backend.c b/src/libmdb/backend.c index 718f6dc..5a03fa3 100644 --- a/src/libmdb/backend.c +++ b/src/libmdb/backend.c @@ -596,6 +596,121 @@ mdb_print_indexes(FILE* outfile, MdbTableDef *table, char *dbnamespace) g_free(quoted_table_name); } +/** + * mdb_print_indexes + * @buf: Where to print the sql + * @bi: Index into buf + * @bsize: Size of buf + * @table: Table to process + * @dbnamespace: Target namespace/schema name + */ +static void +mdb_print_indexess(char* buf, unsigned int *bi, unsigned int *bsize, MdbTableDef *table, char *dbnamespace) +{ + unsigned int i, j; + char* quoted_table_name; + char* index_name; + char* quoted_name; + int backend; + MdbHandle* mdb = table->entry->mdb; + MdbIndex *idx; + MdbColumn *col; + + if (!strcmp(mdb->backend_name, "postgres")) { + backend = MDB_BACKEND_POSTGRES; + } else if (!strcmp(mdb->backend_name, "mysql")) { + backend = MDB_BACKEND_MYSQL; + } else { + *bi += sprintf(buf + *bi, "-- Indexes are not implemented for %s\n\n", mdb->backend_name); + return; + } + + /* read indexes */ + mdb_read_indices(table); + + *bi += sprintf(buf + *bi, "-- CREATE INDEXES ...\n"); + + quoted_table_name = mdb->default_backend->quote_schema_name(dbnamespace, table->name); + + for (i=0;inum_idxs;i++) { + + if (*bi > *bsize/2) { //extend the buffer if needed + char *b; + *bsize *= 2; + b = (char*) g_realloc(buf, *bsize); + buf = b; + } + + idx = (MdbIndex*) g_ptr_array_index (table->indices, i); + if (idx->index_type==2) + continue; + + index_name = (char*) malloc(strlen(table->name)+strlen(idx->name)+5+1); + strcpy(index_name, table->name); + if (idx->index_type==1) + strcat(index_name, "_pkey"); + else { + strcat(index_name, "_"); + strcat(index_name, idx->name); + strcat(index_name, "_idx"); + } + quoted_name = mdb->default_backend->quote_schema_name(dbnamespace, index_name); + if (idx->index_type==1) { + switch (backend) { + case MDB_BACKEND_POSTGRES: + *bi += sprintf(buf + *bi, "ALTER TABLE %s ADD CONSTRAINT %s PRIMARY KEY (", quoted_table_name, quoted_name); + break; + case MDB_BACKEND_MYSQL: + *bi += sprintf(buf + *bi, "ALTER TABLE %s ADD PRIMARY KEY (", quoted_table_name); + break; + } + } else { + switch (backend) { + case MDB_BACKEND_POSTGRES: + *bi += sprintf(buf + *bi, "CREATE"); + if (idx->flags & MDB_IDX_UNIQUE) + *bi += sprintf(buf + *bi, " UNIQUE"); + *bi += sprintf(buf + *bi, " INDEX %s ON %s (", quoted_name, quoted_table_name); + break; + case MDB_BACKEND_MYSQL: + *bi += sprintf(buf + *bi, "ALTER TABLE %s ADD", quoted_table_name); + if (idx->flags & MDB_IDX_UNIQUE) + *bi += sprintf(buf + *bi, " UNIQUE"); + *bi += sprintf(buf + *bi, " INDEX %s (", quoted_name); + break; + } + } + g_free(quoted_name); //changed from free + free(index_name); + + for (j=0;jnum_keys;j++) { + + if (*bi > *bsize/2) { //extend the buffer if needed + char *b; + *bsize *= 2; + b = (char*) g_realloc(buf, *bsize); + buf = b; + } + + if (j) + *bi += sprintf(buf + *bi, ", "); + col= (MdbColumn*) g_ptr_array_index(table->columns,idx->key_col_num[j]-1); + quoted_name = mdb->default_backend->quote_schema_name(NULL, col->name); + *bi += sprintf(buf + *bi, "%s", quoted_name); + if (idx->index_type!=1 && idx->key_col_order[j]) + /* no DESC for primary keys */ + *bi += sprintf(buf + *bi, " DESC"); + + g_free(quoted_name); //changed from free + + } + *bi += sprintf(buf + *bi, ");\n"); + } + *bi += sprintf(buf + *bi, "\n"); + + g_free(quoted_table_name); +} + /** * mdb_get_relationships * @mdb: Handle to open MDB database file @@ -884,6 +999,177 @@ generate_table_schema(FILE *outfile, MdbCatalogEntry *entry, char *dbnamespace, mdb_free_tabledef (table); } +/** Does the same as the above but putting the data in buf. + * In Windows there is no way to write to memory through a FILE pointer, and writing to disk slows down a lot +*/ +void +generate_table_schemas(char *buf, unsigned int *bi, unsigned int *bsize, MdbCatalogEntry *entry, char *dbnamespace, guint32 export_options) +{ + MdbTableDef *table; + MdbHandle *mdb = entry->mdb; + MdbColumn *col; + unsigned int i; + char* quoted_table_name; + char* quoted_name; + MdbProperties *props; + const char *prop_value; + + quoted_table_name = mdb->default_backend->quote_schema_name(dbnamespace, entry->object_name); + + /* drop the table if it exists */ + if (export_options & MDB_SHEXP_DROPTABLE) + *bi = sprintf (buf, mdb->default_backend->drop_statement, quoted_table_name); + + /* create the table */ + *bi += sprintf(buf + *bi, "CREATE TABLE %s (", quoted_table_name); + + 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++) { + + if (*bi > *bsize/2) { //extend the buffer if needed + char *b; + *bsize *= 2; + b = (char*) g_realloc(buf, *bsize); + buf = b; + } + + col = (MdbColumn*) g_ptr_array_index (table->columns, i); + + quoted_name = mdb->default_backend->quote_schema_name(NULL, col->name); + *bi += sprintf(buf + *bi, "%s %s", quoted_name, + mdb_get_colbacktype_string (col)); + g_free(quoted_name); //changed from free + + if (mdb_colbacktype_takes_length(col)) { + + /* more portable version from DW patch */ + if (col->col_size == 0) + *bi += sprintf(buf + *bi, " (255)"); + else + *bi += sprintf(buf + *bi, " (%d)", col->col_size); + } + + if (export_options & MDB_SHEXP_CST_NOTNULL) { + if (col->col_type == MDB_BOOL) { + /* access booleans are never null */ + *bi += sprintf(buf + *bi, " NOT NULL"); + } else { + const gchar *not_null = mdb_col_get_prop(col, "Required"); + if (not_null && not_null[0]=='y') + *bi += sprintf(buf + *bi, " NOT NULL"); + } + } + + if (export_options & MDB_SHEXP_DEFVALUES) { + int done = 0; + if (col->props) { + gchar *defval = (gchar*) g_hash_table_lookup(col->props->hash, "DefaultValue"); + if (defval) { + size_t def_len = strlen(defval); + *bi += sprintf(buf + *bi, " DEFAULT "); + /* ugly hack to detect the type */ + if (defval[0]=='"' && defval[def_len-1]=='"') { + /* this is a string */ + gchar *output_default = (gchar*) malloc(def_len-1); + gchar *output_default_escaped; + memcpy(output_default, defval+1, def_len-2); + output_default[def_len-2] = 0; + output_default_escaped = quote_with_squotes(output_default); + *bi += sprintf(buf + *bi, output_default_escaped); + g_free(output_default_escaped); + free(output_default); + } else if (!strcmp(defval, "Yes")) + *bi += sprintf(buf + *bi, "TRUE"); + else if (!strcmp(defval, "No")) + *bi += sprintf(buf + *bi, "FALSE"); + else if (!strcasecmp(defval, "date()")) { + if (!strcmp(mdb_col_get_prop(col, "Format"), "Short Date")) + *bi += sprintf(buf + *bi, mdb->default_backend->short_now); + else + *bi += sprintf(buf + *bi, mdb->default_backend->long_now); + } + else + *bi += sprintf(buf + *bi, defval); + done = 1; + } + } + if (!done && col->col_type == MDB_BOOL) + /* access booleans are false by default */ + *bi += sprintf(buf + *bi, " DEFAULT FALSE"); + } + if (i < table->num_cols - 1) + *bi += sprintf(buf + *bi, ", "); + } /* for */ + + *bi += sprintf(buf + *bi, ");"); + + /* Add the constraints on columns */ + for (i = 0; i < table->num_cols; i++) { + + if (*bi > *bsize/2) { //extend the buffer if needed + char *b; + *bsize *= 2; + b = (char*) g_realloc(buf, *bsize); + buf = b; + } + + col = (MdbColumn*) g_ptr_array_index (table->columns, i); + props = col->props; + if (!props) + continue; + + quoted_name = mdb->default_backend->quote_schema_name(NULL, col->name); + + if (export_options & MDB_SHEXP_CST_NOTEMPTY) { + prop_value = mdb_col_get_prop(col, "AllowZeroLength"); + if (prop_value && prop_value[0]=='n') + *bi += sprintf(buf + *bi, + mdb->default_backend->constaint_not_empty_statement, + quoted_table_name, quoted_name); + } + + if (export_options & MDB_SHEXP_COMMENTS) { + prop_value = mdb_col_get_prop(col, "Description"); + if (prop_value) { + char *comment = quote_with_squotes(prop_value); + *bi += sprintf(buf + *bi, + mdb->default_backend->column_comment_statement, + quoted_table_name, quoted_name, comment); + g_free(comment); //changed from free + } + } + + g_free(quoted_name); //changed from free + } + + /* Add the constraints on table */ + if (export_options & MDB_SHEXP_COMMENTS) { + prop_value = mdb_table_get_prop(table, "Description"); + if (prop_value) { + char *comment = quote_with_squotes(prop_value); + *bi += sprintf(buf + *bi, + mdb->default_backend->table_comment_statement, + quoted_table_name, comment); + g_free(comment); //changed from free + } + } + //*bi += sprintf(buf + *bi, "\n"); + + + if (export_options & MDB_SHEXP_INDEXES) + // prints all the indexes of that table + mdb_print_indexess(buf, bi, bsize, table, dbnamespace); + + g_free(quoted_table_name); //changed from free + + mdb_free_tabledef (table); +} + void mdb_print_schema(MdbHandle *mdb, FILE *outfile, char *tabname, char *dbnamespace, guint32 export_options) {