Added support for name normalisation when generating code for PostgreSQL so that generated artefact names are consistently exported in lowercase.

This commit is contained in:
Jose Hernandez 2021-07-31 15:47:05 +01:00
parent ce4cf5acbf
commit afc6f4888b
5 changed files with 90 additions and 8 deletions

View File

@ -39,6 +39,7 @@ typedef const void * gconstpointer;
typedef uint8_t guint8;
typedef guint32 GQuark;
typedef guint32 gunichar;
typedef signed int gssize;
typedef guint (*GHashFunc)(gconstpointer);
typedef int (*GCompareFunc)(gconstpointer, gconstpointer);
@ -143,6 +144,7 @@ void g_printerr(const gchar *format, ...);
gint g_unichar_to_utf8(gunichar c, gchar *dst);
gchar *g_locale_to_utf8(const gchar *opsysstring, size_t len,
size_t *bytes_read, size_t *bytes_written, GError **error);
gchar *g_utf8_strdown(const gchar *str, gssize len);
/* GString */
GString *g_string_new(const gchar *init);

View File

@ -235,6 +235,7 @@ typedef struct {
const char *table_comment_statement;
const char *per_table_comment_statement;
gchar* (*quote_schema_name)(const gchar*, const gchar*);
gchar* (*normalise_case)(const gchar*);
} MdbBackend;
typedef struct {
@ -569,7 +570,8 @@ void mdb_register_backend(MdbHandle *mdb, char *backend_name, guint32 capabiliti
const char *drop_statement, const char *constaint_not_empty_statement,
const char *column_comment_statement, const char *per_column_comment_statement,
const char *table_comment_statement, const char *per_table_comment_statement,
gchar* (*quote_schema_name)(const gchar*, const gchar*));
gchar* (*quote_schema_name)(const gchar*, const gchar*),
gchar* (*normalise_case)(const gchar*));
int mdb_set_default_backend(MdbHandle *mdb, const char *backend_name);
int mdb_print_schema(MdbHandle *mdb, FILE *outfile, char *tabname, char *dbnamespace, guint32 export_options);
void mdb_print_col(FILE *outfile, gchar *col_val, int quote_text, int col_type, int bin_len, char *quote_char, char *escape_char, int flags);

View File

