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