/***** * * TOra - An Oracle Toolkit for DBA's and developers * Copyright (C) 2003-2005 Quest Software, Inc * Portions Copyright (C) 2005 Other Contributors * * 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; only version 2 of * the License is valid for this program. * * 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. * * As a special exception, you have permission to link this program * with the Oracle Client libraries and distribute executables, as long * as you follow the requirements of the GNU GPL in regard to all of the * software in the executable aside from Oracle client libraries. * * Specifically you are not permitted to link this program with the * Qt/UNIX, Qt/Windows or Qt Non Commercial products of TrollTech. * And you are not permitted to distribute binaries compiled against * these libraries without written consent from Quest Software, Inc. * Observe that this does not disallow linking to the Qt Free Edition. * * You may link this product with any GPL'd Qt library such as Qt/Free * * All trademarks belong to their respective owners. * *****/ #ifndef TO_EXTRACT #define TO_EXTRACT #include "config.h" #include #include #include #include #include #include class QWidget; class toConnection; #include "tosqlparse.h" // Liberally ported from DDL::Oracle 1.06 // Copyright (c) 2000, 2001 Richard Sutherland - United States of America /** * This class can be used to reverse engineered database objects. */ class toExtract { public: /** Describes an available datatype for the database. */ class datatype { private: QString Name; int MaxLength; int MaxPrecision; public: /** Create a new datatype description. * @param name Name of datatype. * @param maxLength Maximum length of parameter if length is needed. * @param maxPrecision Maximum precision of parameter if precision is supported. */ datatype(const QString &name, int maxLength = -1, int maxPrecision = -1) : Name(name), MaxLength(maxLength), MaxPrecision(maxPrecision) { } /** Returns true if type has length specification. */ bool hasLength() { return MaxLength != -1; } /** Returns true if type has precision specification. */ bool hasPrecision() { return MaxPrecision != -1; } /** Get the maximum length value. */ int maxLength() { return MaxLength; } /** Get the maximum precision of the datatype. */ int maxPrecision() { return MaxPrecision; } /** Get the name of the datatype. */ const QString &name() { return Name; } /** Implemented so that you can easily sort a list of them. Just compares the names. */ bool operator < (const datatype &dat) const { return Name < dat.Name; } /** Implemented so that you can easily sort a list of them. Just compares the names. */ bool operator == (const datatype &dat) const { return Name == dat.Name; } }; /** This is an abstract class to implement part of an extractor for a database. Observe * that an extractor must be stateless and threadsafe except for constructors and * destructors. Use the toExtract::context function for saving context. */ class extractor { protected: /** Register an operation to be handled by this extractor. * @param db Database this extractor works on. * @param oper What kind of operation to implement. Can be one of CREATE, * DESCRIBE, MIGRATE or DROP. * @param type The type of object that this is implemented for. Database specific. */ void registerExtract(const QString &db, const QString &oper, const QString &type); /** Unregister an operation to be handled by this extractor. * @param db Database this extractor works on. * @param oper What kind of operation to implement. Can be one of CREATE, * DESCRIBE, MIGRATE or DROP. * @param type The type of object that this is implemented for. Database specific. */ void unregisterExtract(const QString &db, const QString &oper, const QString &type); public: /** Create an extractor. Normally called from a statical instantiator. Should register * objects it can handle @ref registerExtract. Apart from the objects it handles one * extractor per database can also register an empty operation and type parameter to * @ref registerExtract which will be called to initialize an extractor once per * constructed toExtract object. * operation. */ extractor(); /** Destructor. */ virtual ~extractor(); /** Initiate an extractor for a given connection. Can be used to set up states necessary * for further processing. Should probably set blocksize to be used for resizing (@ref * toExtract::setBlocksize). * @param ext Extractor to generate script. */ virtual void initialize(toExtract &ext) const; /** Called to generate a script to recreate a database object. * @param ext Extractor to generate script. * @param stream Stream to write script to. * @param type Type of object to recreate. * @param schema Specify the schema of the output script or description. If empty * don't specify any object. If the string "1" use same object as input. * Otherwise use the specified schema. * @param owner Owner of database object. * @param name Name of database object. * @return A string containing a script to recreate an object. */ virtual void create(toExtract &ext, QTextStream &stream, const QString &type, const QString &schema, const QString &owner, const QString &name) const; /** Called to describe a database object. * @param ext Extractor to generate script. * @param lst List of descriptions for the object. Should be appended. * @param type Type of object to recreate. * @param schema Specify the schema of the output script or description. If empty * don't specify any object. If the string "1" use same object as input. * Otherwise use the specified schema. * @param owner Owner of database object. * @param name Name of database object. */ virtual void describe(toExtract &ext, std::list &lst, const QString &type, const QString &schema, const QString &owner, const QString &name) const; /** Called to generate a script to migrate a database object from one description to * another description. * @param ext Extractor to generate script. * @param type Type of object to migrate. * @param src Source description list. * @param dst Destination description list. * @return A script to change the src database object to dst. */ virtual void migrate(toExtract &ext, QTextStream &stream, const QString &type, std::list &src, std::list &dst) const; /** Called to generate a script to drop an object. * @param ext Extractor to generate script. * @param type Type of object to recreate. * @param schema Specify the schema of the output script or description. If empty * don't specify any object. If the string "1" use same object as input. * Otherwise use the specified schema. * @param owner Owner of database object. * @param name Name of database object. * @return A string containing a script to recreate an object. */ virtual void drop(toExtract &ext, QTextStream &stream, const QString &type, const QString &schema, const QString &owner, const QString &name) const; /** Get the available datatypes for the database. */ virtual std::list datatypes() const; }; private: toConnection &Connection; QWidget *Parent; // Attributes QString Schema; QString Resize; bool Code; bool Comments; bool Constraints; bool Contents; bool Grants; bool Heading; bool Indexes; bool Parallel; bool Partition; bool Prompt; bool Storage; bool Initialized; int CommitDistance; // Database info int BlockSize; std::list Initial; std::list Next; std::list Limit; // Context, can be used by the extractor to save context std::map Context; // Stuff to handle extractors static std::map *Extractors; static void allocExtract(void); static QString extractorName(const QString &db, const QString &oper, const QString &type); static extractor *findExtractor(toConnection &conn, const QString &oper, const QString &type); extractor *findExtractor(const QString &oper, const QString &type) { return findExtractor(Connection, oper, type); } void initialize(void); // General internal functions /** Parse an object string to get owner and name of the object. * @param object Object string on the format {owner}.{name}. * @param owner Reference to string which will get the object owner. * @param name Reference to string which will get the object name. */ void parseObject(const QString &object, QString &owner, QString &name); void setSizes(void); void rethrow(const QString &what, const QString &object, const QString &exc); QString generateHeading(const QString &action, std::list &list); static std::map > migrateGroup(std::list &grpLst); public: /** Create a new extractor. * @param conn Connection to extract from. * @param parent Parent widget of progress indicator. */ toExtract(toConnection &conn, QWidget *parent); /** Create script to recreate list of objects. * @param object List of object. This has the format {type}:{schema}.{object}. * The type is database dependent but can as an example be of * CONSTRAINT, DATABASE LINK, EXCHANGE INDEX, * EXCHANGE TABLE, FUNCTION, INDEX, MATERIALIZED VIEW, * MATERIALIZED VIEW LOG, PACKAGE, PACKAGE BODY, PROCEDURE, * PROFILE, ROLE, ROLE GRANTS, ROLLBACK SEGMENT, SEQUENCE, * SNAPSHOT, SNAPSHOT LOG, SYNONYM, TABLE, TABLE FAMILY, * TABLE CONTENTS, TABLE REFERENCES, TABLESPACE, TRIGGER, * TRIGGER, TYPE, USER, USER GRANTS for Oracle databases. * @return A string containing a script to recreate the specified objects. */ QString create(std::list &object) { QString ret; QTextStream s(&ret, IO_WriteOnly); create(s, object); return ret; } /** Create script to recreate list of objects. * @param stream Stream to write result to. * @param object List of object. This has the format {type}:{schema}.{object}. * The type is database dependent but can as an example be of * CONSTRAINT, DATABASE LINK, EXCHANGE INDEX, * EXCHANGE TABLE, FUNCTION, INDEX, MATERIALIZED VIEW, * MATERIALIZED VIEW LOG, PACKAGE, PACKAGE BODY, PROCEDURE, * PROFILE, ROLE, ROLE GRANTS, ROLLBACK SEGMENT, SEQUENCE, * SNAPSHOT, SNAPSHOT LOG, SYNONYM, TABLE, TABLE FAMILY, * TABLE CONTENTS, TABLE REFERENCES, TABLESPACE, TRIGGER, * TRIGGER, TYPE, USER, USER GRANTS for Oracle databases. */ void create(QTextStream &stream, std::list &object); /** Create a description of objects. * @param object List of object. This has the format {type}:{schema}.{object}. * The type is database dependent but can as an example be of * CONSTRAINT, DATABASE LINK, EXCHANGE INDEX, * EXCHANGE TABLE, FUNCTION, INDEX, MATERIALIZED VIEW, * MATERIALIZED VIEW LOG, PACKAGE, PACKAGE BODY, PROCEDURE, * PROFILE, ROLE, ROLE GRANTS, ROLLBACK SEGMENT, SEQUENCE, * SNAPSHOT, SNAPSHOT LOG, SYNONYM, TABLE, TABLE FAMILY, * TABLE CONTENTS, TABLE REFERENCES, TABLESPACE, TRIGGER, * TRIGGER, TYPE, USER, USER GRANTS for Oracle databases. * @return A list of strings describing the objects. Each string should be * considered like a list of strings separated by the character '\001'. * The later in each string the smaller item the change and it is hierachical. */ std::list describe(std::list &object); /** Create script to drop a list of objects. * @param object List of object. This has the format {type}:{schema}.{object}. * The type is database dependent but can as an example be of * CONSTRAINT, DATABASE LINK, EXCHANGE INDEX, * EXCHANGE TABLE, FUNCTION, INDEX, MATERIALIZED VIEW, * MATERIALIZED VIEW LOG, PACKAGE, PACKAGE BODY, PROCEDURE, * PROFILE, ROLE, ROLE GRANTS, ROLLBACK SEGMENT, SEQUENCE, * SNAPSHOT, SNAPSHOT LOG, SYNONYM, TABLE, TABLE FAMILY, * TABLE CONTENTS, TABLE REFERENCES, TABLESPACE, TRIGGER, * TRIGGER, TYPE, USER, USER GRANTS for Oracle databases. * @return A string containing a script to drop the specified objects. */ QString drop(std::list &object) { QString ret; QTextStream s(&ret, IO_WriteOnly); drop(s, object); return ret; } /** Create script to drop a list of objects. * @param stream Stream to write result to. * @param object List of object. This has the format {type}:{schema}.{object}. * The type is database dependent but can as an example be of * CONSTRAINT, DATABASE LINK, EXCHANGE INDEX, * EXCHANGE TABLE, FUNCTION, INDEX, MATERIALIZED VIEW, * MATERIALIZED VIEW LOG, PACKAGE, PACKAGE BODY, PROCEDURE, * PROFILE, ROLE, ROLE GRANTS, ROLLBACK SEGMENT, SEQUENCE, * SNAPSHOT, SNAPSHOT LOG, SYNONYM, TABLE, TABLE FAMILY, * TABLE CONTENTS, TABLE REFERENCES, TABLESPACE, TRIGGER, * TRIGGER, TYPE, USER, USER GRANTS for Oracle databases. * @return A string containing a script to drop the specified objects. */ void drop(QTextStream &stream, std::list &object); /** Called to generate a script to migrate a database object from one description to * another description. * @param stream Stream to write result to. * @param src Source description list, generated by describes for the same database. * @param dst Destination description list, generated by describes for the same database. * @return A script to change the src database object to dst. */ QString migrate(std::list &drpLst, std::list &crtLst) { QString ret; QTextStream s(&ret, IO_WriteOnly); migrate(s, drpLst, crtLst); return ret; } /** Called to generate a script to migrate a database object from one description to * another description. * @param stream Stream to write result to. * @param src Source description list, generated by describes for the same database. * @param dst Destination description list, generated by describes for the same database. * @return A script to change the src database object to dst. */ void migrate(QTextStream &stream, std::list &drpLst, std::list &crtLst); /** Set a context for this extractor. * @param name Name of this context * @param val Value of this context */ void setState(const QCString &name, const QVariant &val); /** Get the value of a context for the current extractor. * @param name Name of the context to extract. * @return The value of the context. */ QVariant state(const QCString &name); /** Set the schema of the extraction. * @param schema Specify the schema of the output script or description. If empty * don't specify any object. If the string "1" use same object as input. * Otherwise use the specified schema. */ void setSchema(const QString &schema) { Schema = schema; } /** Set sizes to use for resize of object on extraction. * @param A list of sizes separated by ':'. Should be an even multiple of three where * the first value is the largest current size to use these values. The next * value is the initial value to use, the last is the next increment value to * use. As a special case the string "1" can be used to set up auto resize. */ void setResize(const QString &resize) { Resize = resize; setSizes(); } /** Set inclusion of prompts. * @param prompt If prompt generation should be generated. */ void setPrompt(bool prompt) { Prompt = prompt; } /** Include heading in scripts. * @param heading Include heading in scripts. */ void setHeading(bool heading) { Heading = heading; } /** Include constraints in extraction. * @param constraints Include constraints. */ void setConstraints(bool constraints) { Constraints = constraints; } /** Include indexes in extraction. * @param indexes Include indexes. */ void setIndexes(bool indexes) { Indexes = indexes; } /** Include grants in extraction. * @param val Include grants. */ void setGrants(bool val) { Grants = val; } /** Include storage specification in extraction. * @param val Include storage specification. */ void setStorage(bool val) { Storage = val; } /** Include parallel specification in extraction. * @param val Include parallel specification. */ void setParallel(bool val) { Parallel = val; } /** Include partition specification in extraction. * @param val Include partition specification. */ void setPartition(bool val) { Partition = val; } /** Include contents of tables in scripts. * @param val Include contents of tables. * @param commitdistance The commit distance of the contents 0 means whole tables. */ void setContents(bool val, int commitdistance) { Contents = val; CommitDistance = commitdistance; } /** Include comments in extraction. * @param val Include indexes. */ void setComments(bool val) { Comments = val; } /** Include code in extraction. * @param val Include code. */ void setCode(bool val) { Code = val; } /** Set blocksize of database. * @param val New value of blocksize. */ void setBlockSize(int val) { BlockSize = val; setSizes(); } /** Get schema specification. * @return Schema specification. * @see setSchema */ const QString &getSchema(void) { return Schema; } /** Get resize specification. * @return Resize specification. * @see setResize */ bool getResize(void) { return !Resize.isEmpty(); } /** Check if prompt are generated. * @return If prompts are generated. */ bool getPrompt(void) { return Prompt; } /** Check if headings are generated. * @return If headings are generated. */ bool getHeading(void) { return Heading; } /** Check if constraints are generated. * @return If constraints are generated. */ bool getConstraints(void) { return Constraints; } /** Check if indexes are generated. * @return If indexes are generated. */ bool getIndexes(void) { return Indexes; } /** Check if grants are generated. * @return If grants are generated. */ bool getGrants(void) { return Grants; } /** Check if storage specification are generated. * @return If storage specification are generated. */ bool getStorage(void) { return Storage; } /** Check if parallell specification are generated. * @return If parallell specification are generated. */ bool getParallel(void) { return Parallel; } /** Check if partition specification are generated. * @return If partition specification are generated. */ bool getPartition(void) { return Partition; } /** Check if contents of tables are generated. * @return If content is generated. */ bool getContents(void) { return Contents; } /** Get the distance of the commits when content is generated. * @return Commit distance. */ int getCommitDistance(void) { return CommitDistance; } /** Check if comments are generated. * @return If comments are generated. */ bool getComments(void) { return Comments; } /** Check if code is generated. * @return If code is generated. */ bool getCode(void) { return Code; } /** Get blocksize. */ int getBlockSize(void) { return BlockSize; } /** Get the connection this extractor is working on. */ toConnection &connection() { return Connection; } /** Fill in the initial and next value for an object currently holding a @ref number of * allocated blocks. Uses the resize or default sizes. * @param blocks Blocks currently allocated. * @param initial New initial value. * @param next New next value. */ void initialNext(const QString &blocks, QString &initial, QString &next); /** Get the schema name specified by the extractor setup. Will include the following '.' * if needed. * @param owner Owner of object to get schema for. * @param desc Used from describe and not to generate script. * @return The translated schema. */ QString intSchema(const QString &owner, bool desc); /** Get the available datatypes for a database. * @return A list of datatypes. */ std::list datatypes(); /** Utility function, creates a statement from the start to the end specified by the * parameters. The connection used to specify parsing is the one of the extractor. * @param start Start of parameters. * @param end End of parameters. * @return The indented statement. */ QString createFromParse(std::list::iterator start, std::list::iterator end); /** Create a source and destination object list to two other lists * containing dropped and created objects or attributes. * @param source Source list input (Will not be modified). * @param destination Destination list input (Will not be modified). * @param drop Drop list output (Will be overwritten). * @param create Create list output (Will be overwritten). */ static void srcDst2DropCreate(std::list &source, std::list &destination, std::list &drop, std::list &creat); /** Check if a database is supported at all by the extractor. * @param conn Connection to check for support. * @return True if the database is supported. */ static bool canHandle(toConnection &conn); /** Add a list to description. * @param ret The return list to add a line to. * @param ctx The current description context. * @param arg1 First extra argument to add. */ static void addDescription(std::list &ret, const std::list &ctx, const QString &arg1 = QString::null, const QString &arg2 = QString::null, const QString &arg3 = QString::null, const QString &arg4 = QString::null, const QString &arg5 = QString::null, const QString &arg6 = QString::null, const QString &arg7 = QString::null, const QString &arg8 = QString::null, const QString &arg9 = QString::null); /** Split a description line into its components. * @param str The description line to split. * @return The list of components. */ static std::list splitDescribe(const QString &str); /** Get the part of a description indicated by the level * @param str Description string * @param level The level to get (0 is the first level) */ static QString partDescribe(const QString &str, int level); /** Get the context of a given level. * @param str Description string * @param level The level to get the context for (1 is the first to not return empty string. * @return The context, if not enough parts are available null is returned. */ static QString contextDescribe(const QString &str, int level); /** Used to get column information from a describe list */ struct columnInfo { /** Name of column */ QString Name; /** Definition of column */ QString Definition; /** Extra data for the column (Except for order which has own field. */ std::map Data; /** Order of the column. Used for sorting. */ int Order; /** Create column information from name. */ columnInfo(const QString &name) : Name(name) { Order = 0; } /** Implement sort order based only on Order field. */ bool operator <(const columnInfo &inf) { return Order < inf.Order; } /** Implement sort order based only on Order field. */ bool operator ==(const columnInfo &inf) { return Order == inf.Order; } }; /** Parse a column description and return a sorted list of column data. * @param begin The iterator indicating the beginning to start searching from (Inclusive). * @param end The iterator indicating the end to end searching at (Not inclusive). * @param level Number of levels of context to discard before looking for "COLUMN" definition. * @return The list of column definitions. Sorted by column order. */ static std::list parseColumnDescription(std::list::const_iterator begin, std::list::const_iterator end, int level = 3); /** Parse a column description and return a sorted list of column data. * @param description A description list. Will go through entire list. * @param level Number of levels of context to discard before looking for "COLUMN" definition. * @return The list of column definitions. Sorted by column order. */ static std::list parseColumnDescription(const std::list &description, int level = 3) { return parseColumnDescription(description.begin(), description.end(), level); } friend class extractor; }; #endif