1 /*
2 # PostgreSQL Database Modeler (pgModeler)
3 # Copyright 2006-2020 - Raphael Araújo e Silva <raphael@pgmodeler.io>
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation version 3.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # The complete text of GPLv3 is at LICENSE file on source code root directory.
15 # Also, you can get the complete GNU General Public License at <http://www.gnu.org/licenses/>
16 */
17 
18 /**
19 \class BaseObject
20 \brief Implements the most important operations to define, maintain and generate code (SQL or XML) of database objects
21 \note <strong>Creation date:</strong> 12/09/2006
22 \ingroup libpgmodeler
23 */
24 
25 #ifndef BASE_OBJECT_H
26 #define BASE_OBJECT_H
27 
28 #include "attributes.h"
29 #include "exception.h"
30 #include "schemaparser.h"
31 #include "xmlparser.h"
32 #include <map>
33 #include <QRegExp>
34 #include <QStringList>
35 #include <QTextStream>
36 #include <type_traits>
37 
38 enum class ObjectType: unsigned {
39 	Column,
40 	Constraint,
41 	Function,
42 	Trigger,
43 	Index,
44 	Rule,
45 	Table,
46 	View,
47 	Domain,
48 	Schema,
49 	Aggregate,
50 	Operator,
51 	Sequence,
52 	Role,
53 	Conversion,
54 	Cast,
55 	Language,
56 	Type,
57 	Tablespace,
58 	OpFamily,
59 	OpClass,
60 	Database,
61 	Collation,
62 	Extension,
63 	EventTrigger,
64 	Policy,
65 	ForeignDataWrapper,
66 	ForeignServer,
67 	ForeignTable,
68 	UserMapping,
69 	Relationship,
70 	Textbox,
71 	Permission,
72 	Parameter,
73 	TypeAttribute,
74 	Tag,
75 	GenericSql,
76 	BaseRelationship,
77 	BaseObject,
78 	BaseTable
79 };
80 
81 class BaseObject {
82 	private:
83 		//! \brief Current PostgreSQL version used in SQL code generation
84 		static QString pgsql_ver;
85 
86 		//! \brief Indicates the the cached code enabled
87 		static bool use_cached_code;
88 
89 		static bool escape_comments;
90 
91 		//! \brief Stores the set of special (valid) chars that forces the object's name quoting
92 		static const QByteArray special_chars;
93 
94 		//! \brief Stores the database wich the object belongs
95 		BaseObject *database;
96 
97 	protected:
98 		SchemaParser schparser;
99 
100 		/*! \brief This static attribute is used to generate the unique identifier for objects.
101 		 As object instances are created this value ​​are incremented. In some classes
102 		 like Schema, DatabaseModel, Tablespace, Role, Type and Function id generators are
103 		 used each with a custom different numbering range (see cited classes declaration). */
104 		static unsigned global_id;
105 
106 		/*! \brief Stores the unique identifier for the object. This id is nothing else
107 		 than the current value of global_id. This identifier is used
108 		 to know the chronological order of the creation of each object in the model
109 		 because the generation and reading of the XML code is completely tied to the order
110 		 in which the objects were created */
111 		unsigned object_id;
112 
113 		//! \brief Objects type count declared on enum ObjectType
114 		static constexpr unsigned ObjectTypeCount=enum_cast(ObjectType::BaseTable) + 1;
115 
116 		/*! \brief Indicates whether the object is protected or not.
117 		 A protected object indicates that it can not suffer changes in position
118 		 (e.g. can not be moved or rotated) can not have your name / text changed,
119 		 and deleted. This is only a flag, the cited operations are controled in a
120 		 upper class layer */
121 		bool is_protected,
122 
123 		/*! \brief This property indicates that the object is a system protected object and cannot be modified
124 		by the user. Additionally, the this attribute is true the SQL/XML code for the object is not generated */
125 		system_obj,
126 
127 		/*! \brief Indicates if the generated SQL code is disable. When this flag is true
128 		the object's SQL code is created normally but is commented. This is useful when using
129 		the role only as a reference since it already exists on the destination server. */
130 		sql_disabled,
131 
132 		/*! \brief Indicates if the cached code is invalidated. Some key attributes of this class and other base classes
133 				automatically change the value of this attribute when the respective set[Attribute]() is called. For all the
134 				rest the method setCodeInvalidated() should be explicitly called if you need to invalidate the code and
135 				generate it again */
136 		code_invalidated;
137 
138 		//! \brief Stores the cached xml and sql code
139 		QString cached_code[2],
140 
141 		//! \brief Stores the xml code in reduced form
142 		cached_reduced_code;
143 
144 		/*! \brief This map stores the name of each object type associated to a schema file
145 		 that generates the object's code definition */
146 		static const QString objs_schemas[ObjectTypeCount];
147 
148 		/*! \brief This map associates the object type to a keyword on
149 		 SQL language that represents the object */
150 		static const QString objs_sql[ObjectTypeCount];
151 
152 		/*! \brief Stores the name of the type of objects to be used in error messages formatting
153 		 and others operations that envolves object type name */
154 		static const QString obj_type_names[ObjectTypeCount];
155 
156 		/*! \brief Role that is owner of the object. Some objects cannot be associated to a role
157 		 so if one is assigned to the object an error will be raised */
158 		BaseObject *owner;
159 
160 		/*! \brief Schema the objects belongs. Some objects cannot be associated to a schema
161 		 so if one is assigned to the object an error will be raised */
162 		BaseObject *schema;
163 
164 		/*! \brief Tablespace to which the object is part. Some objects cannot be associated to a tablespace
165 		 so if one is assigned to the object an error will be raised */
166 		BaseObject *tablespace;
167 
168 		/*! \brief Collation referenced by the object. Some objects cannot be associated to a collation
169 		 so if one is assigned to the object an error will be raised */
170 		BaseObject *collation;
171 
172 		//! \brief Comments related to object
173 		QString comment,
174 
175 		//! \brief Object's name (in PostgreSQL accepted format)
176 		obj_name,
177 
178 		//! \brief Object's alias (human readable / friendly) name
179 		alias,
180 
181 		//! \brief The set of SQL commands appended on the objectc's definition
182 		appended_sql,
183 
184 		//! \brief The set of SQL commands prepended on the objectc's definition
185 		prepended_sql;
186 
187 		/*! \brief Stores the attributes and their values ​​shaped in strings to be used
188 		 by SchemaParser on the object's code definition creation. The attribute
189 		 name related to model objects are defined in ParsersAttributes namespace. */
190 		attribs_map attributes,
191 
192 		/*! \brief Stores the attributes and their vales which can be used by the
193 		 * searching mechanism to match patters */
194 		search_attribs;
195 
196 		/*! \brief Type of object, may have one of the values ​​of the enum ObjectType
197 		 It was used a numeric type to avoid the use excessive of RTTI. */
198 		ObjectType obj_type;
199 
200 		/*! \brief This method calls the getCodeDefinition(unsigned, bool) method with the 'reduced_form' defined as 'false',
201 		 This is the real implementation of the virtual method getCodeDefinition(unsigned). */
202 		QString __getCodeDefinition(unsigned def_type);
203 
204 		/*! \brief Set the database that owns the object
205 		ATTENTION: calling this method with a nullptr parameter doesn't means that the object will
206 							 be removed from the database, only the attribute will be set as nullptr and
207 							 if the user calls getDatabase() in further operations may result in crash */
208 		void setDatabase(BaseObject *db);
209 
210 		/*! \brief Swap the the ids of the specified objects. The method will raise errors if the objects are the same,
211 		or some of them are system object. The boolean param enables the id swap between ordinary object and
212 		cluster level objects (database, tablespace and roles). */
213 		static void swapObjectsIds(BaseObject *obj1, BaseObject *obj2, bool enable_cl_obj_swap);
214 
215 		//! \brief Changes the current object id to the most recent global id value.
216 		static void updateObjectId(BaseObject *obj);
217 
218 		//! \brief Clears all the attributes used by the SchemaParser
219 		void clearAttributes();
220 
221 		/*! \brief Returns the cached code for the specified code type. This method returns an empty
222 		 string in case of no code is cached */
223 		QString getCachedCode(unsigned def_type, bool reduced_form);
224 
225 		/*! \brief Configures the DIF_SQL attribute depending on the type of the object. This attribute is used to know how
226 		ALTER, COMMENT and DROP commands must be generated. Refer to schema files for comments, drop and alter. */
227 		void setBasicAttributes(bool format_name);
228 
229 		/*! \brief Compares two xml buffers and returns if they differs from each other. The user can specify which attributes
230 	and tags must be ignored when makin the comparison. NOTE: only the name for attributes and tags must be informed */
231 		bool isCodeDiffersFrom(const QString &xml_def1, const QString &xml_def2, const vector<QString> &ignored_attribs, const vector<QString> &ignored_tags);
232 
233 		/*! \brief Copies the non-empty attributes on the map at parameter to the own object attributes map. This method is used
234 		as an auxiliary when generating alter definition for some objects. When one or more attributes are copied an especial
235 		attribute is inserted (HAS_CHANGES) in order to help the atler generatin process to identify which attributes are
236 		products of comparison */
237 		void copyAttributes(attribs_map &attribs);
238 
239 		static QString getAlterDefinition(QString sch_name, attribs_map &attribs, bool ignore_ukn_attribs=false, bool ignore_empty_attribs=false);
240 
241 		QString getAlterCommentDefinition(BaseObject *object, attribs_map attributes);
242 
243 	public:
244 		//! \brief Maximum number of characters that an object name on PostgreSQL can have
245 		static constexpr int ObjectNameMaxLength=63;
246 
247 		/*! \brief The default number of objects supposed to be stored in objects list.
248 		 * This values is just a reference (hint) and is used to preallocate (reserve) space on vectors which handle objects
249 		 * to avoid excessive allocation/deallocation by resizing the vectors due to insert operation */
250 		static constexpr unsigned DefMaxObjectCount=20;
251 
252 		BaseObject();
~BaseObject(void)253 		virtual ~BaseObject(void){}
254 
255 		//! \brief Returns the reference to the database that owns the object
256 		BaseObject *getDatabase();
257 
258 		/*! \brief Defines a specific attribute in the attribute list used to generate the code definition.
259 		 This method can be used when a class needs to directly write some attributes of
260 		 another class but does not have permission. */
261 		void setAttribute(const QString &attrib, const QString &value);
262 
263 		/*! \brief Returns whether the object name is in conformity with the PostgreSQL object naming rule.
264 		 (e.g. 63 bytes long and chars in set [a-zA-z0-9_] */
265 		static bool isValidName(const QString &name);
266 
267 		/*! \brief Formats the passed name following the PostgreSQL object naming rule.
268 		 The 'is_operator' parameter indicates that the passed name is a for an operator
269 		 this is the only type of object that accepts characters outside of the alphabet
270 		 (e.g. mathematical signs) on the composition of its name.
271 		 In this case, the formatting function just ignores some validations if the parameter is checked */
272 		static QString formatName(const QString &name, bool is_operator=false);
273 
274 		//! \brief Returns the object's type translated name related to the passed object type
275 		static QString getTypeName(ObjectType obj_type);
276 
277 		/*! \brief Returns the object's type translated name related to the passed object type id (in string format).
278 		The string parameter is the value returned by getSchemaName() */
279 		static QString getTypeName(const QString &type_str);
280 
281 		//! \brief Returns the object's type related to the passed type name
282 		static ObjectType getObjectType(const QString &type_name);
283 
284 		/*! \brief Returns the schema identifier used to generate the code definition related to the
285 		 passed object type */
286 		static QString getSchemaName(ObjectType obj_type);
287 
288 		//! \brief Returns the keyword related to the object on SQL language
289 		static QString getSQLName(ObjectType obj_type);
290 
291 		//! \brief Returns the current value of the global object id counter
292 		static unsigned getGlobalId();
293 
294 		static void setEscapeComments(bool value);
295 
296 		static bool isEscapeComments();
297 
298 		//! \brief Defines the comment of the object that will be attached to its SQL definition
299 		virtual void setComment(const QString &comment);
300 
301 		//! \brief Defines the objects name. If the passed name isn't valid it'll raise an error
302 		virtual void setName(const QString &name);
303 
304 		/*! \brief Defines the object's alias (human readable / friendly name). An alias is used when the database model is being
305 		 * displayed in compact view. This method raises an error when the provided name is larger than 63 bytes
306 		 * (the same rule for PostgreSQL names length) */
307 		virtual void setAlias(const QString &alias);
308 
309 		//! \brief Toggles the object's modify protection
310 		virtual void setProtected(bool value);
311 
312 		/*! \brief Defines the schema that the object belongs. An error is raised if the
313 		 passed schema is not valid or the object does not accepts the use of schemas. */
314 		virtual void setSchema(BaseObject *schema);
315 
316 		/*! \brief Defines the owner of the object. An error is raised if the
317 		 passed owner is not valid or the object does not accepts the use of owners. */
318 		virtual void setOwner(BaseObject *owner);
319 
320 		/*! \brief Defines the tablespace which the objects will use. An error is raised if the
321 		 passed tablespace is not valid or the object does not accepts the use of tablespaces. */
322 		virtual void setTablespace(BaseObject *tablespace);
323 
324 		/*! \brief Defines the collation which the objects will use. An error is raised if the
325 		 passed collation is not valid or the object does not accepts the use of collations. */
326 		virtual void setCollation(BaseObject *collation);
327 
328 		//! \brief Disables the SQL code commenting it on generation
329 		virtual void setSQLDisabled(bool value);
330 
331 		//! \brief Assign to the object a set of SQL commands to be appended to it's definition
332 		void setAppendedSQL(const QString &sql);
333 
334 		//! \brief Assign to the object a set of SQL commands to be prepended to it's definition
335 		void setPrependedSQL(const QString &sql);
336 
337 		//! \brief Returns if the generated SQL is commented
338 		bool isSQLDisabled();
339 
340 		//! \brief Defines if the object is a system protected object
341 		virtual void setSystemObject(bool value);
342 
343 		//! \brief Returns if the object is a system protected object
344 		bool isSystemObject();
345 
346 		/*! \brief Returns the object's name. The parameter 'format' is used to get
347 		 the name properly formated (using quotes when there is uppercase char or extended utf-8),
348 		 the parameter 'prepend_schema' includes the schema name on the objects name (defult) */
349 		virtual QString getName(bool format=false, bool prepend_schema=true);
350 
351 		//! \brief Returns the object's alias (user friendly) name
352 		virtual QString getAlias();
353 
354 		//! \brief Returns the name of the object with schema name (when available) prepended by default
355 		virtual QString getSignature(bool format=true);
356 
357 		//! \brief Returns the object's comment (in raw form)
358 		QString getComment();
359 
360 		/*! \brief Returns the object's comment in such way that the quotes are escaped as well,
361 		 * if escape_special_chars is true, any line break and tabulation is returned in form \n and \t */
362 		QString getEscapedComment(bool escape_special_chars);
363 
364 		//! \brief Returns the object's type
365 		ObjectType getObjectType();
366 
367 		//! \brief Returns the object's type name
368 		QString getTypeName();
369 
370 		//! \brief Returns the object's schema name used to generate code definition
371 		QString getSchemaName();
372 
373 		//! \brief Returns the keyword related to the object type
374 		QString getSQLName();
375 
376 		//! \brief Returns the schema that the objects is part
377 		BaseObject *getSchema();
378 
379 		//! \brief Returns the owner of the object
380 		BaseObject *getOwner();
381 
382 		//! \brief Returns the tablespace that the object is part
383 		BaseObject *getTablespace();
384 
385 		//! \brief Returns the collation that the object makes use
386 		BaseObject *getCollation();
387 
388 		QString getAppendedSQL();
389 
390 		QString getPrependedSQL();
391 
392 		//! \brief Returns the object's generated id
393 		unsigned getObjectId();
394 
395 		//! \brief Returns if the object is protected or not
396 		bool isProtected();
397 
398 		//! \brief Assigns an object to other copiyng all the attributes correctly
399 		virtual void operator = (BaseObject &obj);
400 
401 		/*! \brief Forcing the class to be virtual. This means that derivated classes may
402 		 override this method in order to be possible its instatiation. */
403 		virtual QString getCodeDefinition(unsigned)=0;
404 
405 		/*! \brief Returns the object's SQL or XML code definition. The attribute 'reduced_form'
406 		 indicates that the code generation will be an XML minimum representation
407 		 of the object. See schema file for: functions, schemas, domains, types. */
408 		virtual QString getCodeDefinition(unsigned def_type, bool reduced_form);
409 
410 		/*! \brief Returns the SQL definition in form of ALTER commands containing the differences between the this and 'object'.
411 		This form do the camparison considering the difference on the objects' names (ignore_name_diff=false). This method
412 		is used in cases when the objects' name differences are important and can't be discarded */
413 		virtual QString getAlterDefinition(BaseObject *object);
414 
415 		/*! \brief Returns the SQL definition in form of ALTER commands containing the differences between the this and 'object'.
416 		The paramenter ignore_name_diff when true will cause the method to not generate a ALTER ... RENAME TO when the name of
417 		objects differs. */
418 		virtual QString getAlterDefinition(BaseObject *object, bool ignore_name_diff);
419 
420 		//!brief Returns the DROP statement for the object
421 		virtual QString getDropDefinition(bool cascade);
422 
423 		//! \brief Returns if the specified type accepts to have a schema assigned
424 		static bool acceptsSchema(ObjectType obj_type);
425 
426 		//! \brief Returns if the specified type accepts to have an owner assigned
427 		static bool acceptsOwner(ObjectType obj_type);
428 
429 		//! \brief Returns if the specified type accepts to have a tablespace assigned
430 		static bool acceptsTablespace(ObjectType obj_type);
431 
432 		//! \brief Returns if the specified type accepts to have a collation assigned
433 		static bool acceptsCollation(ObjectType obj_type);
434 
435 		//! \brief Returns if the specified type accepts to have appended sql commands
436 		static bool acceptsCustomSQL(ObjectType obj_type);
437 
438 		/*! \brief Returns if the specified type accepts the use of ALTER commands in order to change their attributes
439 		This is different from PostgreSQL implementation. In pgModeler, an object accepts ALTER when an attribute
440 		other than name, schema or owner can be changed. */
441 		static bool acceptsAlterCommand(ObjectType obj_type);
442 
443 		//! \brief Returns if the specified type accepts the use of DROP commands
444 		static bool acceptsDropCommand(ObjectType obj_type);
445 
446 		//! \brief Returns if the specified type accepts an alias (friendly name)
447 		static bool acceptsAlias(ObjectType obj_type);
448 
449 		//! \brief Returns if the object accepts to have a schema assigned
450 		bool acceptsSchema();
451 
452 		//! \brief Returns if the object accepts to have an owner assigned
453 		bool acceptsOwner();
454 
455 		//! \brief Returns if the object accepts to have a tablespace assigned
456 		bool acceptsTablespace();
457 
458 		//! \brief Returns if the object accepts to have a collation assigned
459 		bool acceptsCollation();
460 
461 		//! \brief Returns if the object accepts to have appended sql commands
462 		bool acceptsCustomSQL();
463 
464 		//! \brief Returns if the object accepts the use of ALTER commands to have its attributes changed
465 		bool acceptsAlterCommand();
466 
467 		//! \brief Returns if the object accepts the use of DROP commands
468 		bool acceptsDropCommand();
469 
470 		/*! \brief Marks the current cached code as invalid and forces its regenaration.
471 				Some key attributes / setters in the base classes BaseObject, BaseTable and BaseRelationship
472 				will automatically invalidate the code but for all other setters / attributes the user must call
473 				this method explicitly in order to force the regeneration of the code.
474 				This method has no effect when the cached code support is disables. See enableCachedCode() */
475 		virtual void setCodeInvalidated(bool value);
476 
477 		virtual void configureSearchAttributes();
478 
479 		//! \brief Returns if the code (sql and xml) is invalidated
480 		bool isCodeInvalidated();
481 
482 		/*! \brief Compares the xml code between the "this" object and another one. The user can specify which attributes
483 		and tags must be ignored when makin the comparison. NOTE: only the name for attributes and tags must be informed */
484 		virtual bool isCodeDiffersFrom(BaseObject *object, const vector<QString> &ignored_attribs={}, const vector<QString> &ignored_tags={});
485 
486 		/*! \brief Enable/disable the use of cached sql/xml code. When enabled the code generation speed is hugely increased
487 				but the downward is an increasing on memory usage. Make sure to every time when an attribute of any instance derivated
488 				of this class changes you need to call setCodeInvalidated() in order to force the update of the code cache */
489 		static void enableCachedCode(bool value);
490 
491 		/*! \brief Returns the valid object types in a vector. The types
492 		ObjectType::ObjBaseObject, TYPE_ATTRIBUTE and ObjectType::ObjBaseTable aren't included in return vector.
493 		By default table objects (columns, trigger, constraints, etc) are included. To
494 		avoid the insertion of these types set the boolean param to false. */
495 		static vector<ObjectType> getObjectTypes(bool inc_table_objs=true, vector<ObjectType> exclude_types={});
496 
497 		/*! \brief Returns the valid object types that are child or grouped under the specified type.
498 	This method works a litte different from getObjectTypes() since this latter returns all valid types
499 	and this one returns only the valid types for the current specified type. For now the only accepted
500 	types are ObjectType::Database, ObjectType::Schema, ObjectType::Table, ObjectType::ForeignTable */
501 		static vector<ObjectType> getChildObjectTypes(ObjectType obj_type);
502 
503 		//! \brief Returns true when the child_type is in the list of children types of the parent_type
504 		static bool isChildObjectType(ObjectType parent_type, ObjectType child_type);
505 
506 		/*! \brief Sets the default version when generating the SQL code. This affects all instances of classes that
507 				is based upon this one */
508 		static void setPgSQLVersion(const QString &ver);
509 
510 		//! \brief Returns the current version for SQL code generation
511 		static QString getPgSQLVersion();
512 
513 		//! \brief Returns the set of attributes used by the search mechanism
514 		attribs_map getSearchAttributes();
515 
516 		friend class DatabaseModel;
517 		friend class ModelValidationHelper;
518 		friend class DatabaseImportHelper;
519 		friend class SwapObjectsIdsWidget;
520 		friend class ModelWidget;
521 };
522 
523 #endif
524