backend/wbprivate/sqlide/wb_live_schema_tree.h (394 lines of code) (raw):
/*
* Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0,
* as published by the Free Software Foundation.
*
* This program is designed to work with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms, as
* designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an additional
* permission to link the program and your derivative works with the
* separately licensed software that they have either included with
* the program or referenced in the documentation.
* 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, version 2.0, 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.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "base/symbol-info.h"
#include "grt.h"
#include "grt/tree_model.h"
#include "workbench/wb_backend_public_interface.h"
#include "base/string_utilities.h"
#include "mforms/treeview.h"
#include "base/trackable.h"
namespace wb {
class MYSQLWBBACKEND_PUBLIC_FUNC LiveSchemaTree : base::trackable {
public:
friend class LiveSchemaTreeTester;
static const short COLUMN_DATA;
static const short TRIGGER_DATA;
static const short INDEX_DATA;
static const short FK_DATA;
static const std::string SCHEMA_TAG;
static const std::string TABLES_TAG;
static const std::string VIEWS_TAG;
static const std::string PROCEDURES_TAG;
static const std::string FUNCTIONS_TAG;
static const std::string TABLE_TAG;
static const std::string VIEW_TAG;
static const std::string ROUTINE_TAG;
static const std::string COLUMNS_TAG;
static const std::string INDEXES_TAG;
static const std::string TRIGGERS_TAG;
static const std::string FOREIGN_KEYS_TAG;
static const std::string COLUMN_TAG;
static const std::string INDEX_TAG;
static const std::string TRIGGER_TAG;
static const std::string FOREIGN_KEY_TAG;
static const std::string FETCHING_CAPTION;
static const std::string ERROR_FETCHING_CAPTION;
static const std::string TABLES_CAPTION;
static const std::string VIEWS_CAPTION;
static const std::string PROCEDURES_CAPTION;
static const std::string FUNCTIONS_CAPTION;
static const std::string COLUMNS_CAPTION;
static const std::string INDEXES_CAPTION;
static const std::string TRIGGERS_CAPTION;
static const std::string FOREIGN_KEYS_CAPTION;
static const std::string LST_INFO_BOX_DETAIL_ROW;
static const int TABLES_NODE_INDEX;
static const int VIEWS_NODE_INDEX;
static const int PROCEDURES_NODE_INDEX;
static const int FUNCTIONS_NODE_INDEX;
static const int TABLE_COLUMNS_NODE_INDEX;
static const int TABLE_INDEXES_NODE_INDEX;
static const int TABLE_FOREIGN_KEYS_NODE_INDEX;
static const int TABLE_TRIGGERS_NODE_INDEX;
enum FilterType { LocalLike, LocalRegexp, RemoteLike, RemoteRegexp };
enum ObjectType {
Schema,
Table,
View,
Procedure,
Function,
TableCollection,
ViewCollection,
ProcedureCollection,
FunctionCollection,
ColumnCollection,
IndexCollection,
TriggerCollection,
ForeignKeyCollection,
Trigger,
TableColumn,
ViewColumn,
ForeignKey,
Index,
ForeignKeyColumn,
IndexColumn,
Any,
NoneType
};
// This will be used on different object type validations
enum ObjectTypeValidation {
DatabaseObject, // Schema, Table, View, Procedure, Function
SchemaObject, // Table, View, Procedure, Function
TableOrView, // Table, View
ColumnObject, // TableColumn, ViewVolumn
RoutineObject // Procedure, Function
};
// One entry in a list that describes a single object.
struct ChangeRecord {
ObjectType type;
std::string schema;
std::string name;
std::string detail;
};
class MYSQLWBBACKEND_PUBLIC_FUNC LSTData : public mforms::TreeNodeData {
public:
std::string details;
LSTData();
virtual ObjectType get_type() = 0;
virtual void copy(LSTData* other);
virtual std::string get_details(bool full, const mforms::TreeNodeRef& node);
virtual std::string get_object_name() = 0;
// Nodes requiring to enable this functionality should overwrite
// and return true once their specific criteria is met
virtual bool is_update_complete() {
return false;
}
};
class MYSQLWBBACKEND_PUBLIC_FUNC ColumnData : public LSTData {
private:
ObjectType _type;
public:
ColumnData(ObjectType type = TableColumn) : LSTData(), is_pk(false), is_fk(false), is_id(false), is_idx(false) {
_type = type;
}
// NOTE than name will contain the column name duplicating this info as it
// is already on the TreeNode. Duplicating it is better than having
// full HTML for all the columns on all the tables in the db.
std::string name;
std::string type;
std::string default_value;
std::string charset_collation;
bool is_pk;
bool is_fk;
bool is_id;
bool is_idx;
virtual void copy(LSTData* other);
virtual ObjectType get_type() {
return _type;
}
virtual std::string get_details(bool full, const mforms::TreeNodeRef& node);
virtual std::string get_object_name() {
return _("Column");
}
};
class MYSQLWBBACKEND_PUBLIC_FUNC FKData : public LSTData {
public:
FKData() : LSTData(), update_rule(0), delete_rule(0) {
}
unsigned char update_rule;
unsigned char delete_rule;
std::string referenced_table;
std::string from_cols;
std::string to_cols;
virtual void copy(LSTData* other);
virtual ObjectType get_type() {
return LiveSchemaTree::ForeignKey;
}
virtual std::string get_details(bool full, const mforms::TreeNodeRef& node);
virtual std::string get_object_name() {
return _("Foreign Key");
}
};
class MYSQLWBBACKEND_PUBLIC_FUNC IndexData : public LSTData {
public:
IndexData() : LSTData(), visible(true), unique(false), type(0) {
}
bool visible;
bool unique;
unsigned char type;
std::vector<std::string> columns;
virtual void copy(LSTData* other);
virtual ObjectType get_type() {
return LiveSchemaTree::Index;
}
virtual std::string get_details(bool full, const mforms::TreeNodeRef& node);
virtual std::string get_object_name() {
return _("Index");
}
};
class MYSQLWBBACKEND_PUBLIC_FUNC TriggerData : public LSTData {
public:
TriggerData() : LSTData(), event_manipulation(0), timing(0) {
}
unsigned char event_manipulation;
unsigned char timing;
virtual void copy(LSTData* other);
virtual ObjectType get_type() {
return LiveSchemaTree::Trigger;
}
virtual std::string get_details(bool full, const mforms::TreeNodeRef& node);
virtual std::string get_object_name() {
return _("Trigger");
}
};
class MYSQLWBBACKEND_PUBLIC_FUNC ObjectData : public LSTData {
public:
ObjectData() : LSTData(), fetched(false), fetching(false) {
}
bool fetched;
bool fetching;
virtual void copy(LSTData* other);
virtual ObjectType get_type() {
return LiveSchemaTree::Any;
}
virtual std::string get_object_name() {
return _("Object");
}
};
class MYSQLWBBACKEND_PUBLIC_FUNC ProcedureData : public ObjectData {
public:
ProcedureData() : ObjectData() {
}
virtual ObjectType get_type() {
return LiveSchemaTree::Procedure;
}
virtual std::string get_object_name() {
return _("Procedure");
}
virtual std::string get_details(bool full, const mforms::TreeNodeRef& node);
};
class MYSQLWBBACKEND_PUBLIC_FUNC FunctionData : public ObjectData {
public:
FunctionData() : ObjectData() {
}
virtual ObjectType get_type() {
return LiveSchemaTree::Function;
}
virtual std::string get_object_name() {
return _("Function");
}
virtual std::string get_details(bool full, const mforms::TreeNodeRef& node);
};
class MYSQLWBBACKEND_PUBLIC_FUNC ViewData : public ObjectData {
public:
ViewData() : ObjectData(), columns_load_error(false), _loaded_mask(0), _loading_mask(0), _reload_mask(0) {
}
bool columns_load_error;
short _loaded_mask;
short _loading_mask;
short _reload_mask;
virtual void copy(LSTData* other);
virtual ObjectType get_type() {
return LiveSchemaTree::View;
}
void set_reload_mask(short mask) {
_reload_mask = mask;
}
short get_reload_mask() {
return _reload_mask;
}
virtual short get_loaded_mask();
virtual void set_loaded_data(short mask);
virtual void set_unloaded_data(short mask);
bool is_data_loaded(short mask);
virtual std::string get_details(bool full, const mforms::TreeNodeRef& node);
virtual std::string get_object_name() {
return _("View");
}
short get_loading_mask();
void set_loading_mask(short mask);
virtual bool is_update_complete();
};
class MYSQLWBBACKEND_PUBLIC_FUNC TableData : public ViewData {
public:
TableData() : ViewData() {
}
virtual ObjectType get_type() {
return LiveSchemaTree::Table;
}
virtual std::string get_details(bool full, const mforms::TreeNodeRef& node);
virtual std::string get_object_name() {
return _("Table");
}
};
class MYSQLWBBACKEND_PUBLIC_FUNC SchemaData : public LSTData {
public:
SchemaData() : LSTData(), fetched(false), fetching(false){};
bool fetched;
bool fetching;
virtual void copy(LSTData* other);
virtual ObjectType get_type() {
return LiveSchemaTree::Schema;
}
virtual std::string get_object_name() {
return _("Schema");
}
};
typedef std::function<void(const std::string& schema_name, base::StringListPtr tables, base::StringListPtr views,
base::StringListPtr procedures, base::StringListPtr functions, bool just_append)>
NewSchemaContentArrivedSlot;
typedef std::function<void(const std::string& schema_name, const std::string& object_name, ObjectType obj_type,
ObjectType child_type, const std::map<std::string, LSTData*>& children)>
NewObjectDetailsArrivedSlot;
typedef std::function<bool(mforms::TreeNodeRef, base::StringListPtr, ObjectType, bool sorted, bool just_append)>
NodeChildrenUpdaterSlot;
struct FetchDelegate {
virtual std::vector<std::string> fetch_schema_list() = 0;
virtual bool fetch_data_for_filter(const std::string&, const std::string&,
const NewSchemaContentArrivedSlot&) = 0;
virtual bool fetch_schema_contents(const std::string&, const NewSchemaContentArrivedSlot&) = 0;
virtual bool fetch_object_details(const std::string& schema_name, const std::string& object_name,
wb::LiveSchemaTree::ObjectType type, short, const NodeChildrenUpdaterSlot&) = 0;
virtual bool fetch_routine_details(const std::string& schema_name, const std::string& object_name,
wb::LiveSchemaTree::ObjectType type) = 0;
};
struct Delegate {
virtual void tree_refresh() = 0;
virtual bool sidebar_action(const std::string&) = 0;
virtual void tree_activate_objects(const std::string&, const std::vector<ChangeRecord>&) = 0;
};
typedef boost::signals2::signal<int(const std::string&)> SqlEditorTextInsertSignal;
SqlEditorTextInsertSignal sql_editor_text_insert_signal;
protected:
std::weak_ptr<FetchDelegate> _fetch_delegate;
std::weak_ptr<Delegate> _delegate;
std::string _active_schema;
mforms::TreeView* _model_view;
GPatternSpec* _schema_pattern = nullptr;
GPatternSpec* _object_pattern = nullptr;
bool _case_sensitive_identifiers;
void schema_contents_arrived(const std::string& schema_name, base::StringListPtr tables, base::StringListPtr views,
base::StringListPtr procedures, base::StringListPtr functions, bool just_append);
void load_table_details(mforms::TreeNodeRef& node, int fetch_mask);
void fetch_table_details(ObjectType object_type, const std::string schema_name, const std::string object_name,
int fetch_mask);
void load_routine_details(mforms::TreeNodeRef& node);
void load_schema_content(mforms::TreeNodeRef& schema_node);
void reload_object_data(mforms::TreeNodeRef& node);
void discard_object_data(mforms::TreeNodeRef& node, int data_mask);
bool identifiers_equal(const std::string& a, const std::string& b);
std::vector<std::string> overlay_icons_for_tree_node(mforms::TreeNodeRef node);
// Filtering functions
std::string get_filter_wildcard(const std::string& filter, FilterType type = LocalLike);
void clean_filter();
void filter_children_collection(mforms::TreeNodeRef& source, mforms::TreeNodeRef& target);
bool filter_children(ObjectType type, mforms::TreeNodeRef& source, mforms::TreeNodeRef& target,
GPatternSpec* pattern = NULL);
bool is_object_type(ObjectTypeValidation validation, ObjectType type);
public:
LiveSchemaTree(base::MySQLVersion version);
virtual ~LiveSchemaTree();
void set_model_view(mforms::TreeView* target);
void set_delegate(std::shared_ptr<Delegate> delegate);
void set_fetch_delegate(std::shared_ptr<FetchDelegate> delegate);
void load_table_details(ObjectType object_type, const std::string schema_name, const std::string object_name,
int fetch_mask);
void set_filter(std::string filter);
std::string getFilter() const { return _filter; }
void filter_data();
void load_data_for_filter(const std::string& schema_filter, const std::string& object_filter);
static unsigned char internalize_token(const std::string& token);
static std::string externalize_token(unsigned char c);
void set_active_schema(const std::string& schema);
void set_no_connection();
void set_enabled(bool enabled);
void update_live_object_state(ObjectType type, const std::string& schema_name, const std::string& old_obj_name,
const std::string& new_obj_name);
virtual std::string get_field_description(const mforms::TreeNodeRef& node);
void set_notify_on_reload(const mforms::TreeNodeRef& node);
void notify_on_reload(const mforms::TreeNodeRef& node);
mforms::TreeNodeRef get_node_for_object(const std::string& schema_name, ObjectType type, const std::string& name);
mforms::TreeNodeRef create_node_for_object(const std::string& schema_name, ObjectType type,
const std::string& name);
// Returns a list of db_query_LiveDBObjectRef.
grt::BaseListRef get_selected_objects();
virtual bool activate_popup_item_for_nodes(const std::string& name,
const std::list<mforms::TreeNodeRef>& orig_nodes);
virtual bec::MenuItemList get_popup_items_for_nodes(const std::list<mforms::TreeNodeRef>& nodes);
bool is_schema_contents_enabled() const;
void is_schema_contents_enabled(bool value);
void set_base(LiveSchemaTree* base) {
_base = base;
}
LiveSchemaTree* getBase() { return _base; }
bool update_node_children(mforms::TreeNodeRef parent, base::StringListPtr children, ObjectType type,
bool sorted = false, bool just_append = false);
void update_change_data(mforms::TreeNodeRef parent, base::StringListPtr children, ObjectType type,
std::vector<mforms::TreeNodeRef>& to_remove);
mforms::TreeNodeRef insert_node(mforms::TreeNodeRef parent, const std::string& name, ObjectType type);
void setup_node(mforms::TreeNodeRef node, ObjectType type, mforms::TreeNodeData* data = NULL,
bool ignore_null_data = false);
void update_node_icon(mforms::TreeNodeRef node);
void update_schemata(base::StringListPtr schema_list);
mforms::TreeNodeRef binary_search_node(const mforms::TreeNodeRef& parent, int first, int last,
const std::string& name, ObjectType type, int& position);
mforms::TreeNodeRef get_child_node(const mforms::TreeNodeRef& parent, const std::string& name,
ObjectType type = Any, bool binary_search = true);
bool find_child_position(const mforms::TreeNodeRef& parent, const std::string& name, ObjectType type,
int& position);
void expand_toggled(mforms::TreeNodeRef node, bool value);
void node_activated(mforms::TreeNodeRef node, int column);
void set_case_sensitive_identifiers(bool flag);
std::string get_schema_name(const mforms::TreeNodeRef& node);
std::vector<std::string> get_node_path(const mforms::TreeNodeRef& node);
mforms::TreeNodeRef get_node_from_path(std::vector<std::string> path);
void enable_events(bool enable) {
_enabled_events = enable;
}
bool getEnabledEvents() { return _enabled_events; }
private:
bool _is_schema_contents_enabled;
bool _enabled_events;
base::MySQLVersion _version;
LiveSchemaTree *_base = nullptr;
std::string _filter;
ObjectType _filter_type;
LSTData *notify_on_reload_data = nullptr;
static const char* _schema_tokens[16];
std::map<ObjectType, std::string> _icon_paths;
std::map<ObjectType, mforms::TreeNodeCollectionSkeleton> _node_collections;
void fill_node_icons();
std::string get_node_icon_path(ObjectType type);
bec::IconId get_node_icon(ObjectType type);
};
};