@ -155,6 +155,37 @@ enum {
static void mdb_drop_backend(gpointer key, gpointer value, gpointer data);
gchar *passthrough_unchanged(const gchar *str) {
return (gchar *)str;
}
gchar *to_lower_case(const gchar *str) {
return g_utf8_strdown(str, -1);
}
/**
* Convenience function to replace an input string with its database specific normalised version.
*
* This function throws away the input string after normalisation, freeing its memory, and replaces it with a new
* normalised version allocated on the stack.
*
* @param mdb Database specific MDB handle containing pointers to utility methods
* @param str string to normalise
* @return a pointer to the normalised version of the input string
*/
gchar *normalise_and_replace(MdbHandle *mdb, gchar **str) {
gchar *normalised_str = mdb->default_backend->normalise_case(*str);
if (normalised_str != *str) {
/* Free and replace the old string only and only if a new string was created at a different memory location
* so that we can account for the case where strings a just passed through unchanged.
*/
free(*str);
*str = normalised_str;
}
return *str;
}
static gchar*
quote_generic(const gchar *value, gchar quote_char, gchar escape_char) {
gchar *result, *pr;
@ -310,7 +341,8 @@ void mdb_init_backends(MdbHandle *mdb)
NULL,
NULL,
NULL,
quote_schema_name_bracket_merge);
quote_schema_name_bracket_merge,
passthrough_unchanged);
mdb_register_backend(mdb, "sybase",
MDB_SHEXP_DROPTABLE|MDB_SHEXP_CST_NOTNULL|MDB_SHEXP_CST_NOTEMPTY|MDB_SHEXP_COMMENTS|MDB_SHEXP_DEFVALUES,
mdb_sybase_types, &mdb_sybase_shortdate_type, NULL,
@ -325,7 +357,8 @@ void mdb_init_backends(MdbHandle *mdb)
NULL,
"COMMENT ON TABLE %s IS %s;\n",
NULL,
quote_schema_name_dquote);
quote_schema_name_dquote,
passthrough_unchanged);
mdb_register_backend(mdb, "oracle",
MDB_SHEXP_DROPTABLE|MDB_SHEXP_CST_NOTNULL|MDB_SHEXP_COMMENTS|MDB_SHEXP_INDEXES|MDB_SHEXP_RELATIONS|MDB_SHEXP_DEFVALUES,
mdb_oracle_types, &mdb_oracle_shortdate_type, NULL,
@ -340,7 +373,8 @@ void mdb_init_backends(MdbHandle *mdb)
NULL,
"COMMENT ON TABLE %s IS %s;\n",
NULL,
quote_schema_name_dquote);
quote_schema_name_dquote,
passthrough_unchanged);
mdb_register_backend(mdb, "postgres",
MDB_SHEXP_DROPTABLE|MDB_SHEXP_CST_NOTNULL|MDB_SHEXP_CST_NOTEMPTY|MDB_SHEXP_COMMENTS|MDB_SHEXP_INDEXES|MDB_SHEXP_RELATIONS|MDB_SHEXP_DEFVALUES|MDB_SHEXP_BULK_INSERT,
mdb_postgres_types, &mdb_postgres_shortdate_type, &mdb_postgres_serial_type,
@ -355,7 +389,8 @@ void mdb_init_backends(MdbHandle *mdb)
NULL,
"COMMENT ON TABLE %s IS %s;\n",
NULL,
quote_schema_name_dquote);
quote_schema_name_dquote,
to_lower_case);
mdb_register_backend(mdb, "mysql",
MDB_SHEXP_DROPTABLE|MDB_SHEXP_CST_NOTNULL|MDB_SHEXP_CST_NOTEMPTY|MDB_SHEXP_INDEXES|MDB_SHEXP_RELATIONS|MDB_SHEXP_DEFVALUES|MDB_SHEXP_BULK_INSERT,
mdb_mysql_types, &mdb_mysql_shortdate_type, &mdb_mysql_serial_type,
@ -370,7 +405,8 @@ void mdb_init_backends(MdbHandle *mdb)
"COMMENT %s",
NULL,
"COMMENT %s",
quote_schema_name_rquotes_merge);
quote_schema_name_rquotes_merge,
passthrough_unchanged);
mdb_register_backend(mdb, "sqlite",
MDB_SHEXP_DROPTABLE|MDB_SHEXP_DEFVALUES|MDB_SHEXP_BULK_INSERT,
mdb_sqlite_types, NULL, NULL,
@ -385,7 +421,8 @@ void mdb_init_backends(MdbHandle *mdb)
NULL,
NULL,
NULL,
quote_schema_name_rquotes_merge);
quote_schema_name_rquotes_merge,
passthrough_unchanged);
}
void mdb_register_backend(MdbHandle *mdb, char *backend_name, guint32 capabilities,
@ -400,7 +437,8 @@ void mdb_register_backend(MdbHandle *mdb, char *backend_name, guint32 capabiliti
const char *per_column_comment_statement,
const char *table_comment_statement,
const char *per_table_comment_statement,
gchar* (*quote_schema_name)(const gchar*, const gchar*))
gchar* (*quote_schema_name)(const gchar*, const gchar*),
gchar* (*normalise_case)(const gchar*))
{
MdbBackend *backend = g_malloc0(sizeof(MdbBackend));
backend->capabilities = capabilities;
@ -420,6 +458,7 @@ void mdb_register_backend(MdbHandle *mdb, char *backend_name, guint32 capabiliti
backend->table_comment_statement = table_comment_statement;
backend->per_table_comment_statement = per_table_comment_statement;
backend->quote_schema_name = quote_schema_name;
backend->normalise_case = normalise_case;
g_hash_table_insert(mdb->backends, backend_name, backend);
}
@ -548,6 +587,7 @@ mdb_print_indexes(FILE* outfile, MdbTableDef *table, char *dbnamespace)
fprintf (outfile, "-- CREATE INDEXES ...\n");
quoted_table_name = mdb->default_backend->quote_schema_name(dbnamespace, table->name);
quoted_table_name = mdb->default_backend->normalise_case(quoted_table_name);
for (i=0;i<table->num_idxs;i++) {
idx = g_ptr_array_index (table->indices, i);
@ -569,6 +609,8 @@ mdb_print_indexes(FILE* outfile, MdbTableDef *table, char *dbnamespace)
quoted_name = mdb->default_backend->quote_schema_name(dbnamespace, index_name);
}
quoted_name = normalise_and_replace(mdb, &quoted_name);
if (idx->index_type==1) {
switch (backend) {
case MDB_BACKEND_ORACLE:
@ -604,6 +646,7 @@ mdb_print_indexes(FILE* outfile, MdbTableDef *table, char *dbnamespace)
fprintf(outfile, ", ");
col=g_ptr_array_index(table->columns,idx->key_col_num[j]-1);
quoted_name = mdb->default_backend->quote_schema_name(NULL, col->name);
quoted_name = normalise_and_replace(mdb, &quoted_name);
fprintf (outfile, "%s", quoted_name);
if (idx->index_type!=1 && idx->key_col_order[j])
/* no DESC for primary keys */
@ -711,8 +754,11 @@ mdb_get_relationships(MdbHandle *mdb, const gchar *dbnamespace, const char* tabl
* be namespaced.
*/
quoted_constraint_name = mdb->default_backend->quote_schema_name(NULL, constraint_name);
quoted_constraint_name = normalise_and_replace(mdb, &quoted_constraint_name);
quoted_column_1 = mdb->default_backend->quote_schema_name(NULL, bound[0]);
quoted_column_1 = normalise_and_replace(mdb, &quoted_column_1);
quoted_column_2 = mdb->default_backend->quote_schema_name(NULL, bound[2]);
quoted_column_2 = normalise_and_replace(mdb, &quoted_column_2);
break;
default:
@ -795,6 +841,7 @@ generate_table_schema(FILE *outfile, MdbCatalogEntry *entry, char *dbnamespace,
const char *prop_value;
quoted_table_name = mdb->default_backend->quote_schema_name(dbnamespace, entry->object_name);
quoted_table_name = normalise_and_replace(mdb, &quoted_table_name);
/* drop the table if it exists */
if (export_options & MDB_SHEXP_DROPTABLE)
@ -814,6 +861,7 @@ generate_table_schema(FILE *outfile, MdbCatalogEntry *entry, char *dbnamespace,
col = g_ptr_array_index (table->columns, i);
quoted_name = mdb->default_backend->quote_schema_name(NULL, col->name);
quoted_name = normalise_and_replace(mdb, &quoted_name);
fprintf (outfile, "\t%s\t\t\t%s", quoted_name,
mdb_get_colbacktype_string (col));
g_free(quoted_name);
@ -916,6 +964,7 @@ generate_table_schema(FILE *outfile, MdbCatalogEntry *entry, char *dbnamespace,
continue;
quoted_name = mdb->default_backend->quote_schema_name(NULL, col->name);
quoted_name = normalise_and_replace(mdb, &quoted_name);
if (export_options & MDB_SHEXP_CST_NOTEMPTY) {
prop_value = mdb_col_get_prop(col, "AllowZeroLength");

View File

@ -28,6 +28,7 @@
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <wctype.h>
#ifdef HAVE_ICONV
#include <iconv.h>
#endif
@ -259,6 +260,30 @@ gchar *g_locale_to_utf8(const gchar *opsysstring, size_t len,
return utf8;
}
gchar *g_utf8_strdown(const gchar *str, gssize len) {
gssize i = 0;
if (len == -1)
len = strlen(str);
gchar *lower = malloc(len+1);
while (i<len) {
wchar_t u = 0;
uint8_t c = str[i];
if ((c & 0xF0) == 0xE0) {
u = (c & 0x0F) << 12;
u += (str[i+1] & 0x3F) << 6;
u += (str[i+2] & 0x3F);
} else if ((c & 0xE0) == 0xC0) {
u = (c & 0x1F) << 6;
u += (str[i+1] & 0x3F);
} else {
u = (c & 0x7F);
}
i += g_unichar_to_utf8(towlower(u), &lower[i]);
}
lower[len] = '\0';
return lower;
}
/* GHashTable */
typedef struct MyNode {

View File

@ -226,12 +226,14 @@ main(int argc, char **argv)
counter = 0; // reset to 0, prevent overflow on extremely large data sets.
char *quoted_name;
quoted_name = mdb->default_backend->quote_schema_name(namespace, table_name);
quoted_name = mdb->default_backend->normalise_case(quoted_name);
fprintf(outfile, "INSERT INTO %s (", quoted_name);
free(quoted_name);
for (i = 0; i < table->num_cols; i++) {
if (i > 0) fputs(", ", outfile);
col = g_ptr_array_index(table->columns, i);
quoted_name = mdb->default_backend->quote_schema_name(NULL, col->name);
quoted_name = mdb->default_backend->normalise_case(quoted_name);
fputs(quoted_name, outfile);
free(quoted_name);
}
@ -284,12 +286,14 @@ main(int argc, char **argv)
if (insert_dialect) {
char *quoted_name;
quoted_name = mdb->default_backend->quote_schema_name(namespace, table_name);
quoted_name = mdb->default_backend->normalise_case(quoted_name);
fprintf(outfile, "INSERT INTO %s (", quoted_name);
free(quoted_name);
for (i = 0; i < table->num_cols; i++) {
if (i > 0) fputs(", ", outfile);
col = g_ptr_array_index(table->columns, i);
quoted_name = mdb->default_backend->quote_schema_name(NULL, col->name);
quoted_name = mdb->default_backend->normalise_case(quoted_name);
fputs(quoted_name, outfile);
free(quoted_name);
}