/* * dbMetrix Database Tool v0.1 * Copyright (c) 1998 David E. Storey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "config.h" #include "global.h" #define DBX_MYSQL(conn) (dbx_MySQL *)conn typedef enum { DBX_MYSQL_RELOADPERMS, DBX_MYSQL_REFRESH, DBX_MYSQL_KILL, DBX_MYSQL_FLUSH_HOSTS, DBX_MYSQL_FLUSH_LOGS, DBX_MYSQL_FLUSH_TABLES, DBX_MYSQL_TABLE_DELETE, DBX_MYSQL_SHUTDOWN, DBX_MYSQL_PASSWD } dbx_MySQL_enums; typedef struct { MYSQL conn; char *host; char *user; char *pass; } dbx_MySQL; /* prototypes */ void change_password_MySQL(GtkWidget *dWindow, gpointer data); void close_MySQL(dataSource *dbconn); int create_db_MySQL(dataSource *conn, char *database); void create_MySQL_addDialog(GtkWidget *dWindow, GtkWidget *notebook, int *curpage); void create_MySQL_dsEntry(GtkWidget *widget); void dialog_MySQL_passwd(dataSource *conn); int drop_db_MySQL(dataSource *conn, char *database); int export_MySQL(node_ds *nodeInfo, export_options *exportOptions); int export_MySQL_database(dbx_MySQL *dbconn, export_options *exportOptions, char *database); int export_MySQL_host(dbx_MySQL *dbconn, export_options *exportOptions); int export_MySQL_table(dbx_MySQL *dbconn, export_options *exportOptions, char *database, char *table); void kill_process_MySQL(gpointer nrow, gpointer clist); void kill_processes_MySQL(GtkWidget *clist); void misc_MySQL(GtkWidget *widget, gpointer data); void process_MySQL(GtkWidget *widget, int row, int column, GdkEventButton *event, gpointer data); void properties_MySQL_host(GtkWidget *widget, gpointer data); void query_MySQL(dataSource *conn, char *query); void refresh_MySQL(GtkWidget *treeItem, gpointer data); GtkWidget *result_MySQL(MYSQL_RES *result, int nIdCol, void(*cb)()); void init_MySQL(void); /* variables */ dbxMenuEntry mysqlMenuProcess[] = { {"kill process(s)", NULL, NULL, NULL} }; void close_MySQL(dataSource *dbconn) { dbx_MySQL *conn = DBX_MYSQL(dbconn->info); mysql_close(&conn->conn); g_free(conn->host); g_free(conn->user); g_free(conn->pass); } void create_MySQL_addDialog(GtkWidget *dWindow, GtkWidget *notebook, int *curpage) { dbx_Dialog entries[] = { {"Host:", "MySQL_Host", FALSE}, {"Username:", "MySQL_User", FALSE}, {"Password:", "MySQL_Pass", TRUE}, {"Port:", "MySQL_Port", FALSE}, {"Socket File:", "MySQL_UnixPort", FALSE} }; create_dialogs(dWindow, notebook, curpage, MySQL, "MySQL", entries, sizeof(entries)/sizeof(entries[0])); } void create_MySQL_dsEntry(GtkWidget *widget) { dbx_MySQL *dbconn; char *host, *user, *pass, *text; char name[256]; /* grab everything from the dialog */ host = get_entry_text(widget, "MySQL_Host", FALSE); user = get_entry_text(widget, "MySQL_User", FALSE); pass = get_entry_text(widget, "MySQL_Pass", TRUE); text = get_entry_text(widget, "MySQL_Port", FALSE); if (text) mysql_port = strtol(text, (char **)NULL, 10); text = get_entry_text(widget, "MySQL_UnixPort", FALSE); if (text) mysql_unix_port = text; g_snprintf(name, 256, "mysql://%s@%s", user, host ? host : "localhost"); /* check for another entry in the tree */ if (fetch_ds_key(name)) return; /* connect to server */ dbconn = DBX_MYSQL(g_malloc(sizeof(dbx_MySQL))); if (mysql_connect(&dbconn->conn, host, user, pass)) { dbconn->host = g_strdup(host); dbconn->user = g_strdup(user); dbconn->pass = g_strdup(pass); /* create tree Item */ ds_add(name, dbconn, MySQL, Host); } else { s_print(mysql_error(&dbconn->conn)); g_free(dbconn); } } int create_db_MySQL(dataSource *conn, char *database) { dbx_MySQL *dbconn = DBX_MYSQL(conn->info); if (mysql_create_db(&dbconn->conn, database)) { s_print(mysql_error(&dbconn->conn)); return(FALSE); } return(TRUE); } void change_password_MySQL(GtkWidget *dWindow, gpointer data) { char *oldpw, *newpw0, *newpw1, crypted_pw[256], buff[384]; dataSource *conn = gtk_object_get_data(GTK_OBJECT(dWindow), "conn"); dbx_MySQL *dbconn = DBX_MYSQL(conn->info); oldpw = get_entry_text(dWindow, "oldpw", TRUE); newpw0 = get_entry_text(dWindow, "newpw0", TRUE); newpw1 = get_entry_text(dWindow, "newpw1", TRUE); if (strcmp(oldpw, dbconn->pass) != 0) { s_print("incorrect password"); gtk_widget_destroy(dWindow); return; } if (strcmp(newpw0, newpw1) != 0) { s_print("new passwords did not match"); gtk_widget_destroy(dWindow); return; } if (!strcmp(newpw1, oldpw)) { s_print("old and new passwords are the same"); gtk_widget_destroy(dWindow); return; } if (mysql_query(&dbconn->conn,"set OPTION sql_log_off=1")) { s_print(mysql_error(&dbconn->conn)); gtk_widget_destroy(dWindow); return; } make_scrambled_password(crypted_pw, newpw1); g_snprintf(buff, 384, "set OPTION password='%s',sql_log_off=0", crypted_pw); if (mysql_query(&dbconn->conn, buff)) s_print(mysql_error(&dbconn->conn)); else { g_free(dbconn->pass); dbconn->pass = g_strdup(newpw1); s_print("password successfully changed"); } gtk_widget_destroy(dWindow); } void dialog_MySQL_passwd(dataSource *conn) { GtkWidget *dWindow; GtkWidget *button; dbx_Dialog entries[] = { {"Old Password:", "oldpw", TRUE}, {"New Password:", "newpw0", TRUE}, {"Retype New Password:", "newpw1", TRUE} }; dWindow = gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(dWindow), "Change MySQL Password"); gtk_widget_set_usize(GTK_DIALOG(dWindow)->action_area, -1, 32); gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(dWindow)->action_area), 4); gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(dWindow)->vbox), 4); gtk_widget_show(dWindow); gtk_object_set_data(GTK_OBJECT(dWindow), "conn", conn); /* action area buttons */ button = gtk_button_new_with_label("Ok"); gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(change_password_MySQL), GTK_OBJECT(dWindow)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dWindow)->action_area), button, TRUE, TRUE, 0); gtk_widget_show(button); button = gtk_button_new_with_label("Cancel"); gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(dWindow)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dWindow)->action_area), button, TRUE, TRUE, 0); gtk_widget_show(button); create_dialogs(dWindow, NULL, NULL, 0, NULL, entries, sizeof(entries)/sizeof(entries[0])); } int drop_db_MySQL(dataSource *conn, char *database) { dbx_MySQL *dbconn = DBX_MYSQL(conn->info); if (mysql_drop_db(&dbconn->conn, database)) { s_print(mysql_error(&dbconn->conn)); return(FALSE); } return(TRUE); } int export_MySQL(node_ds *nodeInfo, export_options *exportOptions) { dbx_MySQL *dbconn = DBX_MYSQL(nodeInfo->conn->info); switch(nodeInfo->type) { case Host: return(export_MySQL_host(dbconn, exportOptions)); break; case Database: return(export_MySQL_database(dbconn, exportOptions, nodeInfo->name)); break; case Table: return(export_MySQL_table(dbconn, exportOptions, nodeInfo->parent->name, nodeInfo->name)); break; case Field: break; } return(FALSE); } int export_MySQL_database(dbx_MySQL *dbconn, export_options *exportOptions, char *database) { return(FALSE); } int export_MySQL_host(dbx_MySQL *dbconn, export_options *exportOptions) { MYSQL_RES *result; result = mysql_list_dbs(&dbconn->conn, NULL); if (!result) return(FALSE); return(FALSE); } int export_MySQL_table(dbx_MySQL *dbconn, export_options *exportOptions, char *database, char *table) { return(FALSE); } void kill_process_MySQL(gpointer nrow, gpointer clist) { gpointer pid; dataSource *conn = gtk_object_get_data(GTK_OBJECT(clist), "conn"); dbx_MySQL *dbconn = DBX_MYSQL(conn->info); pid = gtk_clist_get_row_data(GTK_CLIST(clist), (int)nrow); if (!pid) return; if (mysql_kill(&dbconn->conn, (unsigned long)pid)) gtk_clist_remove(GTK_CLIST(clist), (int)nrow); } void kill_processes_MySQL(GtkWidget *clist) { g_list_foreach(GTK_CLIST(clist)->selection, kill_process_MySQL, clist); } void misc_MySQL(GtkWidget *widget, gpointer data) { char message[256]; GtkWidget *treeItem = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(dbTree), "selected"); node_ds *nodeInfo = (node_ds *)gtk_object_get_data(GTK_OBJECT(treeItem), "info"); dbx_MySQL *dbconn = DBX_MYSQL(nodeInfo->conn->info); switch((int)data) { case DBX_MYSQL_TABLE_DELETE: if (mysql_select_db(&dbconn->conn, nodeInfo->parent->name) != -1) { g_snprintf(message, 256, "DROP TABLE %s", nodeInfo->name); if (mysql_query(&dbconn->conn, message) != -1) { g_snprintf(message, 256, "Table '%s' dropped", nodeInfo->name); s_print(message); ds_prune_tree((gpointer)treeItem, NULL); } else s_print(mysql_error(&dbconn->conn)); } else s_print(mysql_error(&dbconn->conn)); break; case DBX_MYSQL_SHUTDOWN: if (mysql_shutdown(&dbconn->conn) != -1) ds_close(treeItem, treeItem); else s_print(mysql_error(&dbconn->conn)); break; case DBX_MYSQL_RELOADPERMS: if (mysql_reload(&dbconn->conn) != -1) { g_snprintf(message, 256, "Successfully reloaded grant tables for %s", nodeInfo->name); s_print(message); } else s_print(mysql_error(&dbconn->conn)); break; case DBX_MYSQL_REFRESH: if (mysql_refresh(&dbconn->conn,(unsigned) ~REFRESH_GRANT) != -1) { g_snprintf(message, 256, "Successfully refreshed server %s", nodeInfo->name); s_print(message); } else s_print(mysql_error(&dbconn->conn)); break; case DBX_MYSQL_FLUSH_LOGS: if (!mysql_refresh(&dbconn->conn, REFRESH_LOG)) { g_snprintf(message, 256, "Successfully flushed logs on %s", nodeInfo->name); s_print(message); } else s_print(mysql_error(&dbconn->conn)); break; case DBX_MYSQL_FLUSH_HOSTS: if (!mysql_refresh(&dbconn->conn, REFRESH_HOSTS)) { g_snprintf(message, 256, "Successfully flushed hosts on %s", nodeInfo->name); s_print(message); } else s_print(mysql_error(&dbconn->conn)); break; case DBX_MYSQL_FLUSH_TABLES: if (!mysql_refresh(&dbconn->conn, REFRESH_TABLES)) { g_snprintf(message, 256, "Successfully flushed tables on %s", nodeInfo->name); s_print(message); } else s_print(mysql_error(&dbconn->conn)); break; case DBX_MYSQL_PASSWD: dialog_MySQL_passwd(nodeInfo->conn); break; } } void process_MySQL(GtkWidget *widget, int row, int column, GdkEventButton *event, gpointer data) { g_print("row selected: %d\n", row); } void properties_MySQL_host(GtkWidget *widget, gpointer data) { GtkWidget *frame; GtkWidget *tLayout; GtkWidget *label; GtkWidget *notebook; node_ds *nodeInfo = fetch_selected(); dbx_MySQL *dbconn = DBX_MYSQL(nodeInfo->conn->info); MYSQL_RES *result; char protocol[256]; int k; frame = new_dialog("MySQL Properties", "MySQL Server Properties"); /* create notebook */ notebook = gtk_notebook_new(); gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), TRUE); gtk_container_add(GTK_CONTAINER(frame), notebook); gtk_widget_show(notebook); tLayout = gtk_table_new(10, 2, FALSE); gtk_table_set_row_spacings(GTK_TABLE(tLayout), 1); gtk_table_set_col_spacings(GTK_TABLE(tLayout), 3); gtk_container_border_width(GTK_CONTAINER(tLayout), 4); label = gtk_label_new("Information"); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), tLayout, label); gtk_widget_show(tLayout); /* host/server/protocol info */ label = gtk_label_new("Host Info:"); gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); gtk_table_attach(GTK_TABLE(tLayout), label, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); label = gtk_label_new(mysql_get_host_info(&dbconn->conn)); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_table_attach(GTK_TABLE(tLayout), label, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); label = gtk_label_new("Server Info:"); gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); gtk_table_attach(GTK_TABLE(tLayout), label, 0, 1, 1, 2, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); label = gtk_label_new(mysql_get_server_info(&dbconn->conn)); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_table_attach(GTK_TABLE(tLayout), label, 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); label = gtk_label_new("Protocol:"); gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); gtk_table_attach(GTK_TABLE(tLayout), label, 0, 1, 2, 3, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); g_snprintf(protocol, 256, "%d", mysql_get_proto_info(&dbconn->conn)); label = gtk_label_new(protocol); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_table_attach(GTK_TABLE(tLayout), label, 1, 2, 2, 3, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); /* server status */ k = 3; if (mysql_query(&dbconn->conn, "SHOW STATUS") != -1) { result = mysql_store_result(&dbconn->conn); if (result) { int i; MYSQL_ROW row = mysql_fetch_row(result); for (i = 0; i < mysql_num_fields(result); i++) { int j; char text[256]; MYSQL_FIELD *field = mysql_fetch_field(result); for (j = 0; j < 2; j++) { if (j) label = gtk_label_new(row[i]); else { g_snprintf(text, 256, "%s:", field->name); label = gtk_label_new(text); } gtk_misc_set_alignment(GTK_MISC(label), !j, 0.5); gtk_table_attach(GTK_TABLE(tLayout), label, j, j + 1, k, k + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); } k++; } mysql_free_result(result); } } /* show variables... */ if (mysql_query(&dbconn->conn, "SHOW VARIABLES") != -1) { result = mysql_store_result(&dbconn->conn); if (result) { GtkWidget *clist = result_MySQL(result, -1, NULL); gtk_widget_show(clist); gtk_clist_column_titles_passive(GTK_CLIST(clist)); gtk_clist_column_titles_show(GTK_CLIST(clist)); gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_SINGLE); label = gtk_label_new("Variables"); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), clist, label); mysql_free_result(result); } } /* process list */ result = mysql_list_processes(&dbconn->conn); if (result) { GtkWidget *vbox = gtk_vbox_new(FALSE, 0); GtkWidget *button = gtk_button_new_with_label("Kill Process(s)"); GtkWidget *clist = result_MySQL(result, 0, process_MySQL); gtk_clist_column_titles_passive(GTK_CLIST(clist)); gtk_clist_column_titles_show(GTK_CLIST(clist)); gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_SINGLE); gtk_widget_show(clist); gtk_object_set_data(GTK_OBJECT(clist), "conn", nodeInfo->conn); gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(kill_processes_MySQL), GTK_OBJECT(clist)); gtk_box_pack_start(GTK_BOX(vbox), clist, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); gtk_widget_show(button); gtk_widget_show(vbox); label = gtk_label_new("Processes"); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label); mysql_free_result(result); } } void query_MySQL(dataSource *conn, char *query) { dbx_MySQL *dbconn; MYSQL_RES *result; if (conn && query) dbconn = DBX_MYSQL(conn->info); else return; if (mysql_query(&dbconn->conn, query) == -1) { s_print(mysql_error(&dbconn->conn)); return; } result = mysql_store_result(&dbconn->conn); if (result) { query_window(result_MySQL(result, -1, NULL)); mysql_free_result(result); } } void refresh_MySQL(GtkWidget *treeItem, gpointer data) { node_ds *nodeInfo = (node_ds *)data; dbx_MySQL *dbconn = DBX_MYSQL(nodeInfo->conn->info); MYSQL_RES *result = NULL; char query[256]; switch(nodeInfo->type) { case Host: result = mysql_list_dbs(&dbconn->conn, NULL); break; case Database: if (mysql_select_db(&dbconn->conn, nodeInfo->name) == -1) break; result = mysql_list_tables(&dbconn->conn, NULL); break; case Table: if (!pref_get("dstree.table.show_fields")) break; if (mysql_select_db(&dbconn->conn, nodeInfo->parent->name) == -1) break; g_snprintf(query, 256, "SHOW COLUMNS FROM %s", nodeInfo->name); if (mysql_query(&dbconn->conn, query) != -1) result = mysql_store_result(&dbconn->conn); break; case Field: break; } if (result) { int i; if (mysql_num_rows(result) > 0) add_subtree(treeItem); for (i = 0; i < mysql_num_rows(result); i++) { MYSQL_ROW row = mysql_fetch_row(result); tree_refresh(treeItem, nodeInfo, i, row[0]); } mysql_free_result(result); } } GtkWidget * result_MySQL(MYSQL_RES *result, int nIdCol, void(*cb)()) { GtkWidget *clist; unsigned *maxflengths; int i, total = 0; if (!result || !mysql_num_rows(result)) return(NULL); maxflengths = (unsigned *)calloc(mysql_num_fields(result), sizeof(unsigned)); clist = gtk_clist_new(mysql_num_fields(result)); for (i = 0; i < mysql_num_fields(result); i++) { MYSQL_FIELD *field = mysql_fetch_field(result); gtk_clist_set_column_title(GTK_CLIST(clist), i, field->name); maxflengths[i] = field->name ? strlen(field->name) : 0; } for (i = 0; i < mysql_num_rows(result); i++) { MYSQL_ROW row = mysql_fetch_row(result); unsigned *lengths = mysql_fetch_lengths(result); int j; gtk_clist_append(GTK_CLIST(clist), row); if (nIdCol >= 0) gtk_clist_set_row_data(GTK_CLIST(clist), i, (gpointer *)atol(row[nIdCol])); for (j = 0; j < mysql_num_fields(result); j++) if (lengths[j] > maxflengths[j]) maxflengths[j] = lengths[j]; } for (i = 0; i < mysql_num_fields(result); i++) { total += maxflengths[i] * 8; gtk_clist_set_column_width(GTK_CLIST(clist), i, maxflengths[i] * 8); } gtk_object_set_data(GTK_OBJECT(clist), "width", (gpointer)total); gtk_object_set_data(GTK_OBJECT(clist), "height", (gpointer)mysql_num_rows(result)); free(maxflengths); if (cb) gtk_signal_connect(GTK_OBJECT(clist), "select_row", GTK_SIGNAL_FUNC(cb), NULL); return(clist); } void init_MySQL(void) { dbxMenuEntry mysqlMenuHost[] = { {"create database...", NULL, DBX_SIGNAL_FUNC(create_dbDialog), (gpointer)MySQL}, {NULL, NULL, NULL, NULL}, {"reload grant tables", NULL, DBX_SIGNAL_FUNC(misc_MySQL), (gpointer)DBX_MYSQL_RELOADPERMS}, {"flush tables/reopen logs", NULL, DBX_SIGNAL_FUNC(misc_MySQL), (gpointer)DBX_MYSQL_REFRESH}, {"flush all cached hosts", NULL, DBX_SIGNAL_FUNC(misc_MySQL), (gpointer)DBX_MYSQL_FLUSH_HOSTS}, {"flush all logs", NULL, DBX_SIGNAL_FUNC(misc_MySQL), (gpointer)DBX_MYSQL_FLUSH_LOGS}, {"flush all tables", NULL, DBX_SIGNAL_FUNC(misc_MySQL), (gpointer)DBX_MYSQL_FLUSH_TABLES}, {"shutdown", NULL, DBX_SIGNAL_FUNC(misc_MySQL), (gpointer)DBX_MYSQL_SHUTDOWN}, {"disconnect", NULL, DBX_SIGNAL_FUNC(ds_close), (gpointer)TRUE}, {NULL, NULL, NULL, NULL}, /* {"export...", NULL, DBX_SIGNAL_FUNC(ds_export), NULL},*/ {"change password...", NULL, DBX_SIGNAL_FUNC(misc_MySQL), (gpointer)DBX_MYSQL_PASSWD}, {"properties...", NULL, DBX_SIGNAL_FUNC(properties_MySQL_host), NULL} }; dbxMenuEntry mysqlMenuDB[] = { {"create table", NULL, NULL, NULL}, {"drop database", NULL, DBX_SIGNAL_FUNC(drop_db), (gpointer)MySQL} /* {"export...", NULL, DBX_SIGNAL_FUNC(ds_export), NULL}*/ }; dbxMenuEntry mysqlMenuTable[] = { {"browse", NULL, NULL, NULL}, {"create field", NULL, NULL, NULL}, {"create index", NULL, NULL, NULL}, {"rename", NULL, NULL, NULL}, {"delete", NULL, DBX_SIGNAL_FUNC(misc_MySQL), (gpointer)DBX_MYSQL_TABLE_DELETE}, {"empty table", NULL, NULL, NULL} /* {"export...", NULL, DBX_SIGNAL_FUNC(ds_export), NULL}*/ }; dsMenus[MySQL].host = set_menu(mysqlMenuHost, sizeof(mysqlMenuHost)/sizeof(mysqlMenuHost[0])); dsMenus[MySQL].database = set_menu(mysqlMenuDB, sizeof(mysqlMenuDB)/sizeof(mysqlMenuDB[0])); dsMenus[MySQL].table = set_menu(mysqlMenuTable, sizeof(mysqlMenuTable)/sizeof(mysqlMenuTable[0])); dsFuncs[MySQL].close = close_MySQL; dsFuncs[MySQL].create_db = create_db_MySQL; dsFuncs[MySQL].create_dsEntry = create_MySQL_dsEntry; dsFuncs[MySQL].create_dsDialog = create_MySQL_addDialog; dsFuncs[MySQL].drop_db = drop_db_MySQL; dsFuncs[MySQL].export = export_MySQL; dsFuncs[MySQL].exec_query = query_MySQL; dsFuncs[MySQL].refresh = refresh_MySQL; }