package.xml100644 765 765 116225 11150346546 6443 MDB2_Schema pear.php.net MDB2 XML based database schema manager PEAR::MDB2_Schema enables users to maintain RDBMS independant schema files in XML that can be used to create, alter and drop database entities and insert data into a database. Reverse engineering database schemas from existing databases is also supported. The format is compatible with both PEAR::MDB and Metabase. Lukas Kahwe Smith lsmith smith@pooteeweet.org no Igor Feghali ifeghali ifeghali@php.net yes Helgi Thormar dufuz dufuz@php.net no 2009-02-22 0.8.5 0.8.0 beta beta BSD License - PEAR dependency updated (Bug #15923) - XML_DTD dependency updated (past releases of XML_DTD doesn't works anymore. release 0.5.1 works only with PHP 5). - Fixed 'disable_queries' and 'show_structure' options that were malfunctioning in mdb2_schematool web version - Added an option to not drop obsolete tables when updating (Request #15278). It defaults not to drop, which reverts the behavior introduced in Release 0.8.3 open todo items: - Clean up output of getDefinitionFromDatabase(). Sync it with Parser and Parser2. - Automatically load reserved keywords - Make MDB2_Schema loadable via MDB2_Driver_Common::loadModule() (Bug #8270) - Allow simple if statements that mean that anything enclosed is only executed if it meets certain criterias based on that version number (or some other variable). This would enable people to add DML statements that are only executed when updating from a specific version. - Modularize Writer code or remake it - Add specific error codes for Validate class - Add support for ORDER clauses on UPDATEs (to resolve the duplicate key problem) - Update description.schema.xml - Create unit test for comparedefinitions() - Create unit test for initializetable() - Create unit test to compare the expected array definition with what is parsed - Improve validateDataFieldValue() to validate <column> - Provide more info on MDB2_Schema_Validate errors (output parsed value and expected value) - Views support - Fulltext index support - PKs as constraints, not indices - Creation of constraints only after all tables have been created/updated to avoid invalid references. 4.3.2 1.7.0 MDB2 pear.php.net 2.5.0b1 XML_Parser pear.php.net 1.2.8 XML_DTD pear.php.net 0.5.1 XML_Serializer pear.php.net 0.18.0 0.8.5 0.8.0 beta beta 2009-02-22 BSD License - PEAR dependency updated (Bug #15923) - XML_DTD dependency updated (past releases of XML_DTD doesn't works anymore. release 0.5.1 works only with PHP 5). - Fixed 'disable_queries' and 'show_structure' options that were malfunctioning in mdb2_schematool web version - Added an option to not drop obsolete tables when updating (Request #15278). It defaults not to drop, which reverts the behavior introduced in Release 0.8.3 open todo items: - Clean up output of getDefinitionFromDatabase(). Sync it with Parser and Parser2. - Automatically load reserved keywords - Make MDB2_Schema loadable via MDB2_Driver_Common::loadModule() (Bug #8270) - Allow simple if statements that mean that anything enclosed is only executed if it meets certain criterias based on that version number (or some other variable). This would enable people to add DML statements that are only executed when updating from a specific version. - Modularize Writer code or remake it - Add specific error codes for Validate class - Add support for ORDER clauses on UPDATEs (to resolve the duplicate key problem) - Update description.schema.xml - Create unit test for comparedefinitions() - Create unit test for initializetable() - Create unit test to compare the expected array definition with what is parsed - Improve validateDataFieldValue() to validate <column> - Provide more info on MDB2_Schema_Validate errors (output parsed value and expected value) - Views support - Fulltext index support - PKs as constraints, not indices - Creation of constraints only after all tables have been created/updated to avoid invalid references. 0.8.4 0.8.0 beta beta 2008-11-17 BSD License - fixed warning in validateTable() that was introduced in last release (Bug #15055) - fixed interpreter for mdb2_schematool, plus it is now been installed to bin_dir (now, really!) - mdb2_schematool has a new feature: initialize database - mdb2_schematool can now be used to dump data and/or database structure open todo items: - Clean up output of getDefinitionFromDatabase(). Sync it with Parser and Parser2. - Automatically load reserved keywords - Make MDB2_Schema loadable via MDB2_Driver_Common::loadModule() (Bug #8270) - Allow simple if statements that mean that anything enclosed is only executed if it meets certain criterias based on that version number (or some other variable). This would enable people to add DML statements that are only executed when updating from a specific version. - Modularize Writer code or remake it - Add specific error codes for Validate class - Add support for ORDER clauses on UPDATEs (to resolve the duplicate key problem) - Update description.schema.xml - Create unit test for comparedefinitions() - Create unit test for initializetable() - Create unit test to compare the expected array definition with what is parsed - Improve validateDataFieldValue() to validate <column> - Provide more info on MDB2_Schema_Validate errors (output parsed value and expected value) - Views support - Fulltext index support 0.8.3 0.8.0 beta beta 2008-11-16 BSD License - updateDatabase() cannot add UNIQUE attribute to an existing index (Bug #13977). Patch by Holger Schletz - updateDatabase() keeps old default value even though new column has no default (Bug #13836). Patch by Holger Schletz - Obsolete tables and sequences not dropped on updateDatabase() (Bug #13608). Patch by Holger Schletz - Error when creating a new index for a renamed table (Bug #13397) - Makes use of MDB2::databaseExists() to check whether updating database exists (Bug #13073). This feature was removed on previous release and now is back again. - createDatabase() correctly lower/upper database name when portability option deems so. - mdb2_schematool now disables transactions - mdb2_schematool was missing argument "help" - mdb2_schematool moved from "bin" to "scripts" folder. now installs to pear_bin dir - Schema validation not failing when autoincrement field is defined but another column is used as primary key (Bug #14213) - Accepting NOW() as value for timestamp fields on schema validation (Bug #14052). Patch by Holger Schletz - Introducing www/mdb2_schematool that is a rewrite of docs/examples/example.php and is now installed to web root - Web frontend (www/mdb2_schematool) has new options "DBA_username" and "DBA_password" - Tests missing sequences on database dump (Bug #13562). Patch by Luca Corbo - When reverse engineering a database, the XML schema file will have <charset> forced to UTF8 open todo items: - Clean up output of getDefinitionFromDatabase(). Sync it with Parser and Parser2. - Automatically load reserved keywords - Make MDB2_Schema loadable via MDB2_Driver_Common::loadModule() (Bug #8270) - Allow simple if statements that mean that anything enclosed is only executed if it meets certain criterias based on that version number (or some other variable). This would enable people to add DML statements that are only executed when updating from a specific version. - Modularize Writer code or remake it - Add specific error codes for Validate class - Add support for ORDER clauses on UPDATEs (to resolve the duplicate key problem) - Update description.schema.xml - Create unit test for comparedefinitions() - Create unit test for initializetable() - Create unit test to compare the expected array definition with what is parsed - Improve validateDataFieldValue() to validate <column> - Provide more info on MDB2_Schema_Validate errors (output parsed value and expected value) - Views support - Fulltext index support 0.8.2 0.8.0 beta beta 2008-02-23 BSD License - updated dependency - updated license disclaimer in source code files - use quoteIdentifier in getInstructionFields() (Bug #13037) - After database creation, sqlite db connection not usable (Bug #11920) - Supporting Database Charset (Bug #12908) - writeInitialization() fails at given conditions (Bug #12950) - drop usage of listDatabases() (Bug #12636), as a consequence updateDatabase() doesn't check anymore whether updating database exists - index-length documented and included in Parser2 (Bug #12540) - xsl transformation chooses wrong value for length (Bug #12261) - added README file for docs dir - the correct variable name for warning is "warnings" not "operation" in example script - disabled transactions in the example script - introducing mdb2_schematool, a command line tool to dump and load schemas open todo items: - Clean up output of getDefinitionFromDatabase(). Sync it with Parser and Parser2. - Automatically load reserved keywords - Make MDB2_Schema loadable via MDB2_Driver_Common::loadModule() (Bug #8270) - Allow simple if statements that mean that anything enclosed is only executed if it meets certain criterias based on that version number (or some other variable). This would enable people to add DML statements that are only executed when updating from a specific version. - Modularize Writer code or remake it - Add specific error codes for Validate class - Add support for ORDER clauses on UPDATEs (to resolve the duplicate key problem) - Update description.schema.xml - Create unit test for comparedefinitions() - Create unit test for initializetable() - Create unit test to compare the expected array definition with what is parsed - Improve validateDataFieldValue() to validate <column> - Provide more info on MDB2_Schema_Validate errors (output parsed value and expected value) - Views support - Fulltext index support 0.8.1 0.8.0 beta beta 2007-08-30 BSD License - updated dependency open todo items: - Clean up output of getDefinitionFromDatabase(). Sync it with Parser and Parser2. - Automatically load reserved keywords - Make MDB2_Schema loadable via MDB2_Driver_Common::loadModule() (Bug #8270) - Allow simple if statements that mean that anything enclosed is only executed if it meets certain criterias based on that version number (or some other variable). This would enable people to add DML statements that are only executed when updating from a specific version. - Modularize Writer code or remake it - Add specific error codes for Validate class - Add support for ORDER clauses on UPDATEs (to resolve the duplicate key problem) - Update description.schema.xml - Create unit test for comparedefinitions() - Create unit test for initializetable() - Create unit test to compare the expected array definition with what is parsed - Improve validateDataFieldValue() to validate <column> - Provide more info on MDB2_Schema_Validate errors (output parsed value and expected value) - Views support - Fulltext index support 0.8.0 0.8.0 beta beta 2007-08-20 BSD License - Primary Key is removed when updating a table against its XML (Bug #11604) - Added support to INSERT...SELECT syntax, so it is now possible to prevent data loss when rollback an updated database (Bug #10892) - Updated API of getInstructionFields() and getInstructionWhere() - It is now possible to prevent updateDatabase() of overwriting the old schema file - alterDatabaseTables() first add new tables, then remove the old one. it is necessary to save table data before a remove - updateDatabase() was aborting, under certain conditions, when <was> was not found (Bug #11600) - Now validating database definition when reverse engineering (Bug #11604) - createDatabase() has a new parameter that is passed to the database driver to set some options like table engine - Foreign Keys support - It is now possible to assign to a column the value of another column, of the same table, when inserting data - Fixed the HTML etities issue when parsing a schema file (Bug #11676) - XML Documentation, XSD and DST updated to show/expect the attributes in a unique order. Writer and parsers was also updated to handle the attributes in that some order. That said Parser and Parser2 must have the exactly same output for a given XML - Except for table fields, all other database elements are being initialized with all its attributes, no matter if those attributes are present on the XML or not - Many bugs fixed in Parser2, that was not creating a valid database definition - Introduced attribute "fixed" of table field declaration - validateIndex() is now checking whether a index has fields - Validate is not returning MDB2_OK instead of boolean true - XML Documentation and schema validators revised and updated open todo items: - Clean up output of getDefinitionFromDatabase(). Sync it with Parser and Parser2. - Automatically load reserved keywords - Make MDB2_Schema loadable via MDB2_Driver_Common::loadModule() (Bug #8270) - Allow simple if statements that mean that anything enclosed is only executed if it meets certain criterias based on that version number (or some other variable). This would enable people to add DML statements that are only executed when updating from a specific version. - Modularize Writer code or remake it - Add specific error codes for Validate class - Add support for ORDER clauses on UPDATEs (to resolve the duplicate key problem) - Update description.schema.xml - Create unit test for comparedefinitions() - Create unit test for initializetable() - Create unit test to compare the expected array definition with what is parsed - Improve validateDataFieldValue() to validate <column> - Provide more info on MDB2_Schema_Validate errors (output parsed value and expected value) - Views support - Fulltext index support 0.7.2 0.7.2 beta beta 2007-04-07 BSD License - Allow options to be passed in when creating tables (Bug #10278) - Existence of a single index results in no further index creation (Bug #10296) - MDB2_Schema::createTableIndexes() ignores indexes (Bug #10285) - column identifiers quoting problem (Bug #10195) - Handle 'scale' value in DECIMAL field definition (Bug #10475) - fixed phpdoc comment for validateDataField() - all primary keys are given an index name of "primary" (Bug #10457) - example.php should echo xml when no filename is given (Bug #10226) open todo items: - Make MDB2_Schema loadable via MDB2_Driver_Common::loadModule() (Bug #8270) - Add ability to define variables inside the schema (like a version number) - Allow simple if statements that mean that anything enclosed is only executed if it meets certain criterias based on that version number (or some other variable). This would enable people to add DML statements that are only executed when updating from a specific version. - Modularize Writer code or remake it - Add specific error codes for Validate class - Add support for ORDER clauses on UPDATEs (to resolve the duplicate key problem) - Update description.schema.xml - Document how to use the API - Create unit test for comparedefinitions() - Create unit test for initializetable() - Create unit test to compare the expected array definition with what is parsed - HTML entities aren't being parsed correctly - Improve validateDataFieldValue() to validate <column> - Provide more info on MDB2_Schema_Validate errors (output parsed value and expected value) - Views support - Foreign keys support - Fulltext index support 0.7.1 0.7.1 beta beta 2007-02-21 BSD License - Package converted to version 2 - compareDefinition() was trying to update non-changing id field (Bug #8820) - for a moment <default> should be always parsed as string, no matter the field type. this behavior may change in the future. - undefined method MDB2_Schema::quoteIdentifier() (Bug #9172) - added support for explicit NULL (<null></null>) - <value></value> is now correctly being parsed as an empty string - fixed internal bug in Parser that was introduced in revision 1.46 (Bug #9435) - MDB2_Schema_Parser::setData() has been removed - MDB2_Schema_Validate::validateDataField() is validating field data again (Bug #9181) - updated reserved keywords of ibase - updated XML Schema documentation - updated XML Schema example - added a new test case to isBoolean() (empty string) - released the very first approach of the new parser that makes usage of XML_Serializer (alternative parser) open todo items: - Make MDB2_Schema loadable via MDB2_Driver_Common::loadModule() (Bug #8270) - Add ability to define variables inside the schema (like a version number) - Allow simple if statements that mean that anything enclosed is only executed if it meets certain criterias based on that version number (or some other variable). This would enable people to add DML statements that are only executed when updating from a specific version. - Modularize Writer code or remake it - Add specific error codes for Validate class - Add support for ORDER clauses on UPDATEs (to resolve the duplicate key problem) - Update description.schema.xml - Document how to use the API - Create unit test for comparedefinitions() - Create unit test for initializetable() - Create unit test to compare the expected array definition with what is parsed - HTML entities aren't being parsed correctly - Add optional support for scale in decimal fields - Improve validateDataFieldValue() to validate <column> - Provide more info on MDB2_Schema_Validate errors (output parsed value and expected value) - Views support - Foreign keys support - Fulltext index support 0.7.0 0.7.0 beta beta 2006-11-07 BSD License - Improved INSERT support, added UPDATE and DELETE statements - XML syntax redesigned to cover DML addictions - Creation of an explicit NULL (<null></null>) - various fixes to the DTD, including DML addictions - XSD schema definition created - Tests also output php version - New example parse.php lets you check how a XML schema is stored - Updated schema.xml to demo the DML support - Documentation reformulated, also covering new XML syntax - Improved demo script example.php, which now includes more actions and options - Writer is returning an error when fopen() fails - Writer has now its own error code - Variable "seq" became "sequence" and "seq_name" became "sequence_name" in the Parser - Moved validation code out of the Parser into a new separate class called Validation - Fixed index handling in the Parser - Refactored error handling in the Parser - Removed variable "init_field", that wasn't being used, from the Parser - Parser simulates only one level of recurssion, which means no more than function-expression or vice-versa - Fixed warning due to not checking with isset() in the Parser - Fixed warning due to not checking with isset() in the Schema - Typo fix (related to Bug #9024) - Fixed createDatabase() that was trying to use a non-existant database that was about to be created - Simplified API for compareTableFieldsDefinitions() and compareTableIndexesDefinitions() - Rewritten some docblocks - Added fold markers where missing - Removed @static from non static methods - Fixed several PEAR CS issues - Added code for field/identifier quoting - Ensure all identifiers are passed to quoteIdentifier() (Bug #8429) open todo items: - Make MDB2_Schema loadable via MDB2_Driver_Common::loadModule() (Bug #8270) - Add ability to define variables inside the schema (like a version number) - Allow simple if statements that mean that anything enclosed is only executed if it meets certain criterias based on that version number (or some other variable). This would enable people to add DML statements that are only executed when updating from a specific version. - Add support for recursive tag parsing. Currently only expression<->function is supported but not expression-expression or function-function, although recursion is already supported by the initializeTable() method - Parser should be replaced for XML serializer ? - Modularize Writer code or remake it - Add specific error codes for Validate class - Add support for ORDER clauses on UPDATEs (to resolve the duplicate key problem) - Update description.schema.xml - Document how to use the API - Create unit test for comparedefinitions() - Create unit test for initializetable() - Create unit test to compare the expected array definition with what is parsed - HTML entities aren't being parsed correctly - Add optional support for scale in decimal fields - Implement "WHERE column IS NULL" - Add ability to parse a "contents-only" XML dump - Improve validateDataFieldValue() to validate <column> - Provide more info on MDB2_Schema_Validate errors (output parsed value and expected value) 0.6.0 0.6.0 beta beta 2006-07-23 BSD License - added new XSL and CSS for xml schema file rendering (thx Bertrand) - automatically generate <on> tags in <sequence> tags if there is a table with the same name and a single column primary key - do not dump default for LOB fields (Bug #7596) - added support for "fixed" (needs more testing) - phpdoc tweaks (thx Stoyan) - fixed primary key emulation and some other minor issues in createTableIndexes() (Bug #7758) - implemented skip_unreadable parameter in parseDatabaseDefinition() (Bug #7756) - switched most array_key_exists() calls to !empty() to improve readability and performance - fixed a few edge cases and potential warnings - add method name as scope for call debug() calls - use getValidTypes() from MDB2 - hint if dropping a primary constraint - minor code tweak in how initialization data is set in the prepared statement - force ISO-8859-1 when parsing XML due to different defaults for PHP4 and PHP5 - fixed handling for changes in indexes/constaints (Bug #7901) - made forcing of defaults optional via the 'force_defaults' option (Request #8074) - fixed several issues in the DTD (Bug #7890) - set length and fixed for user_password in the test suite - use nested transactions instead of normal transactions 0.5.0 0.5.0 beta beta 2006-04-16 BSD License - expanded reserved word handling - fix LOB data dumping - added overwrite support to writer class - added comment for idxname_format setting to example - added autoincrement and primary to the documentation and .xsl/.dtd - if we cannot create the database, then assume it was created manually in the test suite - added option valid_types - added option to set parser and writer class - automatically let the installer set the API Version - make sure that the Datatype module is loaded - added valid_types property to determine if a given type is valid schema and to set missing default values - allow CURRENT_* as default in temporal types (bug #6416) - improve test suite documentation - added parseDatabaseDefinition() that can work with a file or array definition - removed database_definition property and as a result reworked the API of most methods *BC BREAK* - added _dumpBoolean() in writer to better support variables in boolean fields - allow method callbacks in MDB2_Schema_Writer::dumpDatabase (bug #7363) - set error code in all raiseError() calls - minor updates to the xml schema xsl and documentation (thx Bertrand) 0.4.3 0.4.3 beta beta 2006-02-05 BSD License - renamed "manager" property to "schema" for clarity in the testsuite - fixed logic related to using a non existant previous schema name in updateDatabase() open todo items: - better handling for NULL values in the xml schema format 0.4.2 0.4.2 beta beta 2006-01-14 BSD License - added ability to dump sql instead of commiting it to the database in the example - fix for bug in handling of boolean default values (bug #6397) - default to notnull = false in the schema parser - several fixes for database alterations (thx Matthias) - default for autoincrement can be '0' or 0 in the parser - set default 0 for autoincrement columns when reverse engineering a schema - expect MDB2_ERROR_ALREADY_EXISTS when creating a database (bug #6481) open todo items: - better handling for NULL values in the xml schema format 0.4.1 0.4.1 beta beta 2005-12-30 BSD License - fixed bug in updateDatabase() when using a file as the previous schema (bug was introduced in last release) - fixed install roles for test files 0.4.0 0.4.0 beta beta 2005-12-21 BSD License - Silence a "error" when there is auto increment and a primary key index defined on the same field, since auto increment implies a primary key - support column length in create index (mysql only feature, but a nice touch, emulating it with substring is not feasible though) - use exec() for INSERT statement - add extra debug info better use of the var_dump package if present in example - fixed bug in verifyAlterDatabase() when checking table alterations (bug #5977) - fixed typo in getTableConstraintDefinition() method name (removed additional "s") (bug #6054) - expect and ignore MDB2_ERROR_NOT_FOUND when calling getTableConstraintDefinition() and getTableIndexDefinition() (bug #6055) - fixed typo in verifyAlterDatabase() (bug #6053) - fixed typo in alterDatabaseSequences() (bug #6053) - added test suite - fixed issue in createDatabase() with portability fix case turned - ensure that all primary/unique/foreign key handling is only in the contraint methods - optionally allow schemas to be passed as an array to updateDatabase() (thx Matthias) 0.3.0 0.3.0 beta beta 2005-10-10 BSD License Warning: this is an intermediary release to address php 4.4/5.0.5. Some of the new features still need a bit more tweaking. - use MDB2::factory() by default instead of MDB2::connect() - added support for auto increment and primary key in schema. - alterTable now needs the full definition to work (use getTableFieldDefinition from Reverse module if you do not have a definition at hand) this eliminates the need of the declaration part in the alterTable array. - typo fix (bug #4620) - php 4.4.x/5.0.5 fixes - updated getTableFieldDefinition() call to accomodate API changes in MDB2 - MDB2_Schema has its own error class and error codes - made it easier to add new database backend to the example - better handle removing of indexes on renamed columns in alterDatabaseTables() - use array_key_exists() instead of isset() where possible - restructured changes array to fix bugs due to inconsistency in the handling of array keys - added ability to disable query for the alterDatabase()/createDatabase() call in updateDatabase(). this is useful to generate an RDBMS specific SQL file using a custom debug callback - prefer "true" and "false" over "1" and "0" - an emty default tag now implies NULL for nullable columns and an empty string for NOT NULL columns 0.2.0 0.2.0 beta beta 2005-04-29 BSD License - fixed error handling in updateDatabase() - use MDB2::raiseError - always copy schema file in updateDatabase() - cosmetic fixes and tweaks - improved overwrite to check via list*() before creating (bug #3857, #4101) - updated MDB2 dependency - fixed sequence dumping - moved schema documentation, xml_reverse_engineering.php, MDB.dtd and MDB.xls from MDB package - added optional support for PEAR::XML_DTD based validation of schema files - index can be defined on fields that dont explicity prohibit null values - dont disable sequence dumping when implicit sequences have been found - added code to support dumping of lobs (MDB2 really should move to streams) - added writeInitialization() method (untested) - is_boolean() => isBoolean() in parser (CS fix) - added MDB2_Schema::factory() - Parser: if set grab definition of a table from the strucure property if set 0.1.0 0.1.0 beta beta 2005-04-07 BSD License This is the first unbundled release of the old MDB2_Tools_Manager class that was previously part of MDB2 until 2.0.0beta4. Due to the name change the package does not collide with previous versions of MDB2. Also the following changes were made in the process: - fixed index alteration in the Manager (bug #3710) - fixed bug in the Manager when upgrading a database that doesnt exist - moved logic to compareDefinitions from the Manager into the Datatype module - removed default_values property from the Manager (the user will now need to set the proper defaults himself) - do not require that not null fields have a default set in the Manager (bug #3997) - use MDB2::raiseError() instead of MDB2_Driver_Common::raiseError() - cleanedup connect() method to ensure that only MDB2 connections can be assigned to the db property - fixed bug in connect() method that prevented overwriting of options - several cleanups and fixes to the example.php (used to be called reverse_engineer_xml_schema.php) - added apiVersion() - use PEAR::raiseError() MDB2_Schema-0.8.5/docs/examples/parse.php100644 765 765 7735 11150346546 13276 | // +----------------------------------------------------------------------+ // // $Id: parse.php,v 1.4 2006/08/17 10:57:37 lsmith Exp $ // #ini_set('include_path', '../../'.PATH_SEPARATOR.ini_get('include_path')); #ini_set('include_path', '../../../MDB2'.PATH_SEPARATOR.ini_get('include_path')); require_once 'MDB2.php'; $dsn = array( 'phptype' => 'mysql', 'username' => 'root', 'password' => '', 'hostspec' => 'localhost', ); $options = array(); MDB2::loadFile('Schema'); $manager =& MDB2_Schema::factory($dsn, $options); if (MDB2::isError($manager)) { die($manager->getUserinfo()); } $database_definition = $manager->parseDatabaseDefinitionFile('./schema.xml'); $manager->db->setOption('disable_query', true); $manager->db->setOption('debug', true); $manager->writeInitialization($database_definition); ?>
db->getDebugOutput());

?>
MDB2_Schema-0.8.5/docs/examples/schema.xml100644 765 765 14241 11150346546 13443 MDB2Example true true People id integer true true 0 1 name text 128 true unknown age integer true false birthdate date false occupation text 128 false updated timestamp false aux float true false PRIMARY true id ascending name Igor birthdate 1984-05-23 occupation engineer updated now name Heloisa birthdate 1984-04-07 occupation lawyer updated now name Anne Sophie birthdate 2004-01-16 occupation engineer updated now name John birthdate 2005-01-16 occupation philosopher updated now aux DATEDIFF updated birthdate DIVIDED 365 age floor aux aux
Packages id integer true 4 true 0 1 name text 128 true unknown summary clob true creation date false PRIMARY true id ascending id 11 name PEAR summary PEAR Base System creation 2006-08-16 id 12 name MDB2 summary Database Abstraction Layer creation 2006-09-03 id 13 name MDB2_Schema summary XML Based Database Schema Manager creation now id 14 name XML_Parser summary XML parsing class based on PHP's bundled expat creation 2005-09-24 id 77 name I am supposed to be deleted id id MINUS 10 id EQUAL 67
MDB2_Schema-0.8.5/docs/description.schema.xml100644 765 765 24325 11150346546 14153 MDB2_Schema MDB2_Schema self description This is non authoritative but self described 1 0 databaseGeneral database/schema configurationIt is the root element of a MDB2 Schema, must contain at least 1 <table> and eventually some <sequence> name text Database name 1 create boolean Create new 0=Use a previously installed database , 1=Create the specified database 0 overwrite boolean Overwrite previous Overwrite previously created structures ? 0 description text Database description Ignored by the parser comments text Free comments Ignored by the parser
tableDescribes each table of the databaseA child of <database>, must contain a <declaration> with at least 1 <field> and eventually some <index>.
<table> may also have a <initialization> with some <insert>
name text 1 Table name Should be better taken as some NMTOKEN , use ASCII no space better. was text Table previous name description text Table description Ignored by the parser comments text Free comments Ignored by the parser name_index 1 name Indicates that 2 tables should not have the same name within a database
fieldDescribes each field in a table <field> as a child of <declaration> so grand-child of <table> name text 1 Field name was text Field previous name type text 1 Field type Valid types: integer, text, boolean, date, timestamp, time, float, decimal, clob and blob. default text Optional default value notnull boolean Field required Must be set for fields belonging to an index (sql NOT NULL) 0 autoincrement boolean Field auto increments It's a not null integer field with a primary key. Not supported by all DBMS but may be emulated 0 unsigned boolean Unsigned Only for integer. Not supported by all DBMS 0 length integer Length Some types as "text" optionally offer it. description text Field description Ignored by the parser comments text Free comments Ignored by the parser name_index 1 name Indicates that 2 fields should not have the same name within a table
indexDescribes each index in a tablechild of <declaration> so grand-child of <table> name text 1 Index name was text Index previous name unique boolean Index is unique The combined value of the contained fields is unique 0 primary boolean Table primary index 0 description text Index description Ignored by the parser, and not in 0.5.0 dtd comments text Free comments Ignored by the parser, and not in 0.5.0 dtd name_index 1 name Indicates that 2 indexes should not have the same name within a table
index_fieldDescribes what fields make an index in a table<field> as a child of <index> name text 1 Referenced field name This should reference the name of some uncle <field> sorting text Field's order in the sort Valid: ascending or descending description text index field description Ignored by the parser comments text Free comments Ignored by the parser
insert_fieldDescribes each field in an insert for table initializationchild of <insert> from <initialization> so great-grand-child of <table> name text 1 field name This should reference the name of some grand-uncle <field> value text field value description text insert field description Ignored by the parser comments text Free comments Ignored by the parser
sequenceDescribes each sequence of the databaseA child of <database> , may contain one <on> name text 1 Sequence name was text Sequence previous name start integer Sequence start value description text Sequence description Ignored by the parser comments text Free comments Ignored by the parser name_index 1 name Indicates that 2 sequences should not have the same name within a database
MDB2_Schema-0.8.5/docs/MDB.dtd100644 765 765 4327 11150346546 10726 MDB2_Schema-0.8.5/docs/MDB.xsd100644 765 765 15542 11150346546 10772 Schema for PEAR MDB2 XML database schemas. MDB2_Schema-0.8.5/docs/MDB.xsl100644 765 765 7715 11150346546 10765 Metabase DB Documentation
database

table field type comments attributes
index unique primary
() default= autoincrement= unsigned= notnull=
MDB2_Schema-0.8.5/docs/README100644 765 765 171 11150346546 10460 The contents of this directory are outdated, except for: o examples/ o MDB.dtd o MDB.xsd o xml_schema_documentation.htmlMDB2_Schema-0.8.5/docs/schema2html.css100644 765 765 3470 11150346546 12546 /** * MDB2_Schema : Presentation style sheet for the schema2html.xsl doc utility * * CSS2 StyleSheet * * @category DB * @package MDB2_Schema * @author Bertrand Gugger * @copyright 2006 bertrand Gugger * @license http://www.opensource.org/licenses/bsd-license.php BSD license * @version CVS: $Id: schema2html.css,v 1.4 2006/04/22 12:40:15 toggg Exp $ * @link http://pear.php.net/package/MDB2_Schema */ .foo { } body { font-family: Arial, Helvetica, sans-serif; background: #FFDACF; } span { margin: 0 2px; } .database { background: #eee; margin: 2px; border: solid 1px black; } .database .comments { font-size: x-small; } .menu { word-spacing: 5px; } .name { font-size: large; font-weight: bold; } .description { font-size: normal; font-weight: normal; } .label { font-size: x-small; font-weight: lighter; color: #888; } .comments { font-size: x-small; font-weight: lighter; color: #888; } td.comments { border-left: solid 2px #eee; border-right: solid 2px #eee; } .tablemain table { margin: 0 auto; } .tableheader { padding: 3px; border: solid 0px; margin: 0px; background-color: #eee; //rgb(235, 235, 235); color: #888; //rgb(133, 133, 133); text-decoration: none; } .tableheader td { padding: 0 3px; } .tablebody td { padding: 3px; border: solid 1px #eee; // border-left: solid 1px; border-bottom: solid 1px; border-right: solid 1px; // border-color: rgb(210, 210, 210); margin: solid 0px; font-size: 11px; color: rgb(133, 133, 133); text-decoration: none; } .tablebody .name { font-size: small; } .indexfield { font-weight: bold; } .indexes { font-weight: bold; font-family: monospace; } .attributes { font-weight: bold; } MDB2_Schema-0.8.5/docs/schema2html.xsl100644 765 765 14565 11150346546 12613 MDB2 Schema Documentation
database
table fieldtypeindexes N A + descriptiondefaultcomments indexes ^ ^ ^ U P Involved fields comments No index, it's single (parameters) or flat (list) - +     N A + ()        U P -+ 
MDB2_Schema-0.8.5/docs/xml_schema_documentation.html100644 765 765 113505 11150346546 15625 MDB2 XML Schema documentation

MDB2 XML Schema documentation

Manuel Lemos (mlemos@acm.org)

Igor Feghali (ifeghali@php.net)

Version control: @(#) $Id: xml_schema_documentation.html,v 1.17 2008/01/30 01:13:38 ifeghali Exp $

Contents

Introduction to XML

The schema description format is based on XML (eXtensible Markup Language). For those that are not familiar with it, XML is standard that specifies rules to define abstract data formats based on tagged text.

Like HTML (HyperText Markup Language), XML is also based on SGML (Standard Generalized Markup Language). SGML defines rules to structure data using special text tags.

SGML tags may be used to delimit data sections. Section begin tags are of the form <name attributes... > and end tags are of the form </name>. name is the name of the tag and attributes is a set of zero or more pairs of attribute names and the values associated with the respective tag.

XML is a little stricter in the way tags may be used. While with many SGML formats some end tags are optional, in XML end tags are always required. Also, when tag attributes are used, attribute values must be specified always between quotes. These XML requirements are usually known as well-formedness.

Another important detail about XML strictness is that tag names and attributes are case sensitive. This means that tags in upper case are distinct from tags in lower case.

Schema description format and XML

Unlike a common (but mistaken) belief, XML is not meant just for describing data in documents that are meant to be displayed or printed. XML is a standard that defines rules for describing abstract data may be used to for any purpose.

Even though it may be used to schemas that may be displayed or printed, Metabase schema description format is meant to provide a way for developers to design their database schemas using a DBMS independent file format. Using this format, developers may describe relations and properties of tables, field, indexes, sequences, etc..

This format uses just a subset of the XML known as SML (Simplified Markup Language). SML formats complies with the same rules as any XML format but it does not use all its possibilities to make it simpler for users to write and understand the data. For instance, files written on SML do not use any tag attributes.

Metabase schema description format is also simpler to edit by hand because tags and constant data values should always be in lower case to save the user from holding frequently the keyboard shift key.

Schema description data structure

The Metabase schema description format lets the developers describe a set of database schema objects following the database objects hierarchy. This means that a database may contain tables and sequence objects, tables may contain fields and index objects and all these objects have their own attributes.

The definition of each database schema object contained within the begin and end tags of the respective container object. Therefore, the definition of each table and sequence has to be specified between the main database begin and end tags. Likewise, the definition of fields and indexes has to be specified between the respective table begin and end tags.

The properties of each schema object are also defined between the respective begin and end tags. The values of each property are also defined between the respective property being and end tags.

The values of the properties are subject of validation according to the type of each property and the context within which they are being defined.

Some properties define names of database schema objects. There are names that are accepted as valid for some DBMS that are not accepted by other DBMS. Metabase schema parser may optionally fail if such names are used to reduce the potential problems when using the same Metabase based application with different DBMS.

The schema object description tags are defined as follows:

database

The database tag should be always at the top of the schema object hierarchy. Currently it may contain the definition of two types of objects: table and sequence.

The database schema object may have the following properties:

table

The table is one of the main database schema objects. It may be used in a schema description multiple times, once per each table that is contained the database being described.

The table object definition may contain the declaration and initialization sections besides the properties. The table schema object may have the following properties:

Example

declaration

declaration is one of the sections that is part of the table definition. This section is required because it must contain the definition of the table field and index objects.

field

field is one of the types of table definition object. It should be specified within the table declaration section for each field that the table should contain.

The field schema object may have the following properties:

Example

index

index is another type of table definition object. It should also be specified within the table declaration section for each field that the table should contain.

The index schema object may have the following properties:

index field

field is a section that is part of the table index declaration. It should be used once per each field on which the index should be created.

The index field declaration may have the following properties:

Example

foreign

foreign was added in Schema version 0.7.3. [description here]

The foreign schema object may have the following properties:

foreign field

foreign field should be used once per each field on which the foreign key should be created. Allow a string value indicating a field name.

foreign references

references is a section that is part of the table foreign key declaration.

This section is optional. If it is absent, it is assumed that the referenced key is the primary key of referenced table.

The foreign references declaration may have the following properties:

Example

initialization

initialization is another section that is part of the table definition. This section is optional and may contain the definition of actions that should be executed when installing the database for the first time. update and delete was added in Schema version 0.7.0.

The available actions, in the execution order, are:

insert

insert is a table initialization command that specifies the values of the fields of rows that should be inserted in the respective table after the database is created for the first time.

The insert initialization object do not have any property.

insert field

field is a section that is part of the table insert initialization. It should be used once per each field which should be filled with data.

It may have only the property name.

One, and only one, of the following objects should be used to specify the initial data:

When doing an insert missing fields are implicitly initialized by the DBMS with the respective default values.

Example
insert select

select was added in Schema version 0.7.3 to acomplish the INSERT...SELECT syntax. It is optional and, when used, should be the only child of insert.

It may have only the property table that designates the table name in the select statement.

insert select field

The insert select field object is defined exactly the same way as insert field. Here name goes to the fields portion of the insert statement and the next property goes to the fields portion of the select statement

insert select where

The insert select where object, that is not required, must contain only one expression object.

In that case the expression object usually links operants by logical operators like AND, OR and others.

update

update is a table initialization command that replaces the values of the fields of rows, matched by a condition, in the respective table after the database is created for the first time.

The update initialization object do not have any property.

update field

The update field object is defined exactly the same way as insert field

update where

The update where object, that is not required, must contain only one expression object.

In that case the expression object usually links operants by logical operators like AND, OR and others.

Example

delete

delete is a table initialization command that removes rows, matched by a condition, in the respective table after the database is created for the first time.

The delete command definition only contains one more where section used to select the rows to be deleted.

The delete initialization object do not have any property.

delete where

The delete where object must contain only one expression object.

In that case the expression object usually links operants by logical operators like AND, OR and others.

Example

Complex initialization objects

function

The function object will bind to a DBMS function, that can be called with any number of arguments.

It may have only the property name.

Any of the following objects should be used, how many times it is necessary, to provide the arguments:

expression

The expression object is a recursive structure used to relate pairs of value, column, function and expression objects.

The expression object do not have any property and has the exact form operant operator operant.

expression operant

The expression operant isn't a object itself but may be represented by one of the following objects:

expression operator

Operators aren't implemented in a portable way yet. Currently the following descriptive operators are always binded to the same operators:
OperatorBinding
PLUS+
MINUS-
TIMES*
DIVIDED/
EQUAL=
NOT EQUAL!=
LESS THAN<
GREATER THAN>
LESS THAN OR EQUAL<=
GREATER THAN OR EQUAL>=

Any other value given to operator will be parsed with no translation.

Future versions of Schema may provide a common set of descriptive operators that are translated to the respective operator for your DBMS

sequence

The sequence is another main database schema object. It may be used in a schema description multiple times, once per each sequence that is contained the database being described.

A sequence is an object that only contains an integer value. A sequence value is automatically incremented after every time it is fetch the next sequence value. The fetch and increment actions constitute an atomic operation. This means that if two concurrent accesses to the database fetch the next sequence value, they will always different values.

Sequences are useful to generate integer numbers that may be used to store in fields that must contain unique numbers.

The sequence object definition may contain one on section besides the properties. The sequence schema object may have the following properties:

sequence on

The sequence on table field section specifies a table field on which the sequence value should be synchronized.

This information is meant to be used only by the database manager class when it is added a sequence later after the database has been installed for the first time. If the sequence on is specified, the database manager class will override the sequence start value with a value that is higher than the highest value in the specified field table. Therefore, the specified field table type must be integer.

Example

variable

The variable tag is not meant to define any database schema object but rather a means to replace property values with variables defined at parsing time.

For instance, if you have several tables that store user names in text fields with the same length limit, instead of hard coding the length value in all field definitions, you may use a variable reference. The parser will replace variable references found in property definitions by the text values of the respective values passed to the parser.

The parser will issue an error if it find a reference for a variable that is not defined.

Schema overview data structure

Main structure

Common Elements

Legend

MDB2_Schema-0.8.5/MDB2/Schema/Reserved/ibase.php100644 765 765 21656 11150346546 14162 | // +----------------------------------------------------------------------+ // // }}} // {{{ $GLOBALS['_MDB2_Schema_Reserved']['ibase'] /** * Has a list of reserved words of Interbase/Firebird * * @package MDB2_Schema * @category Database * @access protected * @author Lorenzo Alberton */ $GLOBALS['_MDB2_Schema_Reserved']['ibase'] = array( 'ABS', 'ABSOLUTE', 'ACTION', 'ACTIVE', 'ADD', 'ADMIN', 'AFTER', 'ALL', 'ALLOCATE', 'ALTER', 'AND', 'ANY', 'ARE', 'AS', 'ASC', 'ASCENDING', 'ASSERTION', 'AT', 'AUTHORIZATION', 'AUTO', 'AUTODDL', 'AVG', 'BACKUP', 'BASE_NAME', 'BASED', 'BASENAME', 'BEFORE', 'BEGIN', 'BETWEEN', 'BIGINT', 'BIT', 'BIT_LENGTH', 'BLOB', 'BLOCK', 'BLOBEDIT', 'BOOLEAN', 'BOTH', 'BOTH', 'BREAK', 'BUFFER', 'BY', 'CACHE', 'CASCADE', 'CASCADED', 'CASE', 'CASE', 'CAST', 'CATALOG', 'CHAR', 'CHAR_LENGTH', 'CHARACTER', 'CHARACTER_LENGTH', 'CHECK', 'CHECK_POINT_LEN', 'CHECK_POINT_LENGTH', 'CLOSE', 'COALESCE', 'COLLATE', 'COLLATION', 'COLUMN', 'COMMENT', 'COMMIT', 'COMMITTED', 'COMPILETIME', 'COMPUTED', 'CONDITIONAL', 'CONNECT', 'CONNECTION', 'CONSTRAINT', 'CONSTRAINTS', 'CONTAINING', 'CONTINUE', 'CONVERT', 'CORRESPONDING', 'COUNT', 'CREATE', 'CROSS', 'CSTRING', 'CURRENT', 'CURRENT_CONNECTION', 'CURRENT_DATE', 'CURRENT_ROLE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'CURRENT_TRANSACTION', 'CURRENT_USER', 'DATABASE', 'DATE', 'DAY', 'DB_KEY', 'DEALLOCATE', 'DEBUG', 'DEC', 'DECIMAL', 'DECLARE', 'DEFAULT', 'DEFERRABLE', 'DEFERRED', 'DELETE', 'DELETING', 'DESC', 'DESCENDING', 'DESCRIBE', 'DESCRIPTOR', 'DIAGNOSTICS', 'DIFFERENCE', 'DISCONNECT', 'DISPLAY', 'DISTINCT', 'DO', 'DOMAIN', 'DOUBLE', 'DROP', 'ECHO', 'EDIT', 'ELSE', 'END', 'END-EXEC', 'ENTRY_POINT', 'ESCAPE', 'EVENT', 'EXCEPT', 'EXCEPTION', 'EXEC', 'EXECUTE', 'EXISTS', 'EXIT', 'EXTERN', 'EXTERNAL', 'EXTRACT', 'FALSE', 'FETCH', 'FILE', 'FILTER', 'FIRST', 'FLOAT', 'FOR', 'FOREIGN', 'FOUND', 'FREE_IT', 'FROM', 'FULL', 'FUNCTION', 'GDSCODE', 'GEN_ID', 'GENERATOR', 'GET', 'GLOBAL', 'GO', 'GOTO', 'GRANT', 'GROUP', 'GROUP_COMMIT_WAIT', 'GROUP_COMMIT_WAIT_TIME', 'HAVING', 'HELP', 'HOUR', 'IDENTITY', 'IF', 'IIF', 'IMMEDIATE', 'IN', 'INACTIVE', 'INDEX', 'INDICATOR', 'INIT', 'INITIALLY', 'INNER', 'INPUT', 'INPUT_TYPE', 'INSENSITIVE', 'INSERT', 'INSERTING', 'INT', 'INTEGER', 'INTERSECT', 'INTERVAL', 'INTO', 'IS', 'ISOLATION', 'ISQL', 'JOIN', 'KEY', 'LANGUAGE', 'LAST', 'LC_MESSAGES', 'LC_TYPE', 'LEADING', 'LEADING', 'LEADING', 'LEAVE', 'LEFT', 'LENGTH', 'LEV', 'LEVEL', 'LIKE', 'LOCAL', 'LOCK', 'LOG_BUF_SIZE', 'LOG_BUFFER_SIZE', 'LOGFILE', 'LONG', 'LOWER', 'MANUAL', 'MATCH', 'MAX', 'MAX_SEGMENT', 'MAXIMUM', 'MAXIMUM_SEGMENT', 'MERGE', 'MESSAGE', 'MIN', 'MINIMUM', 'MINUTE', 'MODULE', 'MODULE_NAME', 'MONTH', 'NAMES', 'NATIONAL', 'NATURAL', 'NCHAR', 'NEXT', 'NO', 'NOAUTO', 'NOT', 'NULL', 'NULLIF', 'NULLS', 'NUM_LOG_BUFFERS', 'NUM_LOG_BUFS', 'NUMERIC', 'OCTET_LENGTH', 'OF', 'ON', 'ONLY', 'OPEN', 'OPTION', 'OR', 'ORDER', 'OUTER', 'OUTPUT', 'OUTPUT_TYPE', 'OVERFLOW', 'OVERLAPS', 'PAD', 'PAGE', 'PAGE_SIZE', 'PAGELENGTH', 'PAGES', 'PARAMETER', 'PARTIAL', 'PASSWORD', 'PERCENT', 'PLAN', 'POSITION', 'POST_EVENT', 'PRECISION', 'PREPARE', 'PRESERVE', 'PRIMARY', 'PRIOR', 'PRIVILEGES', 'PROCEDURE', 'PUBLIC', 'QUIT', 'RAW_PARTITIONS', 'RDB$DB_KEY', 'READ', 'REAL', 'RECORD_VERSION', 'RECREATE', 'RECREATE ROW_COUNT', 'REFERENCES', 'RELATIVE', 'RELEASE', 'RESERV', 'RESERVING', 'RESTART', 'RESTRICT', 'RETAIN', 'RETURN', 'RETURNING', 'RETURNING_VALUES', 'RETURNS', 'REVOKE', 'RIGHT', 'ROLE', 'ROLLBACK', 'ROW_COUNT', 'ROWS', 'RUNTIME', 'SAVEPOINT', 'SCALAR_ARRAY', 'SCHEMA', 'SCROLL', 'SECOND', 'SECTION', 'SELECT', 'SEQUENCE', 'SESSION', 'SESSION_USER', 'SET', 'SHADOW', 'SHARED', 'SHELL', 'SHOW', 'SINGULAR', 'SIZE', 'SKIP', 'SMALLINT', 'SNAPSHOT', 'SOME', 'SORT', 'SPACE', 'SQL', 'SQLCODE', 'SQLERROR', 'SQLSTATE', 'SQLWARNING', 'STABILITY', 'STARTING', 'STARTS', 'STATEMENT', 'STATIC', 'STATISTICS', 'SUB_TYPE', 'SUBSTRING', 'SUM', 'SUSPEND', 'SYSTEM_USER', 'TABLE', 'TEMPORARY', 'TERMINATOR', 'THEN', 'TIES', 'TIME', 'TIMESTAMP', 'TIMEZONE_HOUR', 'TIMEZONE_MINUTE', 'TO', 'TRAILING', 'TRANSACTION', 'TRANSLATE', 'TRANSLATION', 'TRIGGER', 'TRIM', 'TRUE', 'TYPE', 'UNCOMMITTED', 'UNION', 'UNIQUE', 'UNKNOWN', 'UPDATE', 'UPDATING', 'UPPER', 'USAGE', 'USER', 'USING', 'VALUE', 'VALUES', 'VARCHAR', 'VARIABLE', 'VARYING', 'VERSION', 'VIEW', 'WAIT', 'WEEKDAY', 'WHEN', 'WHENEVER', 'WHERE', 'WHILE', 'WITH', 'WORK', 'WRITE', 'YEAR', 'YEARDAY', 'ZONE', ); // }}} ?>MDB2_Schema-0.8.5/MDB2/Schema/Reserved/mssql.php100644 765 765 14371 11150346546 14232 | // +----------------------------------------------------------------------+ // }}} // {{{ $GLOBALS['_MDB2_Schema_Reserved']['mssql'] /** * Has a list of all the reserved words for mssql. * * @package MDB2_Schema * @category Database * @access protected * @author David Coallier */ $GLOBALS['_MDB2_Schema_Reserved']['mssql'] = array( 'ADD', 'CURRENT_TIMESTAMP', 'GROUP', 'OPENQUERY', 'SERIALIZABLE', 'ALL', 'CURRENT_USER', 'HAVING', 'OPENROWSET', 'SESSION_USER', 'ALTER', 'CURSOR', 'HOLDLOCK', 'OPTION', 'SET', 'AND', 'DATABASE', 'IDENTITY', 'OR', 'SETUSER', 'ANY', 'DBCC', 'IDENTITYCOL', 'ORDER', 'SHUTDOWN', 'AS', 'DEALLOCATE', 'IDENTITY_INSERT', 'OUTER', 'SOME', 'ASC', 'DECLARE', 'IF', 'OVER', 'STATISTICS', 'AUTHORIZATION', 'DEFAULT', 'IN', 'PERCENT', 'SUM', 'AVG', 'DELETE', 'INDEX', 'PERM', 'SYSTEM_USER', 'BACKUP', 'DENY', 'INNER', 'PERMANENT', 'TABLE', 'BEGIN', 'DESC', 'INSERT', 'PIPE', 'TAPE', 'BETWEEN', 'DISK', 'INTERSECT', 'PLAN', 'TEMP', 'BREAK', 'DISTINCT', 'INTO', 'PRECISION', 'TEMPORARY', 'BROWSE', 'DISTRIBUTED', 'IS', 'PREPARE', 'TEXTSIZE', 'BULK', 'DOUBLE', 'ISOLATION', 'PRIMARY', 'THEN', 'BY', 'DROP', 'JOIN', 'PRINT', 'TO', 'CASCADE', 'DUMMY', 'KEY', 'PRIVILEGES', 'TOP', 'CASE', 'DUMP', 'KILL', 'PROC', 'TRAN', 'CHECK', 'ELSE', 'LEFT', 'PROCEDURE', 'TRANSACTION', 'CHECKPOINT', 'END', 'LEVEL', 'PROCESSEXIT', 'TRIGGER', 'CLOSE', 'ERRLVL', 'LIKE', 'PUBLIC', 'TRUNCATE', 'CLUSTERED', 'ERROREXIT', 'LINENO', 'RAISERROR', 'TSEQUAL', 'COALESCE', 'ESCAPE', 'LOAD', 'READ', 'UNCOMMITTED', 'COLUMN', 'EXCEPT', 'MAX', 'READTEXT', 'UNION', 'COMMIT', 'EXEC', 'MIN', 'RECONFIGURE', 'UNIQUE', 'COMMITTED', 'EXECUTE', 'MIRROREXIT', 'REFERENCES', 'UPDATE', 'COMPUTE', 'EXISTS', 'NATIONAL', 'REPEATABLE', 'UPDATETEXT', 'CONFIRM', 'EXIT', 'NOCHECK', 'REPLICATION', 'USE', 'CONSTRAINT', 'FETCH', 'NONCLUSTERED', 'RESTORE', 'USER', 'CONTAINS', 'FILE', 'NOT', 'RESTRICT', 'VALUES', 'CONTAINSTABLE', 'FILLFACTOR', 'NULL', 'RETURN', 'VARYING', 'CONTINUE', 'FLOPPY', 'NULLIF', 'REVOKE', 'VIEW', 'CONTROLROW', 'FOR', 'OF', 'RIGHT', 'WAITFOR', 'CONVERT', 'FOREIGN', 'OFF', 'ROLLBACK', 'WHEN', 'COUNT', 'FREETEXT', 'OFFSETS', 'ROWCOUNT', 'WHERE', 'CREATE', 'FREETEXTTABLE', 'ON', 'ROWGUIDCOL', 'WHILE', 'CROSS', 'FROM', 'ONCE', 'RULE', 'WITH', 'CURRENT', 'FULL', 'ONLY', 'SAVE', 'WORK', 'CURRENT_DATE', 'GOTO', 'OPEN', 'SCHEMA', 'WRITETEXT', 'CURRENT_TIME', 'GRANT', 'OPENDATASOURCE', 'SELECT', ); //}}} ?> MDB2_Schema-0.8.5/MDB2/Schema/Reserved/mysql.php100644 765 765 15347 11150346546 14244 | // +----------------------------------------------------------------------+ // // $Id: mysql.php,v 1.3 2006/03/01 12:16:40 lsmith Exp $ // }}} // {{{ $GLOBALS['_MDB2_Schema_Reserved']['mysql'] /** * Has a list of reserved words of mysql * * @package MDB2_Schema * @category Database * @access protected * @author David Coalier */ $GLOBALS['_MDB2_Schema_Reserved']['mysql'] = array( 'ADD', 'ALL', 'ALTER', 'ANALYZE', 'AND', 'AS', 'ASC', 'ASENSITIVE', 'BEFORE', 'BETWEEN', 'BIGINT', 'BINARY', 'BLOB', 'BOTH', 'BY', 'CALL', 'CASCADE', 'CASE', 'CHANGE', 'CHAR', 'CHARACTER', 'CHECK', 'COLLATE', 'COLUMN', 'CONDITION', 'CONNECTION', 'CONSTRAINT', 'CONTINUE', 'CONVERT', 'CREATE', 'CROSS', 'CURRENT_DATE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'CURRENT_USER', 'CURSOR', 'DATABASE', 'DATABASES', 'DAY_HOUR', 'DAY_MICROSECOND', 'DAY_MINUTE', 'DAY_SECOND', 'DEC', 'DECIMAL', 'DECLARE', 'DEFAULT', 'DELAYED', 'DELETE', 'DESC', 'DESCRIBE', 'DETERMINISTIC', 'DISTINCT', 'DISTINCTROW', 'DIV', 'DOUBLE', 'DROP', 'DUAL', 'EACH', 'ELSE', 'ELSEIF', 'ENCLOSED', 'ESCAPED', 'EXISTS', 'EXIT', 'EXPLAIN', 'FALSE', 'FETCH', 'FLOAT', 'FLOAT4', 'FLOAT8', 'FOR', 'FORCE', 'FOREIGN', 'FROM', 'FULLTEXT', 'GOTO', 'GRANT', 'GROUP', 'HAVING', 'HIGH_PRIORITY', 'HOUR_MICROSECOND', 'HOUR_MINUTE', 'HOUR_SECOND', 'IF', 'IGNORE', 'IN', 'INDEX', 'INFILE', 'INNER', 'INOUT', 'INSENSITIVE', 'INSERT', 'INT', 'INT1', 'INT2', 'INT3', 'INT4', 'INT8', 'INTEGER', 'INTERVAL', 'INTO', 'IS', 'ITERATE', 'JOIN', 'KEY', 'KEYS', 'KILL', 'LABEL', 'LEADING', 'LEAVE', 'LEFT', 'LIKE', 'LIMIT', 'LINES', 'LOAD', 'LOCALTIME', 'LOCALTIMESTAMP', 'LOCK', 'LONG', 'LONGBLOB', 'LONGTEXT', 'LOOP', 'LOW_PRIORITY', 'MATCH', 'MEDIUMBLOB', 'MEDIUMINT', 'MEDIUMTEXT', 'MIDDLEINT', 'MINUTE_MICROSECOND', 'MINUTE_SECOND', 'MOD', 'MODIFIES', 'NATURAL', 'NOT', 'NO_WRITE_TO_BINLOG', 'NULL', 'NUMERIC', 'ON', 'OPTIMIZE', 'OPTION', 'OPTIONALLY', 'OR', 'ORDER', 'OUT', 'OUTER', 'OUTFILE', 'PRECISION', 'PRIMARY', 'PROCEDURE', 'PURGE', 'RAID0', 'READ', 'READS', 'REAL', 'REFERENCES', 'REGEXP', 'RELEASE', 'RENAME', 'REPEAT', 'REPLACE', 'REQUIRE', 'RESTRICT', 'RETURN', 'REVOKE', 'RIGHT', 'RLIKE', 'SCHEMA', 'SCHEMAS', 'SECOND_MICROSECOND', 'SELECT', 'SENSITIVE', 'SEPARATOR', 'SET', 'SHOW', 'SMALLINT', 'SONAME', 'SPATIAL', 'SPECIFIC', 'SQL', 'SQLEXCEPTION', 'SQLSTATE', 'SQLWARNING', 'SQL_BIG_RESULT', 'SQL_CALC_FOUND_ROWS', 'SQL_SMALL_RESULT', 'SSL', 'STARTING', 'STRAIGHT_JOIN', 'TABLE', 'TERMINATED', 'THEN', 'TINYBLOB', 'TINYINT', 'TINYTEXT', 'TO', 'TRAILING', 'TRIGGER', 'TRUE', 'UNDO', 'UNION', 'UNIQUE', 'UNLOCK', 'UNSIGNED', 'UPDATE', 'USAGE', 'USE', 'USING', 'UTC_DATE', 'UTC_TIME', 'UTC_TIMESTAMP', 'VALUES', 'VARBINARY', 'VARCHAR', 'VARCHARACTER', 'VARYING', 'WHEN', 'WHERE', 'WHILE', 'WITH', 'WRITE', 'X509', 'XOR', 'YEAR_MONTH', 'ZEROFILL', ); // }}} ?> MDB2_Schema-0.8.5/MDB2/Schema/Reserved/oci8.php100644 765 765 11677 11150346546 13743 | // +----------------------------------------------------------------------+ // }}} // {{{ $GLOBALS['_MDB2_Schema_Reserved']['oci8'] /** * Has a list of all the reserved words for oracle. * * @package MDB2_Schema * @category Database * @access protected * @author David Coallier */ $GLOBALS['_MDB2_Schema_Reserved']['oci8'] = array( 'ACCESS', 'ELSE', 'MODIFY', 'START', 'ADD', 'EXCLUSIVE', 'NOAUDIT', 'SELECT', 'ALL', 'EXISTS', 'NOCOMPRESS', 'SESSION', 'ALTER', 'FILE', 'NOT', 'SET', 'AND', 'FLOAT', 'NOTFOUND ', 'SHARE', 'ANY', 'FOR', 'NOWAIT', 'SIZE', 'ARRAYLEN', 'FROM', 'NULL', 'SMALLINT', 'AS', 'GRANT', 'NUMBER', 'SQLBUF', 'ASC', 'GROUP', 'OF', 'SUCCESSFUL', 'AUDIT', 'HAVING', 'OFFLINE ', 'SYNONYM', 'BETWEEN', 'IDENTIFIED', 'ON', 'SYSDATE', 'BY', 'IMMEDIATE', 'ONLINE', 'TABLE', 'CHAR', 'IN', 'OPTION', 'THEN', 'CHECK', 'INCREMENT', 'OR', 'TO', 'CLUSTER', 'INDEX', 'ORDER', 'TRIGGER', 'COLUMN', 'INITIAL', 'PCTFREE', 'UID', 'COMMENT', 'INSERT', 'PRIOR', 'UNION', 'COMPRESS', 'INTEGER', 'PRIVILEGES', 'UNIQUE', 'CONNECT', 'INTERSECT', 'PUBLIC', 'UPDATE', 'CREATE', 'INTO', 'RAW', 'USER', 'CURRENT', 'IS', 'RENAME', 'VALIDATE', 'DATE', 'LEVEL', 'RESOURCE', 'VALUES', 'DECIMAL', 'LIKE', 'REVOKE', 'VARCHAR', 'DEFAULT', 'LOCK', 'ROW', 'VARCHAR2', 'DELETE', 'LONG', 'ROWID', 'VIEW', 'DESC', 'MAXEXTENTS', 'ROWLABEL', 'WHENEVER', 'DISTINCT', 'MINUS', 'ROWNUM', 'WHERE', 'DROP', 'MODE', 'ROWS', 'WITH', ); // }}} ?> MDB2_Schema-0.8.5/MDB2/Schema/Reserved/pgsql.php100644 765 765 11176 11150346546 14221 | // +----------------------------------------------------------------------+ // // }}} // {{{ $GLOBALS['_MDB2_Schema_Reserved']['pgsql'] /** * Has a list of reserved words of pgsql * * @package MDB2_Schema * @category Database * @access protected * @author Marcelo Santos Araujo */ $GLOBALS['_MDB2_Schema_Reserved']['pgsql'] = array( 'ALL', 'ANALYSE', 'ANALYZE', 'AND', 'ANY', 'AS', 'ASC', 'AUTHORIZATION', 'BETWEEN', 'BINARY', 'BOTH', 'CASE', 'CAST', 'CHECK', 'COLLATE', 'COLUMN', 'CONSTRAINT', 'CREATE', 'CURRENT_DATE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'CURRENT_USER', 'DEFAULT', 'DEFERRABLE', 'DESC', 'DISTINCT', 'DO', 'ELSE', 'END', 'EXCEPT', 'FALSE', 'FOR', 'FOREIGN', 'FREEZE', 'FROM', 'FULL', 'GRANT', 'GROUP', 'HAVING', 'ILIKE', 'IN', 'INITIALLY', 'INNER', 'INTERSECT', 'INTO', 'IS', 'ISNULL', 'JOIN', 'LEADING', 'LEFT', 'LIKE', 'LIMIT', 'LOCALTIME', 'LOCALTIMESTAMP', 'NATURAL', 'NEW', 'NOT', 'NOTNULL', 'NULL', 'OFF', 'OFFSET', 'OLD', 'ON', 'ONLY', 'OR', 'ORDER', 'OUTER', 'OVERLAPS', 'PLACING', 'PRIMARY', 'REFERENCES', 'SELECT', 'SESSION_USER', 'SIMILAR', 'SOME', 'TABLE', 'THEN', 'TO', 'TRAILING', 'TRUE', 'UNION', 'UNIQUE', 'USER', 'USING', 'VERBOSE', 'WHEN', 'WHERE' ); // }}} ?> MDB2_Schema-0.8.5/MDB2/Schema/Tool/ParameterException.php100644 765 765 111 11150346546 15753 MDB2_Schema-0.8.5/MDB2/Schema/Parser.php100644 765 765 104777 11150346546 12602 * Author: Igor Feghali * * $Id: Parser.php,v 1.68 2008/11/30 03:34:00 clockwerx Exp $ * * @category Database * @package MDB2_Schema * @author Christian Dickmann * @author Igor Feghali * @license BSD http://www.opensource.org/licenses/bsd-license.php * @version CVS: $Id: Parser.php,v 1.68 2008/11/30 03:34:00 clockwerx Exp $ * @link http://pear.php.net/packages/MDB2_Schema */ require_once 'XML/Parser.php'; require_once 'MDB2/Schema/Validate.php'; /** * Parses an XML schema file * * @category Database * @package MDB2_Schema * @author Christian Dickmann * @license BSD http://www.opensource.org/licenses/bsd-license.php * @link http://pear.php.net/packages/MDB2_Schema */ class MDB2_Schema_Parser extends XML_Parser { var $database_definition = array(); var $elements = array(); var $element = ''; var $count = 0; var $table = array(); var $table_name = ''; var $field = array(); var $field_name = ''; var $init = array(); var $init_function = array(); var $init_expression = array(); var $init_field = array(); var $index = array(); var $index_name = ''; var $constraint = array(); var $constraint_name = ''; var $var_mode = false; var $variables = array(); var $sequence = array(); var $sequence_name = ''; var $error; var $structure = false; var $val; function __construct($variables, $fail_on_invalid_names = true, $structure = false, $valid_types = array(), $force_defaults = true) { // force ISO-8859-1 due to different defaults for PHP4 and PHP5 // todo: this probably needs to be investigated some more andcleaned up parent::XML_Parser('ISO-8859-1'); $this->variables = $variables; $this->structure = $structure; $this->val =& new MDB2_Schema_Validate($fail_on_invalid_names, $valid_types, $force_defaults); } function MDB2_Schema_Parser($variables, $fail_on_invalid_names = true, $structure = false, $valid_types = array(), $force_defaults = true) { $this->__construct($variables, $fail_on_invalid_names, $structure, $valid_types, $force_defaults); } function startHandler($xp, $element, $attribs) { if (strtolower($element) == 'variable') { $this->var_mode = true; return; } $this->elements[$this->count++] = strtolower($element); $this->element = implode('-', $this->elements); switch ($this->element) { /* Initialization */ case 'database-table-initialization': $this->table['initialization'] = array(); break; /* Insert */ /* insert: field+ */ case 'database-table-initialization-insert': $this->init = array('type' => 'insert', 'data' => array('field' => array())); break; /* insert-select: field+, table, where? */ case 'database-table-initialization-insert-select': $this->init['data']['table'] = ''; break; /* Update */ /* update: field+, where? */ case 'database-table-initialization-update': $this->init = array('type' => 'update', 'data' => array('field' => array())); break; /* Delete */ /* delete: where */ case 'database-table-initialization-delete': $this->init = array('type' => 'delete', 'data' => array('where' => array())); break; /* Insert and Update */ case 'database-table-initialization-insert-field': case 'database-table-initialization-insert-select-field': case 'database-table-initialization-update-field': $this->init_field = array('name' => '', 'group' => array()); break; case 'database-table-initialization-insert-field-value': case 'database-table-initialization-insert-select-field-value': case 'database-table-initialization-update-field-value': /* if value tag is empty cdataHandler is not called so we must force value element creation here */ $this->init_field['group'] = array('type' => 'value', 'data' => ''); break; case 'database-table-initialization-insert-field-null': case 'database-table-initialization-insert-select-field-null': case 'database-table-initialization-update-field-null': $this->init_field['group'] = array('type' => 'null'); break; case 'database-table-initialization-insert-field-function': case 'database-table-initialization-insert-select-field-function': case 'database-table-initialization-update-field-function': $this->init_function = array('name' => ''); break; case 'database-table-initialization-insert-field-expression': case 'database-table-initialization-insert-select-field-expression': case 'database-table-initialization-update-field-expression': $this->init_expression = array(); break; /* All */ case 'database-table-initialization-insert-select-where': case 'database-table-initialization-update-where': case 'database-table-initialization-delete-where': $this->init['data']['where'] = array('type' => '', 'data' => array()); break; case 'database-table-initialization-insert-select-where-expression': case 'database-table-initialization-update-where-expression': case 'database-table-initialization-delete-where-expression': $this->init_expression = array(); break; /* One level simulation of expression-function recursion */ case 'database-table-initialization-insert-field-expression-function': case 'database-table-initialization-insert-select-field-expression-function': case 'database-table-initialization-insert-select-where-expression-function': case 'database-table-initialization-update-field-expression-function': case 'database-table-initialization-update-where-expression-function': case 'database-table-initialization-delete-where-expression-function': $this->init_function = array('name' => ''); break; /* One level simulation of function-expression recursion */ case 'database-table-initialization-insert-field-function-expression': case 'database-table-initialization-insert-select-field-function-expression': case 'database-table-initialization-insert-select-where-function-expression': case 'database-table-initialization-update-field-function-expression': case 'database-table-initialization-update-where-function-expression': case 'database-table-initialization-delete-where-function-expression': $this->init_expression = array(); break; /* Definition */ case 'database': $this->database_definition = array( 'name' => '', 'create' => '', 'overwrite' => '', 'charset' => '', 'description' => '', 'comments' => '', 'tables' => array(), 'sequences' => array() ); break; case 'database-table': $this->table_name = ''; $this->table = array( 'was' => '', 'description' => '', 'comments' => '', 'fields' => array(), 'indexes' => array(), 'constraints' => array(), 'initialization' => array() ); break; case 'database-table-declaration-field': case 'database-table-declaration-foreign-field': case 'database-table-declaration-foreign-references-field': $this->field_name = ''; $this->field = array(); break; case 'database-table-declaration-index-field': $this->field_name = ''; $this->field = array('sorting' => '', 'length' => ''); break; /* force field attributes to be initialized when the tag is empty in the XML */ case 'database-table-declaration-field-was': $this->field['was'] = ''; break; case 'database-table-declaration-field-type': $this->field['type'] = ''; break; case 'database-table-declaration-field-fixed': $this->field['fixed'] = ''; break; case 'database-table-declaration-field-default': $this->field['default'] = ''; break; case 'database-table-declaration-field-notnull': $this->field['notnull'] = ''; break; case 'database-table-declaration-field-autoincrement': $this->field['autoincrement'] = ''; break; case 'database-table-declaration-field-unsigned': $this->field['unsigned'] = ''; break; case 'database-table-declaration-field-length': $this->field['length'] = ''; break; case 'database-table-declaration-field-description': $this->field['description'] = ''; break; case 'database-table-declaration-field-comments': $this->field['comments'] = ''; break; case 'database-table-declaration-index': $this->index_name = ''; $this->index = array( 'was' => '', 'unique' =>'', 'primary' => '', 'fields' => array() ); break; case 'database-table-declaration-foreign': $this->constraint_name = ''; $this->constraint = array( 'was' => '', 'match' => '', 'ondelete' => '', 'onupdate' => '', 'deferrable' => '', 'initiallydeferred' => '', 'foreign' => true, 'fields' => array(), 'references' => array('table' => '', 'fields' => array()) ); break; case 'database-sequence': $this->sequence_name = ''; $this->sequence = array( 'was' => '', 'start' => '', 'description' => '', 'comments' => '', 'on' => array('table' => '', 'field' => '') ); break; } } function endHandler($xp, $element) { if (strtolower($element) == 'variable') { $this->var_mode = false; return; } switch ($this->element) { /* Initialization */ /* Insert */ case 'database-table-initialization-insert-select': $this->init['data'] = array('select' => $this->init['data']); break; /* Insert and Delete */ case 'database-table-initialization-insert-field': case 'database-table-initialization-insert-select-field': case 'database-table-initialization-update-field': $result = $this->val->validateDataField($this->table['fields'], $this->init['data']['field'], $this->init_field); if (PEAR::isError($result)) { $this->raiseError($result->getUserinfo(), 0, $xp, $result->getCode()); } else { $this->init['data']['field'][] = $this->init_field; } break; case 'database-table-initialization-insert-field-function': case 'database-table-initialization-insert-select-field-function': case 'database-table-initialization-update-field-function': $this->init_field['group'] = array('type' => 'function', 'data' => $this->init_function); break; case 'database-table-initialization-insert-field-expression': case 'database-table-initialization-insert-select-field-expression': case 'database-table-initialization-update-field-expression': $this->init_field['group'] = array('type' => 'expression', 'data' => $this->init_expression); break; /* All */ case 'database-table-initialization-insert-select-where-expression': case 'database-table-initialization-update-where-expression': case 'database-table-initialization-delete-where-expression': $this->init['data']['where']['type'] = 'expression'; $this->init['data']['where']['data'] = $this->init_expression; break; case 'database-table-initialization-insert': case 'database-table-initialization-delete': case 'database-table-initialization-update': $this->table['initialization'][] = $this->init; break; /* One level simulation of expression-function recursion */ case 'database-table-initialization-insert-field-expression-function': case 'database-table-initialization-insert-select-field-expression-function': case 'database-table-initialization-insert-select-where-expression-function': case 'database-table-initialization-update-field-expression-function': case 'database-table-initialization-update-where-expression-function': case 'database-table-initialization-delete-where-expression-function': $this->init_expression['operants'][] = array('type' => 'function', 'data' => $this->init_function); break; /* One level simulation of function-expression recursion */ case 'database-table-initialization-insert-field-function-expression': case 'database-table-initialization-insert-select-field-function-expression': case 'database-table-initialization-insert-select-where-function-expression': case 'database-table-initialization-update-field-function-expression': case 'database-table-initialization-update-where-function-expression': case 'database-table-initialization-delete-where-function-expression': $this->init_function['arguments'][] = array('type' => 'expression', 'data' => $this->init_expression); break; /* Table definition */ case 'database-table': $result = $this->val->validateTable($this->database_definition['tables'], $this->table, $this->table_name); if (PEAR::isError($result)) { $this->raiseError($result->getUserinfo(), 0, $xp, $result->getCode()); } else { $this->database_definition['tables'][$this->table_name] = $this->table; } break; case 'database-table-name': if (isset($this->structure['tables'][$this->table_name])) { $this->table = $this->structure['tables'][$this->table_name]; } break; /* Field declaration */ case 'database-table-declaration-field': $result = $this->val->validateField($this->table['fields'], $this->field, $this->field_name); if (PEAR::isError($result)) { $this->raiseError($result->getUserinfo(), 0, $xp, $result->getCode()); } else { $this->table['fields'][$this->field_name] = $this->field; } break; /* Index declaration */ case 'database-table-declaration-index': $result = $this->val->validateIndex($this->table['indexes'], $this->index, $this->index_name); if (PEAR::isError($result)) { $this->raiseError($result->getUserinfo(), 0, $xp, $result->getCode()); } else { $this->table['indexes'][$this->index_name] = $this->index; } break; case 'database-table-declaration-index-field': $result = $this->val->validateIndexField($this->index['fields'], $this->field, $this->field_name); if (PEAR::isError($result)) { $this->raiseError($result->getUserinfo(), 0, $xp, $result->getCode()); } else { $this->index['fields'][$this->field_name] = $this->field; } break; /* Foreign Key declaration */ case 'database-table-declaration-foreign': $result = $this->val->validateConstraint($this->table['constraints'], $this->constraint, $this->constraint_name); if (PEAR::isError($result)) { $this->raiseError($result->getUserinfo(), 0, $xp, $result->getCode()); } else { $this->table['constraints'][$this->constraint_name] = $this->constraint; } break; case 'database-table-declaration-foreign-field': $result = $this->val->validateConstraintField($this->constraint['fields'], $this->field_name); if (PEAR::isError($result)) { $this->raiseError($result->getUserinfo(), 0, $xp, $result->getCode()); } else { $this->constraint['fields'][$this->field_name] = ''; } break; case 'database-table-declaration-foreign-references-field': $result = $this->val->validateConstraintReferencedField($this->constraint['references']['fields'], $this->field_name); if (PEAR::isError($result)) { $this->raiseError($result->getUserinfo(), 0, $xp, $result->getCode()); } else { $this->constraint['references']['fields'][$this->field_name] = ''; } break; /* Sequence declaration */ case 'database-sequence': $result = $this->val->validateSequence($this->database_definition['sequences'], $this->sequence, $this->sequence_name); if (PEAR::isError($result)) { $this->raiseError($result->getUserinfo(), 0, $xp, $result->getCode()); } else { $this->database_definition['sequences'][$this->sequence_name] = $this->sequence; } break; /* End of File */ case 'database': $result = $this->val->validateDatabase($this->database_definition); if (PEAR::isError($result)) { $this->raiseError($result->getUserinfo(), 0, $xp, $result->getCode()); } break; } unset($this->elements[--$this->count]); $this->element = implode('-', $this->elements); } function &raiseError($msg = null, $xmlecode = 0, $xp = null, $ecode = MDB2_SCHEMA_ERROR_PARSE) { if (is_null($this->error)) { $error = ''; if (is_resource($msg)) { $error .= 'Parser error: '.xml_error_string(xml_get_error_code($msg)); $xp = $msg; } else { $error .= 'Parser error: '.$msg; if (!is_resource($xp)) { $xp = $this->parser; } } if ($error_string = xml_error_string($xmlecode)) { $error .= ' - '.$error_string; } if (is_resource($xp)) { $byte = @xml_get_current_byte_index($xp); $line = @xml_get_current_line_number($xp); $column = @xml_get_current_column_number($xp); $error .= " - Byte: $byte; Line: $line; Col: $column"; } $error .= "\n"; $this->error =& MDB2_Schema::raiseError($ecode, null, null, $error); } return $this->error; } function cdataHandler($xp, $data) { if ($this->var_mode == true) { if (!isset($this->variables[$data])) { $this->raiseError('variable "'.$data.'" not found', null, $xp); return; } $data = $this->variables[$data]; } switch ($this->element) { /* Initialization */ /* Insert */ case 'database-table-initialization-insert-select-table': $this->init['data']['table'] = $data; break; /* Insert and Update */ case 'database-table-initialization-insert-field-name': case 'database-table-initialization-insert-select-field-name': case 'database-table-initialization-update-field-name': $this->init_field['name'] .= $data; break; case 'database-table-initialization-insert-field-value': case 'database-table-initialization-insert-select-field-value': case 'database-table-initialization-update-field-value': $this->init_field['group']['data'] .= $data; break; case 'database-table-initialization-insert-field-function-name': case 'database-table-initialization-insert-select-field-function-name': case 'database-table-initialization-update-field-function-name': $this->init_function['name'] .= $data; break; case 'database-table-initialization-insert-field-function-value': case 'database-table-initialization-insert-select-field-function-value': case 'database-table-initialization-update-field-function-value': $this->init_function['arguments'][] = array('type' => 'value', 'data' => $data); break; case 'database-table-initialization-insert-field-function-column': case 'database-table-initialization-insert-select-field-function-column': case 'database-table-initialization-update-field-function-column': $this->init_function['arguments'][] = array('type' => 'column', 'data' => $data); break; case 'database-table-initialization-insert-field-column': case 'database-table-initialization-insert-select-field-column': case 'database-table-initialization-update-field-column': $this->init_field['group'] = array('type' => 'column', 'data' => $data); break; /* All */ case 'database-table-initialization-insert-field-expression-operator': case 'database-table-initialization-insert-select-field-expression-operator': case 'database-table-initialization-insert-select-where-expression-operator': case 'database-table-initialization-update-field-expression-operator': case 'database-table-initialization-update-where-expression-operator': case 'database-table-initialization-delete-where-expression-operator': $this->init_expression['operator'] = $data; break; case 'database-table-initialization-insert-field-expression-value': case 'database-table-initialization-insert-select-field-expression-value': case 'database-table-initialization-insert-select-where-expression-value': case 'database-table-initialization-update-field-expression-value': case 'database-table-initialization-update-where-expression-value': case 'database-table-initialization-delete-where-expression-value': $this->init_expression['operants'][] = array('type' => 'value', 'data' => $data); break; case 'database-table-initialization-insert-field-expression-column': case 'database-table-initialization-insert-select-field-expression-column': case 'database-table-initialization-insert-select-where-expression-column': case 'database-table-initialization-update-field-expression-column': case 'database-table-initialization-update-where-expression-column': case 'database-table-initialization-delete-where-expression-column': $this->init_expression['operants'][] = array('type' => 'column', 'data' => $data); break; case 'database-table-initialization-insert-field-function-function': case 'database-table-initialization-insert-field-function-expression': case 'database-table-initialization-insert-field-expression-expression': case 'database-table-initialization-update-field-function-function': case 'database-table-initialization-update-field-function-expression': case 'database-table-initialization-update-field-expression-expression': case 'database-table-initialization-update-where-expression-expression': case 'database-table-initialization-delete-where-expression-expression': /* Recursion to be implemented yet */ break; /* One level simulation of expression-function recursion */ case 'database-table-initialization-insert-field-expression-function-name': case 'database-table-initialization-insert-select-field-expression-function-name': case 'database-table-initialization-insert-select-where-expression-function-name': case 'database-table-initialization-update-field-expression-function-name': case 'database-table-initialization-update-where-expression-function-name': case 'database-table-initialization-delete-where-expression-function-name': $this->init_function['name'] .= $data; break; case 'database-table-initialization-insert-field-expression-function-value': case 'database-table-initialization-insert-select-field-expression-function-value': case 'database-table-initialization-insert-select-where-expression-function-value': case 'database-table-initialization-update-field-expression-function-value': case 'database-table-initialization-update-where-expression-function-value': case 'database-table-initialization-delete-where-expression-function-value': $this->init_function['arguments'][] = array('type' => 'value', 'data' => $data); break; case 'database-table-initialization-insert-field-expression-function-column': case 'database-table-initialization-insert-select-field-expression-function-column': case 'database-table-initialization-insert-select-where-expression-function-column': case 'database-table-initialization-update-field-expression-function-column': case 'database-table-initialization-update-where-expression-function-column': case 'database-table-initialization-delete-where-expression-function-column': $this->init_function['arguments'][] = array('type' => 'column', 'data' => $data); break; /* One level simulation of function-expression recursion */ case 'database-table-initialization-insert-field-function-expression-operator': case 'database-table-initialization-insert-select-field-function-expression-operator': case 'database-table-initialization-update-field-function-expression-operator': $this->init_expression['operator'] = $data; break; case 'database-table-initialization-insert-field-function-expression-value': case 'database-table-initialization-insert-select-field-function-expression-value': case 'database-table-initialization-update-field-function-expression-value': $this->init_expression['operants'][] = array('type' => 'value', 'data' => $data); break; case 'database-table-initialization-insert-field-function-expression-column': case 'database-table-initialization-insert-select-field-function-expression-column': case 'database-table-initialization-update-field-function-expression-column': $this->init_expression['operants'][] = array('type' => 'column', 'data' => $data); break; /* Database */ case 'database-name': $this->database_definition['name'] .= $data; break; case 'database-create': $this->database_definition['create'] .= $data; break; case 'database-overwrite': $this->database_definition['overwrite'] .= $data; break; case 'database-charset': $this->database_definition['charset'] .= $data; break; case 'database-description': $this->database_definition['description'] .= $data; break; case 'database-comments': $this->database_definition['comments'] .= $data; break; /* Table declaration */ case 'database-table-name': $this->table_name .= $data; break; case 'database-table-was': $this->table['was'] .= $data; break; case 'database-table-description': $this->table['description'] .= $data; break; case 'database-table-comments': $this->table['comments'] .= $data; break; /* Field declaration */ case 'database-table-declaration-field-name': $this->field_name .= $data; break; case 'database-table-declaration-field-was': $this->field['was'] .= $data; break; case 'database-table-declaration-field-type': $this->field['type'] .= $data; break; case 'database-table-declaration-field-fixed': $this->field['fixed'] .= $data; break; case 'database-table-declaration-field-default': $this->field['default'] .= $data; break; case 'database-table-declaration-field-notnull': $this->field['notnull'] .= $data; break; case 'database-table-declaration-field-autoincrement': $this->field['autoincrement'] .= $data; break; case 'database-table-declaration-field-unsigned': $this->field['unsigned'] .= $data; break; case 'database-table-declaration-field-length': $this->field['length'] .= $data; break; case 'database-table-declaration-field-description': $this->field['description'] .= $data; break; case 'database-table-declaration-field-comments': $this->field['comments'] .= $data; break; /* Index declaration */ case 'database-table-declaration-index-name': $this->index_name .= $data; break; case 'database-table-declaration-index-was': $this->index['was'] .= $data; break; case 'database-table-declaration-index-unique': $this->index['unique'] .= $data; break; case 'database-table-declaration-index-primary': $this->index['primary'] .= $data; break; case 'database-table-declaration-index-field-name': $this->field_name .= $data; break; case 'database-table-declaration-index-field-sorting': $this->field['sorting'] .= $data; break; /* Add by Leoncx */ case 'database-table-declaration-index-field-length': $this->field['length'] .= $data; break; /* Foreign Key declaration */ case 'database-table-declaration-foreign-name': $this->constraint_name .= $data; break; case 'database-table-declaration-foreign-was': $this->constraint['was'] .= $data; break; case 'database-table-declaration-foreign-match': $this->constraint['match'] .= $data; break; case 'database-table-declaration-foreign-ondelete': $this->constraint['ondelete'] .= $data; break; case 'database-table-declaration-foreign-onupdate': $this->constraint['onupdate'] .= $data; break; case 'database-table-declaration-foreign-deferrable': $this->constraint['deferrable'] .= $data; break; case 'database-table-declaration-foreign-initiallydeferred': $this->constraint['initiallydeferred'] .= $data; break; case 'database-table-declaration-foreign-field': $this->field_name .= $data; break; case 'database-table-declaration-foreign-references-table': $this->constraint['references']['table'] .= $data; break; case 'database-table-declaration-foreign-references-field': $this->field_name .= $data; break; /* Sequence declaration */ case 'database-sequence-name': $this->sequence_name .= $data; break; case 'database-sequence-was': $this->sequence['was'] .= $data; break; case 'database-sequence-start': $this->sequence['start'] .= $data; break; case 'database-sequence-description': $this->sequence['description'] .= $data; break; case 'database-sequence-comments': $this->sequence['comments'] .= $data; break; case 'database-sequence-on-table': $this->sequence['on']['table'] .= $data; break; case 'database-sequence-on-field': $this->sequence['on']['field'] .= $data; break; } } } ?> MDB2_Schema-0.8.5/MDB2/Schema/Parser2.php100644 765 765 53102 11150346546 12625 * * @category Database * @package MDB2_Schema * @author Igor Feghali * @license BSD http://www.opensource.org/licenses/bsd-license.php * @version CVS: $Id: Parser2.php,v 1.12 2008/11/30 03:34:00 clockwerx Exp $ * @link http://pear.php.net/packages/MDB2_Schema */ require_once 'XML/Unserializer.php'; require_once 'MDB2/Schema/Validate.php'; /** * Parses an XML schema file * * @category Database * @package MDB2_Schema * @author Lukas Smith * @author Igor Feghali * @license BSD http://www.opensource.org/licenses/bsd-license.php * @link http://pear.php.net/packages/MDB2_Schema */ class MDB2_Schema_Parser2 extends XML_Unserializer { var $database_definition = array(); var $database_loaded = array(); var $variables = array(); var $error; var $structure = false; var $val; var $options = array(); var $table = array(); var $table_name = ''; var $field = array(); var $field_name = ''; var $index = array(); var $index_name = ''; var $constraint = array(); var $constraint_name = ''; var $sequence = array(); var $sequence_name = ''; var $init = array(); function __construct($variables, $fail_on_invalid_names = true, $structure = false, $valid_types = array(), $force_defaults = true) { // force ISO-8859-1 due to different defaults for PHP4 and PHP5 // todo: this probably needs to be investigated some more and cleaned up $this->options['encoding'] = 'ISO-8859-1'; $this->options['XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE'] = true; $this->options['XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY'] = false; $this->options['forceEnum'] = array('table', 'field', 'index', 'foreign', 'insert', 'update', 'delete', 'sequence'); /* * todo: find a way to force the following items not to be parsed as arrays * as it cause problems in functions with multiple arguments */ //$this->options['forceNEnum'] = array('value', 'column'); $this->variables = $variables; $this->structure = $structure; $this->val =& new MDB2_Schema_Validate($fail_on_invalid_names, $valid_types, $force_defaults); parent::XML_Unserializer($this->options); } function MDB2_Schema_Parser2($variables, $fail_on_invalid_names = true, $structure = false, $valid_types = array(), $force_defaults = true) { $this->__construct($variables, $fail_on_invalid_names, $structure, $valid_types, $force_defaults); } function parse() { $result = $this->unserialize($this->filename, true); if (PEAR::isError($result)) { return $result; } else { $this->database_loaded = $this->getUnserializedData(); return $this->fixDatabaseKeys($this->database_loaded); } } function setInputFile($filename) { $this->filename = $filename; return MDB2_OK; } function renameKey(&$arr, $oKey, $nKey) { $arr[$nKey] = &$arr[$oKey]; unset($arr[$oKey]); } function fixDatabaseKeys($database) { $this->database_definition = array( 'name' => '', 'create' => '', 'overwrite' => '', 'charset' => '', 'description' => '', 'comments' => '', 'tables' => array(), 'sequences' => array() ); if (!empty($database['name'])) { $this->database_definition['name'] = $database['name']; } if (!empty($database['create'])) { $this->database_definition['create'] = $database['create']; } if (!empty($database['overwrite'])) { $this->database_definition['overwrite'] = $database['overwrite']; } if (!empty($database['charset'])) { $this->database_definition['charset'] = $database['charset']; } if (!empty($database['description'])) { $this->database_definition['description'] = $database['description']; } if (!empty($database['comments'])) { $this->database_definition['comments'] = $database['comments']; } if (!empty($database['table']) && is_array($database['table'])) { foreach ($database['table'] as $table) { $this->fixTableKeys($table); } } if (!empty($database['sequence']) && is_array($database['sequence'])) { foreach ($database['sequence'] as $sequence) { $this->fixSequenceKeys($sequence); } } $result = $this->val->validateDatabase($this->database_definition); if (PEAR::isError($result)) { return $this->raiseError($result->getUserinfo()); } return MDB2_OK; } function fixTableKeys($table) { $this->table = array( 'was' => '', 'description' => '', 'comments' => '', 'fields' => array(), 'indexes' => array(), 'constraints' => array(), 'initialization' => array() ); if (!empty($table['name'])) { $this->table_name = $table['name']; } else { $this->table_name = ''; } if (!empty($table['was'])) { $this->table['was'] = $table['was']; } if (!empty($table['description'])) { $this->table['description'] = $table['description']; } if (!empty($table['comments'])) { $this->table['comments'] = $table['comments']; } if (!empty($table['declaration']) && is_array($table['declaration'])) { if (!empty($table['declaration']['field']) && is_array($table['declaration']['field'])) { foreach ($table['declaration']['field'] as $field) { $this->fixTableFieldKeys($field); } } if (!empty($table['declaration']['index']) && is_array($table['declaration']['index'])) { foreach ($table['declaration']['index'] as $index) { $this->fixTableIndexKeys($index); } } if (!empty($table['declaration']['foreign']) && is_array($table['declaration']['foreign'])) { foreach ($table['declaration']['foreign'] as $constraint) { $this->fixTableConstraintKeys($constraint); } } } if (!empty($table['initialization']) && is_array($table['initialization'])) { if (!empty($table['initialization']['insert']) && is_array($table['initialization']['insert'])) { foreach ($table['initialization']['insert'] as $init) { $this->fixTableInitializationKeys($init, 'insert'); } } if (!empty($table['initialization']['update']) && is_array($table['initialization']['update'])) { foreach ($table['initialization']['update'] as $init) { $this->fixTableInitializationKeys($init, 'update'); } } if (!empty($table['initialization']['delete']) && is_array($table['initialization']['delete'])) { foreach ($table['initialization']['delete'] as $init) { $this->fixTableInitializationKeys($init, 'delete'); } } } $result = $this->val->validateTable($this->database_definition['tables'], $this->table, $this->table_name); if (PEAR::isError($result)) { return $this->raiseError($result->getUserinfo()); } else { $this->database_definition['tables'][$this->table_name] = $this->table; } return MDB2_OK; } function fixTableFieldKeys($field) { $this->field = array(); if (!empty($field['name'])) { $this->field_name = $field['name']; } else { $this->field_name = ''; } if (!empty($field['was'])) { $this->field['was'] = $field['was']; } if (!empty($field['type'])) { $this->field['type'] = $field['type']; } if (!empty($field['fixed'])) { $this->field['fixed'] = $field['fixed']; } if (isset($field['default'])) { $this->field['default'] = $field['default']; } if (!empty($field['notnull'])) { $this->field['notnull'] = $field['notnull']; } if (!empty($field['autoincrement'])) { $this->field['autoincrement'] = $field['autoincrement']; } if (!empty($field['unsigned'])) { $this->field['unsigned'] = $field['unsigned']; } if (!empty($field['length'])) { $this->field['length'] = $field['length']; } if (!empty($field['description'])) { $this->field['description'] = $field['description']; } if (!empty($field['comments'])) { $this->field['comments'] = $field['comments']; } $result = $this->val->validateField($this->table['fields'], $this->field, $this->field_name); if (PEAR::isError($result)) { return $this->raiseError($result->getUserinfo()); } else { $this->table['fields'][$this->field_name] = $this->field; } return MDB2_OK; } function fixTableIndexKeys($index) { $this->index = array( 'was' => '', 'unique' =>'', 'primary' => '', 'fields' => array() ); if (!empty($index['name'])) { $this->index_name = $index['name']; } else { $this->index_name = ''; } if (!empty($index['was'])) { $this->index['was'] = $index['was']; } if (!empty($index['unique'])) { $this->index['unique'] = $index['unique']; } if (!empty($index['primary'])) { $this->index['primary'] = $index['primary']; } if (!empty($index['field'])) { foreach ($index['field'] as $field) { if (!empty($field['name'])) { $this->field_name = $field['name']; } else { $this->field_name = ''; } $this->field = array( 'sorting' => '', 'length' => '' ); if (!empty($field['sorting'])) { $this->field['sorting'] = $field['sorting']; } if (!empty($field['length'])) { $this->field['length'] = $field['length']; } $result = $this->val->validateIndexField($this->index['fields'], $this->field, $this->field_name); if (PEAR::isError($result)) { return $this->raiseError($result->getUserinfo()); } $this->index['fields'][$this->field_name] = $this->field; } } $result = $this->val->validateIndex($this->table['indexes'], $this->index, $this->index_name); if (PEAR::isError($result)) { return $this->raiseError($result->getUserinfo()); } else { $this->table['indexes'][$this->index_name] = $this->index; } return MDB2_OK; } function fixTableConstraintKeys($constraint) { $this->constraint = array( 'was' => '', 'match' => '', 'ondelete' => '', 'onupdate' => '', 'deferrable' => '', 'initiallydeferred' => '', 'foreign' => true, 'fields' => array(), 'references' => array('table' => '', 'fields' => array()) ); if (!empty($constraint['name'])) { $this->constraint_name = $constraint['name']; } else { $this->constraint_name = ''; } if (!empty($constraint['was'])) { $this->constraint['was'] = $constraint['was']; } if (!empty($constraint['match'])) { $this->constraint['match'] = $constraint['match']; } if (!empty($constraint['ondelete'])) { $this->constraint['ondelete'] = $constraint['ondelete']; } if (!empty($constraint['onupdate'])) { $this->constraint['onupdate'] = $constraint['onupdate']; } if (!empty($constraint['deferrable'])) { $this->constraint['deferrable'] = $constraint['deferrable']; } if (!empty($constraint['initiallydeferred'])) { $this->constraint['initiallydeferred'] = $constraint['initiallydeferred']; } if (!empty($constraint['field']) && is_array($constraint['field'])) { foreach ($constraint['field'] as $field) { $result = $this->val->validateConstraintField($this->constraint['fields'], $field); if (PEAR::isError($result)) { return $this->raiseError($result->getUserinfo()); } $this->constraint['fields'][$field] = ''; } } if (!empty($constraint['references']) && is_array($constraint['references'])) { /** * As we forced 'table' to be enumerated * we have to fix it on the foreign-references-table context */ if (!empty($constraint['references']['table']) && is_array($constraint['references']['table'])) { $this->constraint['references']['table'] = $constraint['references']['table'][0]; } if (!empty($constraint['references']['field']) && is_array($constraint['references']['field'])) { foreach ($constraint['references']['field'] as $field) { $result = $this->val->validateConstraintReferencedField($this->constraint['references']['fields'], $field); if (PEAR::isError($result)) { return $this->raiseError($result->getUserinfo()); } $this->constraint['references']['fields'][$field] = ''; } } } $result = $this->val->validateConstraint($this->table['constraints'], $this->constraint, $this->constraint_name); if (PEAR::isError($result)) { return $this->raiseError($result->getUserinfo()); } else { $this->table['constraints'][$this->constraint_name] = $this->constraint; } return MDB2_OK; } function fixTableInitializationKeys($element, $type = '') { if (!empty($element['select']) && is_array($element['select'])) { $this->fixTableInitializationDataKeys($element['select']); $this->init = array( 'select' => $this->init ); } else { $this->fixTableInitializationDataKeys($element); } $this->table['initialization'][] = array( 'type' => $type, 'data' => $this->init ); } function fixTableInitializationDataKeys($element) { $this->init = array(); if (!empty($element['field']) && is_array($element['field'])) { foreach ($element['field'] as $field) { $name = $field['name']; unset($field['name']); $this->setExpression($field); $this->init['field'][] = array( 'name' => $name, 'group' => $field ); } } /** * As we forced 'table' to be enumerated * we have to fix it on the insert-select context */ if (!empty($element['table']) && is_array($element['table'])) { $this->init['table'] = $element['table'][0]; } if (!empty($element['where']) && is_array($element['where'])) { $this->init['where'] = $element['where']; $this->setExpression($this->init['where']); } } function setExpression(&$arr) { $element = each($arr); $arr = array( 'type' => $element['key'] ); $element = $element['value']; switch ($arr['type']) { case 'null': break; case 'value': case 'column': $arr['data'] = $element; break; case 'function': if (!empty($element) && is_array($element) ) { $arr['data'] = array( 'name' => $element['name'] ); unset($element['name']); foreach ($element as $type => $value) { if (!empty($value)) { if (is_array($value)) { foreach ($value as $argument) { $argument = array( $type => $argument ); $this->setExpression($argument); $arr['data']['arguments'][] = $argument; } } else { $arr['data']['arguments'][] = array( 'type' => $type, 'data' => $value ); } } } } break; case 'expression': $arr['data'] = array( 'operants' => array(), 'operator' => $element['operator'] ); unset($element['operator']); foreach ($element as $k => $v) { $argument = array( $k => $v ); $this->setExpression($argument); $arr['data']['operants'][] = $argument; } break; } } function fixSequenceKeys($sequence) { $this->sequence = array( 'was' => '', 'start' => '', 'description' => '', 'comments' => '', 'on' => array('table' => '', 'field' => '') ); if (!empty($sequence['name'])) { $this->sequence_name = $sequence['name']; } else { $this->sequence_name = ''; } if (!empty($sequence['was'])) { $this->sequence['was'] = $sequence['was']; } if (!empty($sequence['start'])) { $this->sequence['start'] = $sequence['start']; } if (!empty($sequence['description'])) { $this->sequence['description'] = $sequence['description']; } if (!empty($sequence['comments'])) { $this->sequence['comments'] = $sequence['comments']; } if (!empty($sequence['on']) && is_array($sequence['on'])) { /** * As we forced 'table' to be enumerated * we have to fix it on the sequence-on-table context */ if (!empty($sequence['on']['table']) && is_array($sequence['on']['table'])) { $this->sequence['on']['table'] = $sequence['on']['table'][0]; } /** * As we forced 'field' to be enumerated * we have to fix it on the sequence-on-field context */ if (!empty($sequence['on']['field']) && is_array($sequence['on']['field'])) { $this->sequence['on']['field'] = $sequence['on']['field'][0]; } } $result = $this->val->validateSequence($this->database_definition['sequences'], $this->sequence, $this->sequence_name); if (PEAR::isError($result)) { return $this->raiseError($result->getUserinfo()); } else { $this->database_definition['sequences'][$this->sequence_name] = $this->sequence; } return MDB2_OK; } function &raiseError($msg = null, $ecode = MDB2_SCHEMA_ERROR_PARSE) { if (is_null($this->error)) { $error = 'Parser error: '.$msg."\n"; $this->error =& MDB2_Schema::raiseError($ecode, null, null, $error); } return $this->error; } } ?> MDB2_Schema-0.8.5/MDB2/Schema/Tool.php100644 765 765 36724 11150346546 12237 * $Id: Tool.php,v 1.6 2008/12/13 00:26:07 clockwerx Exp $ * * @category Database * @package MDB2_Schema * @author Christian Weiske * @license BSD http://www.opensource.org/licenses/bsd-license.php * @version CVS: $Id: Tool.php,v 1.6 2008/12/13 00:26:07 clockwerx Exp $ * @link http://pear.php.net/packages/MDB2_Schema */ require_once 'MDB2/Schema.php'; require_once 'MDB2/Schema/Tool/ParameterException.php'; /** * Command line tool to work with database schemas * * Functionality: * - dump a database schema to stdout * - import schema into database * - create a diff between two schemas * - apply diff to database * * @category Database * @package MDB2_Schema * @author Christian Weiske * @license BSD http://www.opensource.org/licenses/bsd-license.php * @link http://pear.php.net/packages/MDB2_Schema */ class MDB2_Schema_Tool { /** * Run the schema tool * * @param array $args Array of command line arguments */ public function __construct($args) { $strAction = $this->getAction($args); try { $this->{'do' . ucfirst($strAction)}($args); } catch (MDB2_Schema_Tool_ParameterException $e) { $this->{'doHelp' . ucfirst($strAction)}($e->getMessage()); } }//public function __construct($args) /** * Runs the tool with command line arguments * * @return void */ public static function run() { $args = $GLOBALS['argv']; array_shift($args); try { $tool = new MDB2_Schema_Tool($args); } catch (Exception $e) { self::toStdErr($e->getMessage() . "\n"); } }//public static function run() /** * Reads the first parameter from the argument array and * returns the action. * * @param array &$args Command line parameters * * @return string Action to execute */ protected function getAction(&$args) { if (count($args) == 0) { return 'help'; } $arg = array_shift($args); switch ($arg) { case 'h': case 'help': case '-h': case '--help': return 'help'; case 'd': case 'dump': case '-d': case '--dump': return 'dump'; case 'l': case 'load': case '-l': case '--load': return 'load'; case 'i': case 'diff': case '-i': case '--diff': return 'diff'; case 'a': case 'apply': case '-a': case '--apply': return 'apply'; case 'n': case 'init': case '-i': case '--init': return 'init'; default: throw new MDB2_Schema_Tool_ParameterException("Unknown mode \"$arg\""); } }//protected function getAction(&$args) /** * Writes the message to stderr * * @param string $msg Message to print * * @return void */ protected static function toStdErr($msg) { file_put_contents('php://stderr', $msg); }//protected static function toStdErr($msg) /** * Displays generic help to stdout * * @return void */ protected function doHelp() { self::toStdErr(<< '
', 'idxname_format' => '%s', 'debug' => true, 'quote_identifier' => true, 'force_defaults' => false, 'portability' => true, 'use_transactions' => false, ); return $options; }//protected function getSchemaOptions() /** * Checks if the passed parameter is a PEAR_Error object * and throws an exception in that case. * * @param mixed $object Some variable to check * @param string $location Where the error occured * * @return void */ protected function throwExceptionOnError($object, $location = '') { if (PEAR::isError($object)) { //FIXME: exception class //debug_print_backtrace(); throw new Exception('Error ' . $location . "\n" . $object->getMessage() . "\n" . $object->getUserInfo() ); } }//protected function throwExceptionOnError($object, $location = '') /** * Loads a file or a dsn from the arguments * * @param array &$args Array of arguments to the program * * @return array Array of ('file'|'dsn', $value) */ protected function getFileOrDsn(&$args) { if (count($args) == 0) { throw new MDB2_Schema_Tool_ParameterException('File or DSN expected'); } $arg = array_shift($args); if ($arg == '-p') { $bAskPassword = true; $arg = array_shift($args); } else { $bAskPassword = false; } if (strpos($arg, '://') === false) { if (file_exists($arg)) { //File return array('file', $arg); } else { throw new Exception('Schema file does not exist'); } } //read password if necessary if ($bAskPassword) { $password = $this->readPasswordFromStdin($arg); $arg = self::setPasswordIntoDsn($arg, $password); self::toStdErr($arg); } return array('dsn', $arg); }//protected function getFileOrDsn(&$args) /** * Takes a DSN data source name and integrates the given * password into it. * * @param string $dsn Data source name * @param string $password Password * * @return string DSN with password */ protected function setPasswordIntoDsn($dsn, $password) { //simple try to integrate password if (strpos($dsn, '@') === false) { //no @ -> no user and no password return str_replace('://', '://:' . $password . '@', $dsn); } else if (preg_match('|://[^:]+@|', $dsn)) { //user only, no password return str_replace('@', ':' . $password . '@', $dsn); } else if (strpos($dsn, ':@') !== false) { //abstract version return str_replace(':@', ':' . $password . '@', $dsn); } return $dsn; }//protected function setPasswordIntoDsn($dsn, $password) /** * Reads a password from stdin * * @param string $dsn DSN name to put into the message * * @return string Password */ protected function readPasswordFromStdin($dsn) { $stdin = fopen('php://stdin', 'r'); self::toStdErr('Please insert password for ' . $dsn . "\n"); $password = ''; $breakme = false; while (false !== ($char = fgetc($stdin))) { if (ord($char) == 10 || $char == "\n" || $char == "\r") { break; } $password .= $char; } fclose($stdin); return trim($password); }//protected function readPasswordFromStdin() /** * Creates a database schema dump and sends it to stdout * * @param array $args Command line arguments * * @return void */ protected function doDump($args) { $dump_what = MDB2_SCHEMA_DUMP_STRUCTURE; $arg = ''; if (count($args)) { $arg = $args[0]; } switch (strtolower($arg)) { case 'all': $dump_what = MDB2_SCHEMA_DUMP_ALL; array_shift($args); break; case 'data': $dump_what = MDB2_SCHEMA_DUMP_CONTENT; array_shift($args); break; case 'schema': array_shift($args); } list($type, $dsn) = $this->getFileOrDsn($args); if ($type == 'file') { throw new MDB2_Schema_Tool_ParameterException( 'Dumping a schema file as a schema file does not make much sense' ); } $schema = MDB2_Schema::factory($dsn, $this->getSchemaOptions()); $this->throwExceptionOnError($schema); $definition = $schema->getDefinitionFromDatabase(); $this->throwExceptionOnError($definition); $dump_options = array( 'output_mode' => 'file', 'output' => 'php://stdout', 'end_of_line' => "\r\n" ); $op = $schema->dumpDatabase( $definition, $dump_options, $dump_what ); $this->throwExceptionOnError($op); $schema->disconnect(); }//protected function doDump($args) /** * Loads a database schema * * @param array $args Command line arguments * * @return void */ protected function doLoad($args) { list($typeSource, $dsnSource) = $this->getFileOrDsn($args); list($typeDest, $dsnDest) = $this->getFileOrDsn($args); if ($typeDest == 'file') { throw new MDB2_Schema_Tool_ParameterException( 'A schema can only be loaded into a database, not a file' ); } $schemaDest = MDB2_Schema::factory($dsnDest, $this->getSchemaOptions()); $this->throwExceptionOnError($schemaDest); //load definition if ($typeSource == 'file') { $definition = $schemaDest->parseDatabaseDefinitionFile($dsnSource); $where = 'loading schema file'; } else { $schemaSource = MDB2_Schema::factory($dsnSource, $this->getSchemaOptions()); $this->throwExceptionOnError($schemaSource, 'connecting to source database'); $definition = $schemaSource->getDefinitionFromDatabase(); $where = 'loading definition from database'; } $this->throwExceptionOnError($definition, $where); //create destination database from definition $simulate = false; $op = $schemaDest->createDatabase($definition, array(), $simulate); $this->throwExceptionOnError($op, 'creating the database'); }//protected function doLoad($args) /** * Initializes a database with data * * @param array $args Command line arguments * * @return void */ protected function doInit($args) { list($typeSource, $dsnSource) = $this->getFileOrDsn($args); list($typeDest, $dsnDest) = $this->getFileOrDsn($args); if ($typeSource != 'file') { throw new MDB2_Schema_Tool_ParameterException( 'Data must come from a source file' ); } if ($typeDest != 'dsn') { throw new MDB2_Schema_Tool_ParameterException( 'A schema can only be loaded into a database, not a file' ); } $schemaDest = MDB2_Schema::factory($dsnDest, $this->getSchemaOptions()); $this->throwExceptionOnError($schemaDest, 'connecting to destination database'); $definition = $schemaDest->getDefinitionFromDatabase(); $this->throwExceptionOnError($definition, 'loading definition from database'); $op = $schemaDest->writeInitialization($dsnSource, $definition); $this->throwExceptionOnError($op, 'initializing database'); }//protected function doInit($args) }//class MDB2_Schema_Tool ?> MDB2_Schema-0.8.5/MDB2/Schema/Validate.php100644 765 765 105603 11150346546 13064 * Author: Igor Feghali * * @category Database * @package MDB2_Schema * @author Christian Dickmann * @author Igor Feghali * @license BSD http://www.opensource.org/licenses/bsd-license.php * @version CVS: $Id: Validate.php,v 1.42 2008/11/30 03:34:00 clockwerx Exp $ * @link http://pear.php.net/packages/MDB2_Schema */ /** * Validates an XML schema file * * @category Database * @package MDB2_Schema * @author Igor Feghali * @license BSD http://www.opensource.org/licenses/bsd-license.php * @link http://pear.php.net/packages/MDB2_Schema */ class MDB2_Schema_Validate { // {{{ properties var $fail_on_invalid_names = true; var $valid_types = array(); var $force_defaults = true; // }}} // {{{ constructor function __construct($fail_on_invalid_names = true, $valid_types = array(), $force_defaults = true) { if (empty($GLOBALS['_MDB2_Schema_Reserved'])) { $GLOBALS['_MDB2_Schema_Reserved'] = array(); } if (is_array($fail_on_invalid_names)) { $this->fail_on_invalid_names = array_intersect($fail_on_invalid_names, array_keys($GLOBALS['_MDB2_Schema_Reserved'])); } elseif ($fail_on_invalid_names === true) { $this->fail_on_invalid_names = array_keys($GLOBALS['_MDB2_Schema_Reserved']); } else { $this->fail_on_invalid_names = array(); } $this->valid_types = $valid_types; $this->force_defaults = $force_defaults; } function MDB2_Schema_Validate($fail_on_invalid_names = true, $valid_types = array(), $force_defaults = true) { $this->__construct($fail_on_invalid_names, $valid_types, $force_defaults); } // }}} // {{{ raiseError() function &raiseError($ecode, $msg = null) { $error =& MDB2_Schema::raiseError($ecode, null, null, $msg); return $error; } // }}} // {{{ isBoolean() /** * Verifies if a given value can be considered boolean. If yes, set value * to true or false according to its actual contents and return true. If * not, keep its contents untouched and return false. * * @param mixed &$value value to be checked * * @return bool * * @access public * @static */ function isBoolean(&$value) { if (is_bool($value)) { return true; } if ($value === 0 || $value === 1 || $value === '') { $value = (bool)$value; return true; } if (!is_string($value)) { return false; } switch ($value) { case '0': case 'N': case 'n': case 'no': case 'false': $value = false; break; case '1': case 'Y': case 'y': case 'yes': case 'true': $value = true; break; default: return false; } return true; } // }}} // {{{ validateTable() /* Definition */ /** * Checks whether the definition of a parsed table is valid. Modify table * definition when necessary. * * @param array $tables multi dimensional array that contains the * tables of current database. * @param array &$table multi dimensional array that contains the * structure and optional data of the table. * @param string $table_name name of the parsed table * * @return bool|error object * * @access public */ function validateTable($tables, &$table, $table_name) { /* Have we got a name? */ if (!$table_name) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'a table has to have a name'); } /* Table name duplicated? */ if (is_array($tables) && isset($tables[$table_name])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'table "'.$table_name.'" already exists'); } /* Table name reserved? */ if (is_array($this->fail_on_invalid_names)) { $name = strtoupper($table_name); foreach ($this->fail_on_invalid_names as $rdbms) { if (in_array($name, $GLOBALS['_MDB2_Schema_Reserved'][$rdbms])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'table name "'.$table_name.'" is a reserved word in: '.$rdbms); } } } /* Was */ if (empty($table['was'])) { $table['was'] = $table_name; } /* Have we got fields? */ if (empty($table['fields']) || !is_array($table['fields'])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'tables need one or more fields'); } /* Autoincrement */ $autoinc = $primary = false; foreach ($table['fields'] as $field_name => $field) { if (!empty($field['autoincrement'])) { if ($autoinc) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'there was already an autoincrement field in "'.$table_name.'" before "'.$field_name.'"'); } $autoinc = $field_name; } } /* * Checking Indexes * this have to be done here otherwise we can't * guarantee that all table fields were already * defined in the moment we are parsing indexes */ if (!empty($table['indexes']) && is_array($table['indexes'])) { foreach ($table['indexes'] as $name => $index) { $skip_index = false; if (!empty($index['primary'])) { /* * Lets see if we should skip this index since there is * already an auto increment on this field this implying * a primary key index. */ if (count($index['fields']) == '1' && $autoinc && array_key_exists($autoinc, $index['fields'])) { $skip_index = true; } elseif ($autoinc || $primary) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'there was already an primary index or autoincrement field in "'.$table_name.'" before "'.$name.'"'); } else { $primary = true; } } if (!$skip_index && is_array($index['fields'])) { foreach ($index['fields'] as $field_name => $field) { if (!isset($table['fields'][$field_name])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'index field "'.$field_name.'" does not exist'); } if (!empty($index['primary']) && !$table['fields'][$field_name]['notnull'] ) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'all primary key fields must be defined notnull in "'.$table_name.'"'); } } } else { unset($table['indexes'][$name]); } } } return MDB2_OK; } // }}} // {{{ validateField() /** * Checks whether the definition of a parsed field is valid. Modify field * definition when necessary. * * @param array $fields multi dimensional array that contains the * fields of current table. * @param array &$field multi dimensional array that contains the * structure of the parsed field. * @param string $field_name name of the parsed field * * @return bool|error object * * @access public */ function validateField($fields, &$field, $field_name) { /* Have we got a name? */ if (!$field_name) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'field name missing'); } /* Field name duplicated? */ if (is_array($fields) && isset($fields[$field_name])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'field "'.$field_name.'" already exists'); } /* Field name reserverd? */ if (is_array($this->fail_on_invalid_names)) { $name = strtoupper($field_name); foreach ($this->fail_on_invalid_names as $rdbms) { if (in_array($name, $GLOBALS['_MDB2_Schema_Reserved'][$rdbms])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'field name "'.$field_name.'" is a reserved word in: '.$rdbms); } } } /* Type check */ if (empty($field['type'])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'no field type specified'); } if (!empty($this->valid_types) && !array_key_exists($field['type'], $this->valid_types)) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'no valid field type ("'.$field['type'].'") specified'); } /* Unsigned */ if (array_key_exists('unsigned', $field) && !$this->isBoolean($field['unsigned'])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'unsigned has to be a boolean value'); } /* Fixed */ if (array_key_exists('fixed', $field) && !$this->isBoolean($field['fixed'])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'fixed has to be a boolean value'); } /* Length */ if (array_key_exists('length', $field) && $field['length'] <= 0) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'length has to be an integer greater 0'); } // if it's a DECIMAL datatype, check if a 'scale' value is provided: // 8,4 should be translated to DECIMAL(8,4) if (is_float($this->valid_types[$field['type']]) && !empty($field['length']) && strpos($field['length'], ',') !== false ) { list($field['length'], $field['scale']) = explode(',', $field['length']); } /* Was */ if (empty($field['was'])) { $field['was'] = $field_name; } /* Notnull */ if (empty($field['notnull'])) { $field['notnull'] = false; } if (!$this->isBoolean($field['notnull'])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'field "notnull" has to be a boolean value'); } /* Default */ if ($this->force_defaults && !array_key_exists('default', $field) && $field['type'] != 'clob' && $field['type'] != 'blob' ) { $field['default'] = $this->valid_types[$field['type']]; } if (array_key_exists('default', $field)) { if ($field['type'] == 'clob' || $field['type'] == 'blob') { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, '"'.$field['type'].'"-fields are not allowed to have a default value'); } if ($field['default'] === '' && !$field['notnull']) { $field['default'] = null; } } if (isset($field['default']) && PEAR::isError($result = $this->validateDataFieldValue($field, $field['default'], $field_name)) ) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'default value of "'.$field_name.'" is incorrect: '.$result->getUserinfo()); } /* Autoincrement */ if (!empty($field['autoincrement'])) { if (!$field['notnull']) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'all autoincrement fields must be defined notnull'); } if (empty($field['default'])) { $field['default'] = '0'; } elseif ($field['default'] !== '0' && $field['default'] !== 0) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'all autoincrement fields must be defined default "0"'); } } return MDB2_OK; } // }}} // {{{ validateIndex() /** * Checks whether a parsed index is valid. Modify index definition when * necessary. * * @param array $table_indexes multi dimensional array that contains the * indexes of current table. * @param array &$index multi dimensional array that contains the * structure of the parsed index. * @param string $index_name name of the parsed index * * @return bool|error object * * @access public */ function validateIndex($table_indexes, &$index, $index_name) { if (!$index_name) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'an index has to have a name'); } if (is_array($table_indexes) && isset($table_indexes[$index_name])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'index "'.$index_name.'" already exists'); } if (array_key_exists('unique', $index) && !$this->isBoolean($index['unique'])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'field "unique" has to be a boolean value'); } if (array_key_exists('primary', $index) && !$this->isBoolean($index['primary'])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'field "primary" has to be a boolean value'); } /* Have we got fields? */ if (empty($index['fields']) || !is_array($index['fields'])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'indexes need one or more fields'); } if (empty($index['was'])) { $index['was'] = $index_name; } return MDB2_OK; } // }}} // {{{ validateIndexField() /** * Checks whether a parsed index-field is valid. Modify its definition when * necessary. * * @param array $index_fields multi dimensional array that contains the * fields of current index. * @param array &$field multi dimensional array that contains the * structure of the parsed index-field. * @param string $field_name name of the parsed index-field * * @return bool|error object * * @access public */ function validateIndexField($index_fields, &$field, $field_name) { if (is_array($index_fields) && isset($index_fields[$field_name])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'index field "'.$field_name.'" already exists'); } if (!$field_name) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'the index-field-name is required'); } if (empty($field['sorting'])) { $field['sorting'] = 'ascending'; } elseif ($field['sorting'] !== 'ascending' && $field['sorting'] !== 'descending') { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'sorting type unknown'); } return MDB2_OK; } // }}} // {{{ validateConstraint() /** * Checks whether a parsed foreign key is valid. Modify its definition when * necessary. * * @param array $table_constraints multi dimensional array that contains the * constraints of current table. * @param array &$constraint multi dimensional array that contains the * structure of the parsed foreign key. * @param string $constraint_name name of the parsed foreign key * * @return bool|error object * * @access public */ function validateConstraint($table_constraints, &$constraint, $constraint_name) { if (!$constraint_name) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'a foreign key has to have a name'); } if (is_array($table_constraints) && isset($table_constraints[$constraint_name])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'foreign key "'.$constraint_name.'" already exists'); } /* Have we got fields? */ if (empty($constraint['fields']) || !is_array($constraint['fields'])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'foreign key "'.$constraint_name.'" need one or more fields'); } /* Have we got referenced fields? */ if (empty($constraint['references']) || !is_array($constraint['references'])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'foreign key "'.$constraint_name.'" need to reference one or more fields'); } /* Have we got referenced table? */ if (empty($constraint['references']['table'])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'foreign key "'.$constraint_name.'" need to reference a table'); } if (empty($constraint['was'])) { $constraint['was'] = $constraint_name; } return MDB2_OK; } // }}} // {{{ validateConstraintField() /** * Checks whether a foreign-field is valid. * * @param array $constraint_fields multi dimensional array that contains the * fields of current foreign key. * @param string $field_name name of the parsed foreign-field * * @return bool|error object * * @access public */ function validateConstraintField($constraint_fields, $field_name) { if (!$field_name) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'empty value for foreign-field'); } if (is_array($constraint_fields) && isset($constraint_fields[$field_name])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'foreign field "'.$field_name.'" already exists'); } return MDB2_OK; } // }}} // {{{ validateConstraintReferencedField() /** * Checks whether a foreign-referenced field is valid. * * @param array $referenced_fields multi dimensional array that contains the * fields of current foreign key. * @param string $field_name name of the parsed foreign-field * * @return bool|error object * * @access public */ function validateConstraintReferencedField($referenced_fields, $field_name) { if (!$field_name) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'empty value for referenced foreign-field'); } if (is_array($referenced_fields) && isset($referenced_fields[$field_name])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'foreign field "'.$field_name.'" already referenced'); } return MDB2_OK; } // }}} // {{{ validateSequence() /** * Checks whether the definition of a parsed sequence is valid. Modify * sequence definition when necessary. * * @param array $sequences multi dimensional array that contains the * sequences of current database. * @param array &$sequence multi dimensional array that contains the * structure of the parsed sequence. * @param string $sequence_name name of the parsed sequence * * @return bool|error object * * @access public */ function validateSequence($sequences, &$sequence, $sequence_name) { if (!$sequence_name) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'a sequence has to have a name'); } if (is_array($sequences) && isset($sequences[$sequence_name])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'sequence "'.$sequence_name.'" already exists'); } if (is_array($this->fail_on_invalid_names)) { $name = strtoupper($sequence_name); foreach ($this->fail_on_invalid_names as $rdbms) { if (in_array($name, $GLOBALS['_MDB2_Schema_Reserved'][$rdbms])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'sequence name "'.$sequence_name.'" is a reserved word in: '.$rdbms); } } } if (empty($sequence['was'])) { $sequence['was'] = $sequence_name; } if (!empty($sequence['on']) && (empty($sequence['on']['table']) || empty($sequence['on']['field'])) ) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'sequence "'.$sequence_name.'" on a table was not properly defined'); } return MDB2_OK; } // }}} // {{{ validateDatabase() /** * Checks whether a parsed database is valid. Modify its structure and * data when necessary. * * @param array &$database multi dimensional array that contains the * structure and optional data of the database. * * @return bool|error object * * @access public */ function validateDatabase(&$database) { /* Have we got a name? */ if (!is_array($database) || !isset($database['name']) || !$database['name']) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'a database has to have a name'); } /* Database name reserved? */ if (is_array($this->fail_on_invalid_names)) { $name = strtoupper($database['name']); foreach ($this->fail_on_invalid_names as $rdbms) { if (in_array($name, $GLOBALS['_MDB2_Schema_Reserved'][$rdbms])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'database name "'.$database['name'].'" is a reserved word in: '.$rdbms); } } } /* Create */ if (isset($database['create']) && !$this->isBoolean($database['create']) ) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'field "create" has to be a boolean value'); } /* Overwrite */ if (isset($database['overwrite']) && $database['overwrite'] !== '' && !$this->isBoolean($database['overwrite']) ) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'field "overwrite" has to be a boolean value'); } /* * This have to be done here otherwise we can't guarantee that all * tables were already defined in the moment we are parsing constraints */ if (isset($database['tables'])) { foreach ($database['tables'] as $table_name => $table) { if (!empty($table['constraints'])) { foreach ($table['constraints'] as $constraint_name => $constraint) { $referenced_table_name = $constraint['references']['table']; if (!isset($database['tables'][$referenced_table_name])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'referenced table "'.$referenced_table_name.'" of foreign key "'.$constraint_name.'" of table "'.$table_name.'" does not exist'); } if (empty($constraint['references']['fields'])) { $referenced_table = $database['tables'][$referenced_table_name]; $primary = false; if (!empty($referenced_table['indexes'])) { foreach ($referenced_table['indexes'] as $index_name => $index) { if (array_key_exists('primary', $index) && $index['primary'] ) { $primary = array(); foreach ($index['fields'] as $field_name => $field) { $primary[$field_name] = ''; } break; } } } if (!$primary) { foreach ($referenced_table['fields'] as $field_name => $field) { if (array_key_exists('autoincrement', $field) && $field['autoincrement'] ) { $primary = array( $field_name => '' ); break; } } } if (!$primary) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'referenced table "'.$referenced_table_name.'" has no primary key and no referenced field was specified for foreign key "'.$constraint_name.'" of table "'.$table_name.'"'); } $constraint['references']['fields'] = $primary; } /* the same number of referencing and referenced fields ? */ if (count($constraint['fields']) != count($constraint['references']['fields'])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'The number of fields in the referenced key must match those of the foreign key "'.$constraint_name.'"'); } $database['tables'][$table_name]['constraints'][$constraint_name]['references']['fields'] = $constraint['references']['fields']; } } } } /* * This have to be done here otherwise we can't guarantee that all * tables were already defined in the moment we are parsing sequences */ if (isset($database['sequences'])) { foreach ($database['sequences'] as $seq_name => $seq) { if (!empty($seq['on']) && empty($database['tables'][$seq['on']['table']]['fields'][$seq['on']['field']]) ) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'sequence "'.$seq_name.'" was assigned on unexisting field/table'); } } } return MDB2_OK; } // }}} // {{{ validateDataField() /* Data Manipulation */ /** * Checks whether a parsed DML-field is valid. Modify its structure when * necessary. This is called when validating INSERT and * UPDATE. * * @param array $table_fields multi dimensional array that contains the * definition for current table's fields. * @param array $instruction_fields multi dimensional array that contains the * parsed fields of the current DML instruction. * @param string &$field array that contains the parsed instruction field * * @return bool|error object * * @access public */ function validateDataField($table_fields, $instruction_fields, &$field) { if (!$field['name']) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'field-name has to be specified'); } if (is_array($instruction_fields) && isset($instruction_fields[$field['name']])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'field "'.$field['name'].'" already initialized'); } if (is_array($table_fields) && !isset($table_fields[$field['name']])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, '"'.$field['name'].'" is not defined'); } if (!isset($field['group']['type'])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, '"'.$field['name'].'" has no initial value'); } if (isset($field['group']['data']) && $field['group']['type'] == 'value' && $field['group']['data'] !== '' && PEAR::isError($result = $this->validateDataFieldValue($table_fields[$field['name']], $field['group']['data'], $field['name'])) ) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, 'value of "'.$field['name'].'" is incorrect: '.$result->getUserinfo()); } return MDB2_OK; } // }}} // {{{ validateDataFieldValue() /** * Checks whether a given value is compatible with a table field. This is * done when parsing a field for a INSERT or UPDATE instruction. * * @param array $field_def multi dimensional array that contains the * definition for current table's fields. * @param string &$field_value value to fill the parsed field * @param string $field_name name of the parsed field * * @return bool|error object * * @access public * @see MDB2_Schema_Validate::validateInsertField() */ function validateDataFieldValue($field_def, &$field_value, $field_name) { switch ($field_def['type']) { case 'text': case 'clob': if (!empty($field_def['length']) && strlen($field_value) > $field_def['length']) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, '"'.$field_value.'" is larger than "'.$field_def['length'].'"'); } break; case 'blob': $field_value = pack('H*', $field_value); if (!empty($field_def['length']) && strlen($field_value) > $field_def['length']) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, '"'.$field_value.'" is larger than "'.$field_def['type'].'"'); } break; case 'integer': if ($field_value != ((int)$field_value)) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, '"'.$field_value.'" is not of type "'.$field_def['type'].'"'); } //$field_value = (int)$field_value; if (!empty($field_def['unsigned']) && $field_def['unsigned'] && $field_value < 0) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, '"'.$field_value.'" signed instead of unsigned'); } break; case 'boolean': if (!$this->isBoolean($field_value)) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, '"'.$field_value.'" is not of type "'.$field_def['type'].'"'); } break; case 'date': if (!preg_match('/([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})/', $field_value) && $field_value !== 'CURRENT_DATE' ) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, '"'.$field_value.'" is not of type "'.$field_def['type'].'"'); } break; case 'timestamp': if (!preg_match('/([0-9]{4})-([0-9]{1,2})-([0-9]{1,2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})/', $field_value) && strcasecmp($field_value, 'now()') != 0 && $field_value !== 'CURRENT_TIMESTAMP' ) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, '"'.$field_value.'" is not of type "'.$field_def['type'].'"'); } break; case 'time': if (!preg_match("/([0-9]{2}):([0-9]{2}):([0-9]{2})/", $field_value) && $field_value !== 'CURRENT_TIME' ) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, '"'.$field_value.'" is not of type "'.$field_def['type'].'"'); } break; case 'float': case 'double': if ($field_value != (double)$field_value) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, '"'.$field_value.'" is not of type "'.$field_def['type'].'"'); } //$field_value = (double)$field_value; break; } return MDB2_OK; } } ?> MDB2_Schema-0.8.5/MDB2/Schema/Writer.php100644 765 765 62306 11150346546 12571 * Author: Igor Feghali * * @category Database * @package MDB2_Schema * @author Lukas Smith * @author Igor Feghali * @license BSD http://www.opensource.org/licenses/bsd-license.php * @version CVS: $Id: Writer.php,v 1.40 2008/11/30 03:34:00 clockwerx Exp $ * @link http://pear.php.net/packages/MDB2_Schema */ /** * Writes an XML schema file * * @category Database * @package MDB2_Schema * @author Lukas Smith * @license BSD http://www.opensource.org/licenses/bsd-license.php * @link http://pear.php.net/packages/MDB2_Schema */ class MDB2_Schema_Writer { // {{{ properties var $valid_types = array(); // }}} // {{{ constructor function __construct($valid_types = array()) { $this->valid_types = $valid_types; } function MDB2_Schema_Writer($valid_types = array()) { $this->__construct($valid_types); } // }}} // {{{ raiseError() /** * This method is used to communicate an error and invoke error * callbacks etc. Basically a wrapper for PEAR::raiseError * without the message string. * * @param int|PEAR_Error $code integer error code or and PEAR_Error instance * @param int $mode error mode, see PEAR_Error docs * error level (E_USER_NOTICE etc). If error mode is * PEAR_ERROR_CALLBACK, this is the callback function, * either as a function name, or as an array of an * object and method name. For other error modes this * parameter is ignored. * @param string $options Extra debug information. Defaults to the last * query and native error code. * * @return object a PEAR error object * @access public * @see PEAR_Error */ function &raiseError($code = null, $mode = null, $options = null, $userinfo = null) { $error =& MDB2_Schema::raiseError($code, $mode, $options, $userinfo); return $error; } // }}} // {{{ _escapeSpecialChars() /** * add escapecharacters to all special characters in a string * * @param string $string string that should be escaped * * @return string escaped string * @access protected */ function _escapeSpecialChars($string) { if (!is_string($string)) { $string = strval($string); } $escaped = ''; for ($char = 0, $count = strlen($string); $char < $count; $char++) { switch ($string[$char]) { case '&': $escaped .= '&'; break; case '>': $escaped .= '>'; break; case '<': $escaped .= '<'; break; case '"': $escaped .= '"'; break; case '\'': $escaped .= '''; break; default: $code = ord($string[$char]); if ($code < 32 || $code > 127) { $escaped .= "&#$code;"; } else { $escaped .= $string[$char]; } break; } } return $escaped; } // }}} // {{{ _dumpBoolean() /** * dump the structure of a sequence * * @param string $boolean boolean value or variable definition * * @return string with xml boolea definition * @access private */ function _dumpBoolean($boolean) { if (is_string($boolean)) { if ($boolean !== 'true' || $boolean !== 'false' || preg_match('/.*/', $boolean) ) { return $boolean; } } return $boolean ? 'true' : 'false'; } // }}} // {{{ dumpSequence() /** * dump the structure of a sequence * * @param string $sequence_definition sequence definition * @param string $sequence_name sequence name * @param string $eol end of line characters * @param integer $dump determines what data to dump * MDB2_SCHEMA_DUMP_ALL : the entire db * MDB2_SCHEMA_DUMP_STRUCTURE : only the structure of the db * MDB2_SCHEMA_DUMP_CONTENT : only the content of the db * * @return mixed string xml sequence definition on success, or a error object * @access public */ function dumpSequence($sequence_definition, $sequence_name, $eol, $dump = MDB2_SCHEMA_DUMP_ALL) { $buffer = "$eol $eol $sequence_name$eol"; if ($dump == MDB2_SCHEMA_DUMP_ALL || $dump == MDB2_SCHEMA_DUMP_CONTENT) { if (!empty($sequence_definition['start'])) { $start = $sequence_definition['start']; $buffer .= " $start$eol"; } } if (!empty($sequence_definition['on'])) { $buffer .= " $eol"; $buffer .= " ".$sequence_definition['on']['table']; $buffer .= "
$eol ".$sequence_definition['on']['field']; $buffer .= "$eol
$eol"; } $buffer .= "
$eol"; return $buffer; } // }}} // {{{ dumpDatabase() /** * Dump a previously parsed database structure in the Metabase schema * XML based format suitable for the Metabase parser. This function * may optionally dump the database definition with initialization * commands that specify the data that is currently present in the tables. * * @param array $database_definition unknown * @param array $arguments associative array that takes pairs of tag * names and values that define dump options. * array ( * 'output_mode' => String * 'file' : dump into a file * default: dump using a function * 'output' => String * depending on the 'Output_Mode' * name of the file * name of the function * 'end_of_line' => String * end of line delimiter that should be used * default: "\n" * ); * @param integer $dump determines what data to dump * MDB2_SCHEMA_DUMP_ALL : the entire db * MDB2_SCHEMA_DUMP_STRUCTURE : only the structure of the db * MDB2_SCHEMA_DUMP_CONTENT : only the content of the db * * @return mixed MDB2_OK on success, or a error object * @access public */ function dumpDatabase($database_definition, $arguments, $dump = MDB2_SCHEMA_DUMP_ALL) { if (!empty($arguments['output'])) { if (!empty($arguments['output_mode']) && $arguments['output_mode'] == 'file') { $fp = fopen($arguments['output'], 'w'); if ($fp === false) { return $this->raiseError(MDB2_SCHEMA_ERROR_WRITER, null, null, 'it was not possible to open output file'); } $output = false; } elseif (is_callable($arguments['output'])) { $output = $arguments['output']; } else { return $this->raiseError(MDB2_SCHEMA_ERROR_WRITER, null, null, 'no valid output function specified'); } } else { return $this->raiseError(MDB2_SCHEMA_ERROR_WRITER, null, null, 'no output method specified'); } $eol = isset($arguments['end_of_line']) ? $arguments['end_of_line'] : "\n"; $sequences = array(); if (!empty($database_definition['sequences']) && is_array($database_definition['sequences']) ) { foreach ($database_definition['sequences'] as $sequence_name => $sequence) { $table = !empty($sequence['on']) ? $sequence['on']['table'] :''; $sequences[$table][] = $sequence_name; } } $buffer = ''.$eol; $buffer .= "$eol$eol ".$database_definition['name'].""; $buffer .= "$eol ".$this->_dumpBoolean($database_definition['create']).""; $buffer .= "$eol ".$this->_dumpBoolean($database_definition['overwrite'])."$eol"; $buffer .= "$eol ".$database_definition['charset']."$eol"; if ($output) { call_user_func($output, $buffer); } else { fwrite($fp, $buffer); } if (!empty($database_definition['tables']) && is_array($database_definition['tables'])) { foreach ($database_definition['tables'] as $table_name => $table) { $buffer = "$eol $eol$eol $table_name$eol"; if ($dump == MDB2_SCHEMA_DUMP_ALL || $dump == MDB2_SCHEMA_DUMP_STRUCTURE) { $buffer .= "$eol $eol"; if (!empty($table['fields']) && is_array($table['fields'])) { foreach ($table['fields'] as $field_name => $field) { if (empty($field['type'])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, null, null, 'it was not specified the type of the field "'. $field_name.'" of the table "'.$table_name.'"'); } if (!empty($this->valid_types) && !array_key_exists($field['type'], $this->valid_types)) { return $this->raiseError(MDB2_SCHEMA_ERROR_UNSUPPORTED, null, null, 'type "'.$field['type'].'" is not yet supported'); } $buffer .= "$eol $eol $field_name$eol "; $buffer .= $field['type']."$eol"; if (!empty($field['fixed']) && $field['type'] === 'text') { $buffer .= " ".$this->_dumpBoolean($field['fixed'])."$eol"; } if (array_key_exists('default', $field) && $field['type'] !== 'clob' && $field['type'] !== 'blob' ) { $buffer .= ' '.$this->_escapeSpecialChars($field['default'])."$eol"; } if (!empty($field['notnull'])) { $buffer .= " ".$this->_dumpBoolean($field['notnull'])."$eol"; } else { $buffer .= " false$eol"; } if (!empty($field['autoincrement'])) { $buffer .= " " . $field['autoincrement'] ."$eol"; } if (!empty($field['unsigned'])) { $buffer .= " ".$this->_dumpBoolean($field['unsigned'])."$eol"; } if (!empty($field['length'])) { $buffer .= ' '.$field['length']."$eol"; } $buffer .= " $eol"; } } if (!empty($table['indexes']) && is_array($table['indexes'])) { foreach ($table['indexes'] as $index_name => $index) { if (strtolower($index_name) === 'primary') { $index_name = $table_name . '_pKey'; } $buffer .= "$eol $eol $index_name$eol"; if (!empty($index['unique'])) { $buffer .= " ".$this->_dumpBoolean($index['unique'])."$eol"; } if (!empty($index['primary'])) { $buffer .= " ".$this->_dumpBoolean($index['primary'])."$eol"; } foreach ($index['fields'] as $field_name => $field) { $buffer .= " $eol $field_name$eol"; if (!empty($field) && is_array($field)) { $buffer .= ' '.$field['sorting']."$eol"; } $buffer .= " $eol"; } $buffer .= " $eol"; } } if (!empty($table['constraints']) && is_array($table['constraints'])) { foreach ($table['constraints'] as $constraint_name => $constraint) { $buffer .= "$eol $eol $constraint_name$eol"; if (empty($constraint['fields']) || !is_array($constraint['fields'])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, null, null, 'it was not specified a field for the foreign key "'. $constraint_name.'" of the table "'.$table_name.'"'); } if (!is_array($constraint['references']) || empty($constraint['references']['table'])) { return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE, null, null, 'it was not specified the referenced table of the foreign key "'. $constraint_name.'" of the table "'.$table_name.'"'); } if (!empty($constraint['match'])) { $buffer .= " ".$constraint['match']."$eol"; } if (!empty($constraint['ondelete'])) { $buffer .= " ".$constraint['ondelete']."$eol"; } if (!empty($constraint['onupdate'])) { $buffer .= " ".$constraint['onupdate']."$eol"; } if (!empty($constraint['deferrable'])) { $buffer .= " ".$constraint['deferrable']."$eol"; } if (!empty($constraint['initiallydeferred'])) { $buffer .= " ".$constraint['initiallydeferred']."$eol"; } foreach ($constraint['fields'] as $field_name => $field) { $buffer .= " $field_name$eol"; } $buffer .= " $eol
".$constraint['references']['table']."
$eol"; foreach ($constraint['references']['fields'] as $field_name => $field) { $buffer .= " $field_name$eol"; } $buffer .= " $eol"; $buffer .= " $eol"; } } $buffer .= "$eol $eol"; } if ($output) { call_user_func($output, $buffer); } else { fwrite($fp, $buffer); } $buffer = ''; if ($dump == MDB2_SCHEMA_DUMP_ALL || $dump == MDB2_SCHEMA_DUMP_CONTENT) { if (!empty($table['initialization']) && is_array($table['initialization'])) { $buffer = "$eol $eol"; foreach ($table['initialization'] as $instruction) { switch ($instruction['type']) { case 'insert': $buffer .= "$eol $eol"; foreach ($instruction['data']['field'] as $field) { $field_name = $field['name']; $buffer .= "$eol $eol $field_name$eol"; $buffer .= $this->writeExpression($field['group'], 5, $arguments); $buffer .= " $eol"; } $buffer .= "$eol $eol"; break; case 'update': $buffer .= "$eol $eol"; foreach ($instruction['data']['field'] as $field) { $field_name = $field['name']; $buffer .= "$eol $eol $field_name$eol"; $buffer .= $this->writeExpression($field['group'], 5, $arguments); $buffer .= " $eol"; } if (!empty($instruction['data']['where']) && is_array($instruction['data']['where']) ) { $buffer .= " $eol"; $buffer .= $this->writeExpression($instruction['data']['where'], 5, $arguments); $buffer .= " $eol"; } $buffer .= "$eol $eol"; break; case 'delete': $buffer .= "$eol $eol$eol"; if (!empty($instruction['data']['where']) && is_array($instruction['data']['where']) ) { $buffer .= " $eol"; $buffer .= $this->writeExpression($instruction['data']['where'], 5, $arguments); $buffer .= " $eol"; } $buffer .= "$eol $eol"; break; } } $buffer .= "$eol $eol"; } } $buffer .= "$eol $eol"; if ($output) { call_user_func($output, $buffer); } else { fwrite($fp, $buffer); } if (isset($sequences[$table_name])) { foreach ($sequences[$table_name] as $sequence) { $result = $this->dumpSequence($database_definition['sequences'][$sequence], $sequence, $eol, $dump); if (PEAR::isError($result)) { return $result; } if ($output) { call_user_func($output, $result); } else { fwrite($fp, $result); } } } } } if (isset($sequences[''])) { foreach ($sequences[''] as $sequence) { $result = $this->dumpSequence($database_definition['sequences'][$sequence], $sequence, $eol, $dump); if (PEAR::isError($result)) { return $result; } if ($output) { call_user_func($output, $result); } else { fwrite($fp, $result); } } } $buffer = "$eol
$eol"; if ($output) { call_user_func($output, $buffer); } else { fwrite($fp, $buffer); fclose($fp); } return MDB2_OK; } // }}} // {{{ writeExpression() /** * Dumps the structure of an element. Elements can be value, column, * function or expression. * * @param array $element multi dimensional array that represents the parsed element * of a DML instruction. * @param integer $offset base indentation width * @param array $arguments associative array that takes pairs of tag * names and values that define dump options. * * @return string * * @access public * @see MDB2_Schema_Writer::dumpDatabase() */ function writeExpression($element, $offset = 0, $arguments = null) { $eol = isset($arguments['end_of_line']) ? $arguments['end_of_line'] : "\n"; $str = ''; $indent = str_repeat(' ', $offset); $noffset = $offset + 1; switch ($element['type']) { case 'value': $str .= "$indent".$this->_escapeSpecialChars($element['data'])."$eol"; break; case 'column': $str .= "$indent".$this->_escapeSpecialChars($element['data'])."$eol"; break; case 'function': $str .= "$indent$eol$indent ".$this->_escapeSpecialChars($element['data']['name'])."$eol"; if (!empty($element['data']['arguments']) && is_array($element['data']['arguments']) ) { foreach ($element['data']['arguments'] as $v) { $str .= $this->writeExpression($v, $noffset, $arguments); } } $str .= "$indent$eol"; break; case 'expression': $str .= "$indent$eol"; $str .= $this->writeExpression($element['data']['operants'][0], $noffset, $arguments); $str .= "$indent ".$element['data']['operator']."$eol"; $str .= $this->writeExpression($element['data']['operants'][1], $noffset, $arguments); $str .= "$indent$eol"; break; } return $str; } // }}} } ?> MDB2_Schema-0.8.5/MDB2/Schema.php100644 765 765 336225 11150346546 11341 * Author: Igor Feghali * * @category Database * @package MDB2_Schema * @author Lukas Smith * @author Igor Feghali * @license BSD http://www.opensource.org/licenses/bsd-license.php * @version CVS: $Id: Schema.php,v 1.132 2009/02/22 21:43:22 ifeghali Exp $ * @link http://pear.php.net/packages/MDB2_Schema */ require_once 'MDB2.php'; define('MDB2_SCHEMA_DUMP_ALL', 0); define('MDB2_SCHEMA_DUMP_STRUCTURE', 1); define('MDB2_SCHEMA_DUMP_CONTENT', 2); /** * If you add an error code here, make sure you also add a textual * version of it in MDB2_Schema::errorMessage(). */ define('MDB2_SCHEMA_ERROR', -1); define('MDB2_SCHEMA_ERROR_PARSE', -2); define('MDB2_SCHEMA_ERROR_VALIDATE', -3); define('MDB2_SCHEMA_ERROR_UNSUPPORTED', -4); // Driver does not support this function define('MDB2_SCHEMA_ERROR_INVALID', -5); // Invalid attribute value define('MDB2_SCHEMA_ERROR_WRITER', -6); /** * The database manager is a class that provides a set of database * management services like installing, altering and dumping the data * structures of databases. * * @category Database * @package MDB2_Schema * @author Lukas Smith * @license BSD http://www.opensource.org/licenses/bsd-license.php * @link http://pear.php.net/packages/MDB2_Schema */ class MDB2_Schema extends PEAR { // {{{ properties var $db; var $warnings = array(); var $options = array( 'fail_on_invalid_names' => true, 'dtd_file' => false, 'valid_types' => array(), 'force_defaults' => true, 'parser' => 'MDB2_Schema_Parser', 'writer' => 'MDB2_Schema_Writer', 'validate' => 'MDB2_Schema_Validate', 'drop_missing_tables' => false ); // }}} // {{{ apiVersion() /** * Return the MDB2 API version * * @return string the MDB2 API version number * @access public */ function apiVersion() { return '0.4.3'; } // }}} // {{{ arrayMergeClobber() /** * Clobbers two arrays together * * @param array $a1 array that should be clobbered * @param array $a2 array that should be clobbered * * @return array|false array on success and false on error * * @access public * @author kc@hireability.com */ function arrayMergeClobber($a1, $a2) { if (!is_array($a1) || !is_array($a2)) { return false; } foreach ($a2 as $key => $val) { if (is_array($val) && array_key_exists($key, $a1) && is_array($a1[$key])) { $a1[$key] = MDB2_Schema::arrayMergeClobber($a1[$key], $val); } else { $a1[$key] = $val; } } return $a1; } // }}} // {{{ resetWarnings() /** * reset the warning array * * @access public * @return void */ function resetWarnings() { $this->warnings = array(); } // }}} // {{{ getWarnings() /** * Get all warnings in reverse order * * This means that the last warning is the first element in the array * * @return array with warnings * @access public * @see resetWarnings() */ function getWarnings() { return array_reverse($this->warnings); } // }}} // {{{ setOption() /** * Sets the option for the db class * * @param string $option option name * @param mixed $value value for the option * * @return bool|MDB2_Error MDB2_OK or error object * @access public */ function setOption($option, $value) { if (isset($this->options[$option])) { if (is_null($value)) { return $this->raiseError(MDB2_SCHEMA_ERROR, null, null, 'may not set an option to value null'); } $this->options[$option] = $value; return MDB2_OK; } return $this->raiseError(MDB2_SCHEMA_ERROR_UNSUPPORTED, null, null, "unknown option $option"); } // }}} // {{{ getOption() /** * returns the value of an option * * @param string $option option name * * @return mixed the option value or error object * @access public */ function getOption($option) { if (isset($this->options[$option])) { return $this->options[$option]; } return $this->raiseError(MDB2_SCHEMA_ERROR_UNSUPPORTED, null, null, "unknown option $option"); } // }}} // {{{ factory() /** * Create a new MDB2 object for the specified database type * type * * @param string|array|MDB2_Driver_Common &$db 'data source name', see the * MDB2::parseDSN method for a description of the dsn format. * Can also be specified as an array of the * format returned by @see MDB2::parseDSN. * Finally you can also pass an existing db object to be used. * @param array $options An associative array of option names and their values. * * @return bool|MDB2_Error MDB2_OK or error object * @access public * @see MDB2::parseDSN */ function &factory(&$db, $options = array()) { $obj =& new MDB2_Schema(); $result = $obj->connect($db, $options); if (PEAR::isError($result)) { return $result; } return $obj; } // }}} // {{{ connect() /** * Create a new MDB2 connection object and connect to the specified * database * * @param string|array|MDB2_Driver_Common &$db 'data source name', see the * MDB2::parseDSN method for a description of the dsn format. * Can also be specified as an array of the * format returned by MDB2::parseDSN. * Finally you can also pass an existing db object to be used. * @param array $options An associative array of option names and their values. * * @return bool|MDB2_Error MDB2_OK or error object * @access public * @see MDB2::parseDSN */ function connect(&$db, $options = array()) { $db_options = array(); if (is_array($options)) { foreach ($options as $option => $value) { if (array_key_exists($option, $this->options)) { $result = $this->setOption($option, $value); if (PEAR::isError($result)) { return $result; } } else { $db_options[$option] = $value; } } } $this->disconnect(); if (!MDB2::isConnection($db)) { $db =& MDB2::factory($db, $db_options); } if (PEAR::isError($db)) { return $db; } $this->db =& $db; $this->db->loadModule('Datatype'); $this->db->loadModule('Manager'); $this->db->loadModule('Reverse'); $this->db->loadModule('Function'); if (empty($this->options['valid_types'])) { $this->options['valid_types'] = $this->db->datatype->getValidTypes(); } return MDB2_OK; } // }}} // {{{ disconnect() /** * Log out and disconnect from the database. * * @access public * @return void */ function disconnect() { if (MDB2::isConnection($this->db)) { $this->db->disconnect(); unset($this->db); } } // }}} // {{{ parseDatabaseDefinition() /** * Parse a database definition from a file or an array * * @param string|array $schema the database schema array or file name * @param bool $skip_unreadable if non readable files should be skipped * @param array $variables associative array that the defines the text string values * that are meant to be used to replace the variables that are * used in the schema description. * @param bool $fail_on_invalid_names make function fail on invalid names * @param array $structure database structure definition * * @access public * @return array */ function parseDatabaseDefinition($schema, $skip_unreadable = false, $variables = array(), $fail_on_invalid_names = true, $structure = false) { $database_definition = false; if (is_string($schema)) { // if $schema is not readable then we just skip it // and simply copy the $current_schema file to that file name if (is_readable($schema)) { $database_definition = $this->parseDatabaseDefinitionFile($schema, $variables, $fail_on_invalid_names, $structure); } } elseif (is_array($schema)) { $database_definition = $schema; } if (!$database_definition && !$skip_unreadable) { $database_definition = $this->raiseError(MDB2_SCHEMA_ERROR, null, null, 'invalid data type of schema or unreadable data source'); } return $database_definition; } // }}} // {{{ parseDatabaseDefinitionFile() /** * Parse a database definition file by creating a schema format * parser object and passing the file contents as parser input data stream. * * @param string $input_file the database schema file. * @param array $variables associative array that the defines the text string values * that are meant to be used to replace the variables that are * used in the schema description. * @param bool $fail_on_invalid_names make function fail on invalid names * @param array $structure database structure definition * * @access public * @return array */ function parseDatabaseDefinitionFile($input_file, $variables = array(), $fail_on_invalid_names = true, $structure = false) { $dtd_file = $this->options['dtd_file']; if ($dtd_file) { include_once 'XML/DTD/XmlValidator.php'; $dtd =& new XML_DTD_XmlValidator; if (!$dtd->isValid($dtd_file, $input_file)) { return $this->raiseError(MDB2_SCHEMA_ERROR_PARSE, null, null, $dtd->getMessage()); } } $class_name = $this->options['parser']; $result = MDB2::loadClass($class_name, $this->db->getOption('debug')); if (PEAR::isError($result)) { return $result; } $parser =& new $class_name($variables, $fail_on_invalid_names, $structure, $this->options['valid_types'], $this->options['force_defaults']); $result = $parser->setInputFile($input_file); if (PEAR::isError($result)) { return $result; } $result = $parser->parse(); if (PEAR::isError($result)) { return $result; } if (PEAR::isError($parser->error)) { return $parser->error; } return $parser->database_definition; } // }}} // {{{ getDefinitionFromDatabase() /** * Attempt to reverse engineer a schema structure from an existing MDB2 * This method can be used if no xml schema file exists yet. * The resulting xml schema file may need some manual adjustments. * * @return array|MDB2_Error array with definition or error object * @access public */ function getDefinitionFromDatabase() { $database = $this->db->database_name; if (empty($database)) { return $this->raiseError(MDB2_SCHEMA_ERROR_INVALID, null, null, 'it was not specified a valid database name'); } $class_name = $this->options['validate']; $result = MDB2::loadClass($class_name, $this->db->getOption('debug')); if (PEAR::isError($result)) { return $result; } $val =& new $class_name($this->options['fail_on_invalid_names'], $this->options['valid_types'], $this->options['force_defaults']); $database_definition = array( 'name' => $database, 'create' => true, 'overwrite' => false, 'charset' => 'utf8', 'description' => '', 'comments' => '', 'tables' => array(), 'sequences' => array(), ); $tables = $this->db->manager->listTables(); if (PEAR::isError($tables)) { return $tables; } foreach ($tables as $table_name) { $fields = $this->db->manager->listTableFields($table_name); if (PEAR::isError($fields)) { return $fields; } $database_definition['tables'][$table_name] = array( 'was' => '', 'description' => '', 'comments' => '', 'fields' => array(), 'indexes' => array(), 'constraints' => array(), 'initialization' => array() ); $table_definition =& $database_definition['tables'][$table_name]; foreach ($fields as $field_name) { $definition = $this->db->reverse->getTableFieldDefinition($table_name, $field_name); if (PEAR::isError($definition)) { return $definition; } if (!empty($definition[0]['autoincrement'])) { $definition[0]['default'] = '0'; } $table_definition['fields'][$field_name] = $definition[0]; $field_choices = count($definition); if ($field_choices > 1) { $warning = "There are $field_choices type choices in the table $table_name field $field_name (#1 is the default): "; $field_choice_cnt = 1; $table_definition['fields'][$field_name]['choices'] = array(); foreach ($definition as $field_choice) { $table_definition['fields'][$field_name]['choices'][] = $field_choice; $warning .= 'choice #'.($field_choice_cnt).': '.serialize($field_choice); $field_choice_cnt++; } $this->warnings[] = $warning; } /** * The first parameter is used to verify if there are duplicated * fields which we can guarantee that won't happen when reverse engineering */ $result = $val->validateField(array(), $table_definition['fields'][$field_name], $field_name); if (PEAR::isError($result)) { return $result; } } $keys = array(); $indexes = $this->db->manager->listTableIndexes($table_name); if (PEAR::isError($indexes)) { return $indexes; } if (is_array($indexes)) { foreach ($indexes as $index_name) { $this->db->expectError(MDB2_ERROR_NOT_FOUND); $definition = $this->db->reverse->getTableIndexDefinition($table_name, $index_name); $this->db->popExpect(); if (PEAR::isError($definition)) { if (PEAR::isError($definition, MDB2_ERROR_NOT_FOUND)) { continue; } return $definition; } $keys[$index_name] = $definition; } } $constraints = $this->db->manager->listTableConstraints($table_name); if (PEAR::isError($constraints)) { return $constraints; } if (is_array($constraints)) { foreach ($constraints as $constraint_name) { $this->db->expectError(MDB2_ERROR_NOT_FOUND); $definition = $this->db->reverse->getTableConstraintDefinition($table_name, $constraint_name); $this->db->popExpect(); if (PEAR::isError($definition)) { if (PEAR::isError($definition, MDB2_ERROR_NOT_FOUND)) { continue; } return $definition; } $keys[$constraint_name] = $definition; } } foreach ($keys as $key_name => $definition) { if (array_key_exists('foreign', $definition) && $definition['foreign'] ) { /** * The first parameter is used to verify if there are duplicated * foreign keys which we can guarantee that won't happen when reverse engineering */ $result = $val->validateConstraint(array(), $definition, $key_name); if (PEAR::isError($result)) { return $result; } foreach ($definition['fields'] as $field_name => $field) { /** * The first parameter is used to verify if there are duplicated * referencing fields which we can guarantee that won't happen when reverse engineering */ $result = $val->validateConstraintField(array(), $field_name); if (PEAR::isError($result)) { return $result; } $definition['fields'][$field_name] = ''; } foreach ($definition['references']['fields'] as $field_name => $field) { /** * The first parameter is used to verify if there are duplicated * referenced fields which we can guarantee that won't happen when reverse engineering */ $result = $val->validateConstraintReferencedField(array(), $field_name); if (PEAR::isError($result)) { return $result; } $definition['references']['fields'][$field_name] = ''; } $table_definition['constraints'][$key_name] = $definition; } else { /** * The first parameter is used to verify if there are duplicated * indices which we can guarantee that won't happen when reverse engineering */ $result = $val->validateIndex(array(), $definition, $key_name); if (PEAR::isError($result)) { return $result; } foreach ($definition['fields'] as $field_name => $field) { /** * The first parameter is used to verify if there are duplicated * index fields which we can guarantee that won't happen when reverse engineering */ $result = $val->validateIndexField(array(), $field, $field_name); if (PEAR::isError($result)) { return $result; } $definition['fields'][$field_name] = $field; } $table_definition['indexes'][$key_name] = $definition; } } /** * The first parameter is used to verify if there are duplicated * tables which we can guarantee that won't happen when reverse engineering */ $result = $val->validateTable(array(), $table_definition, $table_name); if (PEAR::isError($result)) { return $result; } } $sequences = $this->db->manager->listSequences(); if (PEAR::isError($sequences)) { return $sequences; } if (is_array($sequences)) { foreach ($sequences as $sequence_name) { $definition = $this->db->reverse->getSequenceDefinition($sequence_name); if (PEAR::isError($definition)) { return $definition; } if (isset($database_definition['tables'][$sequence_name]) && isset($database_definition['tables'][$sequence_name]['indexes']) ) { foreach ($database_definition['tables'][$sequence_name]['indexes'] as $index) { if (isset($index['primary']) && $index['primary'] && count($index['fields'] == 1) ) { $definition['on'] = array( 'table' => $sequence_name, 'field' => key($index['fields']), ); break; } } } /** * The first parameter is used to verify if there are duplicated * sequences which we can guarantee that won't happen when reverse engineering */ $result = $val->validateSequence(array(), $definition, $sequence_name); if (PEAR::isError($result)) { return $result; } $database_definition['sequences'][$sequence_name] = $definition; } } $result = $val->validateDatabase($database_definition); if (PEAR::isError($result)) { return $result; } return $database_definition; } // }}} // {{{ createTableIndexes() /** * A method to create indexes for an existing table * * @param string $table_name Name of the table * @param array $indexes An array of indexes to be created * @param boolean $overwrite If the table/index should be overwritten if it already exists * * @return mixed MDB2_Error if there is an error creating an index, MDB2_OK otherwise * @access public */ function createTableIndexes($table_name, $indexes, $overwrite = false) { if (!$this->db->supports('indexes')) { $this->db->debug('Indexes are not supported', __FUNCTION__); return MDB2_OK; } $errorcodes = array(MDB2_ERROR_UNSUPPORTED, MDB2_ERROR_NOT_CAPABLE); foreach ($indexes as $index_name => $index) { // Does the index already exist, and if so, should it be overwritten? $create_index = true; $this->db->expectError($errorcodes); if (!empty($index['primary']) || !empty($index['unique'])) { $current_indexes = $this->db->manager->listTableConstraints($table_name); } else { $current_indexes = $this->db->manager->listTableIndexes($table_name); } $this->db->popExpect(); if (PEAR::isError($current_indexes)) { if (!MDB2::isError($current_indexes, $errorcodes)) { return $current_indexes; } } elseif (is_array($current_indexes) && in_array($index_name, $current_indexes)) { if (!$overwrite) { $this->db->debug('Index already exists: '.$index_name, __FUNCTION__); $create_index = false; } else { $this->db->debug('Preparing to overwrite index: '.$index_name, __FUNCTION__); $this->db->expectError(MDB2_ERROR_NOT_FOUND); if (!empty($index['primary']) || !empty($index['unique'])) { $result = $this->db->manager->dropConstraint($table_name, $index_name); } else { $result = $this->db->manager->dropIndex($table_name, $index_name); } $this->db->popExpect(); if (PEAR::isError($result) && !MDB2::isError($result, MDB2_ERROR_NOT_FOUND)) { return $result; } } } // Check if primary is being used and if it's supported if (!empty($index['primary']) && !$this->db->supports('primary_key')) { // Primary not supported so we fallback to UNIQUE and making the field NOT NULL $index['unique'] = true; $changes = array(); foreach ($index['fields'] as $field => $empty) { $field_info = $this->db->reverse->getTableFieldDefinition($table_name, $field); if (PEAR::isError($field_info)) { return $field_info; } if (!$field_info[0]['notnull']) { $changes['change'][$field] = $field_info[0]; $changes['change'][$field]['notnull'] = true; } } if (!empty($changes)) { $this->db->manager->alterTable($table_name, $changes, false); } } // Should the index be created? if ($create_index) { if (!empty($index['primary']) || !empty($index['unique'])) { $result = $this->db->manager->createConstraint($table_name, $index_name, $index); } else { $result = $this->db->manager->createIndex($table_name, $index_name, $index); } if (PEAR::isError($result)) { return $result; } } } return MDB2_OK; } // }}} // {{{ createTableConstraints() /** * A method to create foreign keys for an existing table * * @param string $table_name Name of the table * @param array $constraints An array of foreign keys to be created * @param boolean $overwrite If the foreign key should be overwritten if it already exists * * @return mixed MDB2_Error if there is an error creating a foreign key, MDB2_OK otherwise * @access public */ function createTableConstraints($table_name, $constraints, $overwrite = false) { if (!$this->db->supports('indexes')) { $this->db->debug('Indexes are not supported', __FUNCTION__); return MDB2_OK; } $errorcodes = array(MDB2_ERROR_UNSUPPORTED, MDB2_ERROR_NOT_CAPABLE); foreach ($constraints as $constraint_name => $constraint) { // Does the foreign key already exist, and if so, should it be overwritten? $create_constraint = true; $this->db->expectError($errorcodes); $current_constraints = $this->db->manager->listTableConstraints($table_name); $this->db->popExpect(); if (PEAR::isError($current_constraints)) { if (!MDB2::isError($current_constraints, $errorcodes)) { return $current_constraints; } } elseif (is_array($current_constraints) && in_array($constraint_name, $current_constraints)) { if (!$overwrite) { $this->db->debug('Foreign key already exists: '.$constraint_name, __FUNCTION__); $create_constraint = false; } else { $this->db->debug('Preparing to overwrite foreign key: '.$constraint_name, __FUNCTION__); $result = $this->db->manager->dropConstraint($table_name, $constraint_name); if (PEAR::isError($result)) { return $result; } } } // Should the foreign key be created? if ($create_constraint) { $result = $this->db->manager->createConstraint($table_name, $constraint_name, $constraint); if (PEAR::isError($result)) { return $result; } } } return MDB2_OK; } // }}} // {{{ createTable() /** * Create a table and inititialize the table if data is available * * @param string $table_name name of the table to be created * @param array $table multi dimensional array that contains the * structure and optional data of the table * @param bool $overwrite if the table/index should be overwritten if it already exists * @param array $options an array of options to be passed to the database specific driver * version of MDB2_Driver_Manager_Common::createTable(). * * @return bool|MDB2_Error MDB2_OK or error object * @access public */ function createTable($table_name, $table, $overwrite = false, $options = array()) { $create = true; $errorcodes = array(MDB2_ERROR_UNSUPPORTED, MDB2_ERROR_NOT_CAPABLE); $this->db->expectError($errorcodes); $tables = $this->db->manager->listTables(); $this->db->popExpect(); if (PEAR::isError($tables)) { if (!MDB2::isError($tables, $errorcodes)) { return $tables; } } elseif (is_array($tables) && in_array($table_name, $tables)) { if (!$overwrite) { $create = false; $this->db->debug('Table already exists: '.$table_name, __FUNCTION__); } else { $result = $this->db->manager->dropTable($table_name); if (PEAR::isError($result)) { return $result; } $this->db->debug('Overwritting table: '.$table_name, __FUNCTION__); } } if ($create) { $result = $this->db->manager->createTable($table_name, $table['fields'], $options); if (PEAR::isError($result)) { return $result; } } if (!empty($table['initialization']) && is_array($table['initialization'])) { $result = $this->initializeTable($table_name, $table); if (PEAR::isError($result)) { return $result; } } if (!empty($table['indexes']) && is_array($table['indexes'])) { $result = $this->createTableIndexes($table_name, $table['indexes'], $overwrite); if (PEAR::isError($result)) { return $result; } } if (!empty($table['constraints']) && is_array($table['constraints'])) { $result = $this->createTableConstraints($table_name, $table['constraints'], $overwrite); if (PEAR::isError($result)) { return $result; } } return MDB2_OK; } // }}} // {{{ initializeTable() /** * Inititialize the table with data * * @param string $table_name name of the table * @param array $table multi dimensional array that contains the * structure and optional data of the table * * @return bool|MDB2_Error MDB2_OK or error object * @access public */ function initializeTable($table_name, $table) { $query_insertselect = 'INSERT INTO %s (%s) (SELECT %s FROM %s %s)'; $query_insert = 'INSERT INTO %s (%s) VALUES (%s)'; $query_update = 'UPDATE %s SET %s %s'; $query_delete = 'DELETE FROM %s %s'; $table_name = $this->db->quoteIdentifier($table_name, true); $result = MDB2_OK; $support_transactions = $this->db->supports('transactions'); foreach ($table['initialization'] as $instruction) { $query = ''; switch ($instruction['type']) { case 'insert': if (!isset($instruction['data']['select'])) { $data = $this->getInstructionFields($instruction['data'], $table['fields']); if (!empty($data)) { $fields = implode(', ', array_keys($data)); $values = implode(', ', array_values($data)); $query = sprintf($query_insert, $table_name, $fields, $values); } } else { $data = $this->getInstructionFields($instruction['data']['select'], $table['fields']); $where = $this->getInstructionWhere($instruction['data']['select'], $table['fields']); $select_table_name = $this->db->quoteIdentifier($instruction['data']['select']['table'], true); if (!empty($data)) { $fields = implode(', ', array_keys($data)); $values = implode(', ', array_values($data)); $query = sprintf($query_insertselect, $table_name, $fields, $values, $select_table_name, $where); } } break; case 'update': $data = $this->getInstructionFields($instruction['data'], $table['fields']); $where = $this->getInstructionWhere($instruction['data'], $table['fields']); if (!empty($data)) { array_walk($data, array($this, 'buildFieldValue')); $fields_values = implode(', ', $data); $query = sprintf($query_update, $table_name, $fields_values, $where); } break; case 'delete': $where = $this->getInstructionWhere($instruction['data'], $table['fields']); $query = sprintf($query_delete, $table_name, $where); break; } if ($query) { if ($support_transactions && PEAR::isError($res = $this->db->beginNestedTransaction())) { return $res; } $result = $this->db->exec($query); if (PEAR::isError($result)) { return $result; } if ($support_transactions && PEAR::isError($res = $this->db->completeNestedTransaction())) { return $res; } } } return $result; } // }}} // {{{ buildFieldValue() /** * Appends the contents of second argument + '=' to the beginning of first * argument. * * Used with array_walk() in initializeTable() for UPDATEs. * * @param string &$element value of array's element * @param string $key key of array's element * * @return void * * @access public * @see MDB2_Schema::initializeTable() */ function buildFieldValue(&$element, $key) { $element = $key."=$element"; } // }}} // {{{ getExpression() /** * Generates a string that represents a value that would be associated * with a column in a DML instruction. * * @param array $element multi dimensional array that contains the * structure of the current DML instruction. * @param array $fields_definition multi dimensional array that contains the * definition for current table's fields * @param string $type type of given field * * @return string * * @access public * @see MDB2_Schema::getInstructionFields(), MDB2_Schema::getInstructionWhere() */ function getExpression($element, $fields_definition = array(), $type = null) { $str = ''; switch ($element['type']) { case 'null': $str .= 'NULL'; break; case 'value': $str .= $this->db->quote($element['data'], $type); break; case 'column': $str .= $this->db->quoteIdentifier($element['data'], true); break; case 'function': $arguments = array(); if (!empty($element['data']['arguments']) && is_array($element['data']['arguments']) ) { foreach ($element['data']['arguments'] as $v) { $arguments[] = $this->getExpression($v, $fields_definition); } } if (method_exists($this->db->function, $element['data']['name'])) { $user_func = array(&$this->db->function, $element['data']['name']); $str .= call_user_func_array($user_func, $arguments); } else { $str .= $element['data']['name'].'('; $str .= implode(', ', $arguments); $str .= ')'; } break; case 'expression': $type0 = $type1 = null; if ($element['data']['operants'][0]['type'] == 'column' && array_key_exists($element['data']['operants'][0]['data'], $fields_definition) ) { $type0 = $fields_definition[$element['data']['operants'][0]['data']]['type']; } if ($element['data']['operants'][1]['type'] == 'column' && array_key_exists($element['data']['operants'][1]['data'], $fields_definition) ) { $type1 = $fields_definition[$element['data']['operants'][1]['data']]['type']; } $str .= '('; $str .= $this->getExpression($element['data']['operants'][0], $fields_definition, $type1); $str .= $this->getOperator($element['data']['operator']); $str .= $this->getExpression($element['data']['operants'][1], $fields_definition, $type0); $str .= ')'; break; } return $str; } // }}} // {{{ getOperator() /** * Returns the matching SQL operator * * @param string $op parsed descriptive operator * * @return string matching SQL operator * * @access public * @static * @see MDB2_Schema::getExpression() */ function getOperator($op) { switch ($op) { case 'PLUS': return ' + '; case 'MINUS': return ' - '; case 'TIMES': return ' * '; case 'DIVIDED': return ' / '; case 'EQUAL': return ' = '; case 'NOT EQUAL': return ' != '; case 'LESS THAN': return ' < '; case 'GREATER THAN': return ' > '; case 'LESS THAN OR EQUAL': return ' <= '; case 'GREATER THAN OR EQUAL': return ' >= '; default: return ' '.$op.' '; } } // }}} // {{{ getInstructionFields() /** * Walks the parsed DML instruction array, field by field, * storing them and their processed values inside a new array. * * @param array $instruction multi dimensional array that contains the * structure of the current DML instruction. * @param array $fields_definition multi dimensional array that contains the * definition for current table's fields * * @return array array of strings in the form 'field_name' => 'value' * * @access public * @static * @see MDB2_Schema::initializeTable() */ function getInstructionFields($instruction, $fields_definition = array()) { $fields = array(); if (!empty($instruction['field']) && is_array($instruction['field'])) { foreach ($instruction['field'] as $field) { $field_name = $this->db->quoteIdentifier($field['name'], true); $fields[$field_name] = $this->getExpression($field['group'], $fields_definition); } } return $fields; } // }}} // {{{ getInstructionWhere() /** * Translates the parsed WHERE expression of a DML instruction * (array structure) to a SQL WHERE clause (string). * * @param array $instruction multi dimensional array that contains the * structure of the current DML instruction. * @param array $fields_definition multi dimensional array that contains the * definition for current table's fields. * * @return string SQL WHERE clause * * @access public * @static * @see MDB2_Schema::initializeTable() */ function getInstructionWhere($instruction, $fields_definition = array()) { $where = ''; if (!empty($instruction['where'])) { $where = 'WHERE '.$this->getExpression($instruction['where'], $fields_definition); } return $where; } // }}} // {{{ createSequence() /** * Create a sequence * * @param string $sequence_name name of the sequence to be created * @param array $sequence multi dimensional array that contains the * structure and optional data of the table * @param bool $overwrite if the sequence should be overwritten if it already exists * * @return bool|MDB2_Error MDB2_OK or error object * @access public */ function createSequence($sequence_name, $sequence, $overwrite = false) { if (!$this->db->supports('sequences')) { $this->db->debug('Sequences are not supported', __FUNCTION__); return MDB2_OK; } $errorcodes = array(MDB2_ERROR_UNSUPPORTED, MDB2_ERROR_NOT_CAPABLE); $this->db->expectError($errorcodes); $sequences = $this->db->manager->listSequences(); $this->db->popExpect(); if (PEAR::isError($sequences)) { if (!MDB2::isError($sequences, $errorcodes)) { return $sequences; } } elseif (is_array($sequence) && in_array($sequence_name, $sequences)) { if (!$overwrite) { $this->db->debug('Sequence already exists: '.$sequence_name, __FUNCTION__); return MDB2_OK; } $result = $this->db->manager->dropSequence($sequence_name); if (PEAR::isError($result)) { return $result; } $this->db->debug('Overwritting sequence: '.$sequence_name, __FUNCTION__); } $start = 1; $field = ''; if (!empty($sequence['on'])) { $table = $sequence['on']['table']; $field = $sequence['on']['field']; $errorcodes = array(MDB2_ERROR_UNSUPPORTED, MDB2_ERROR_NOT_CAPABLE); $this->db->expectError($errorcodes); $tables = $this->db->manager->listTables(); $this->db->popExpect(); if (PEAR::isError($tables) && !MDB2::isError($tables, $errorcodes)) { return $tables; } if (!PEAR::isError($tables) && is_array($tables) && in_array($table, $tables)) { if ($this->db->supports('summary_functions')) { $query = "SELECT MAX($field) FROM ".$this->db->quoteIdentifier($table, true); } else { $query = "SELECT $field FROM ".$this->db->quoteIdentifier($table, true)." ORDER BY $field DESC"; } $start = $this->db->queryOne($query, 'integer'); if (PEAR::isError($start)) { return $start; } ++$start; } else { $this->warnings[] = 'Could not sync sequence: '.$sequence_name; } } elseif (!empty($sequence['start']) && is_numeric($sequence['start'])) { $start = $sequence['start']; $table = ''; } $result = $this->db->manager->createSequence($sequence_name, $start); if (PEAR::isError($result)) { return $result; } return MDB2_OK; } // }}} // {{{ createDatabase() /** * Create a database space within which may be created database objects * like tables, indexes and sequences. The implementation of this function * is highly DBMS specific and may require special permissions to run * successfully. Consult the documentation or the DBMS drivers that you * use to be aware of eventual configuration requirements. * * @param array $database_definition multi dimensional array that contains the current definition * @param array $options an array of options to be passed to the * database specific driver version of * MDB2_Driver_Manager_Common::createTable(). * * @return bool|MDB2_Error MDB2_OK or error object * @access public */ function createDatabase($database_definition, $options = array()) { if (!isset($database_definition['name']) || !$database_definition['name']) { return $this->raiseError(MDB2_SCHEMA_ERROR_INVALID, null, null, 'no valid database name specified'); } $create = (isset($database_definition['create']) && $database_definition['create']); $overwrite = (isset($database_definition['overwrite']) && $database_definition['overwrite']); /** * * We need to clean up database name before any query to prevent * database driver from using a inexistent database * */ $previous_database_name = $this->db->setDatabase(''); // Lower / Upper case the db name if the portability deems so. if ($this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { $func = $this->db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'; $db_name = $func($database_definition['name']); } else { $db_name = $database_definition['name']; } if ($create) { $dbExists = $this->db->databaseExists($db_name); if (PEAR::isError($dbExists)) { return $dbExists; } if ($dbExists && $overwrite) { $this->db->expectError(MDB2_ERROR_CANNOT_DROP); $result = $this->db->manager->dropDatabase($db_name); $this->db->popExpect(); if (PEAR::isError($result) && !MDB2::isError($result, MDB2_ERROR_CANNOT_DROP)) { return $result; } $dbExists = false; $this->db->debug('Overwritting database: ' . $db_name, __FUNCTION__); } $dbOptions = array(); if (array_key_exists('charset', $database_definition) && !empty($database_definition['charset'])) { $dbOptions['charset'] = $database_definition['charset']; } if ($dbExists) { $this->db->debug('Database already exists: ' . $db_name, __FUNCTION__); if (!empty($dbOptions)) { $errorcodes = array(MDB2_ERROR_UNSUPPORTED, MDB2_ERROR_NO_PERMISSION); $this->db->expectError($errorcodes); $result = $this->db->manager->alterDatabase($db_name, $dbOptions); $this->db->popExpect(); if (PEAR::isError($result) && !MDB2::isError($result, $errorcodes)) { return $result; } } $create = false; } else { $this->db->expectError(MDB2_ERROR_UNSUPPORTED); $result = $this->db->manager->createDatabase($db_name, $dbOptions); $this->db->popExpect(); if (PEAR::isError($result) && !MDB2::isError($result, MDB2_ERROR_UNSUPPORTED)) { return $result; } $this->db->debug('Creating database: ' . $db_name, __FUNCTION__); } } $this->db->setDatabase($db_name); if (($support_transactions = $this->db->supports('transactions')) && PEAR::isError($result = $this->db->beginNestedTransaction()) ) { return $result; } $created_objects = 0; if (isset($database_definition['tables']) && is_array($database_definition['tables']) ) { foreach ($database_definition['tables'] as $table_name => $table) { $result = $this->createTable($table_name, $table, $overwrite, $options); if (PEAR::isError($result)) { break; } $created_objects++; } } if (!PEAR::isError($result) && isset($database_definition['sequences']) && is_array($database_definition['sequences']) ) { foreach ($database_definition['sequences'] as $sequence_name => $sequence) { $result = $this->createSequence($sequence_name, $sequence, false, $overwrite); if (PEAR::isError($result)) { break; } $created_objects++; } } if ($support_transactions) { $res = $this->db->completeNestedTransaction(); if (PEAR::isError($res)) { $result = $this->raiseError(MDB2_SCHEMA_ERROR, null, null, 'Could not end transaction ('. $res->getMessage().' ('.$res->getUserinfo().'))'); } } elseif (PEAR::isError($result) && $created_objects) { $result = $this->raiseError(MDB2_SCHEMA_ERROR, null, null, 'the database was only partially created ('. $result->getMessage().' ('.$result->getUserinfo().'))'); } $this->db->setDatabase($previous_database_name); if (PEAR::isError($result) && $create && PEAR::isError($result2 = $this->db->manager->dropDatabase($db_name)) ) { if (!MDB2::isError($result2, MDB2_ERROR_UNSUPPORTED)) { return $this->raiseError(MDB2_SCHEMA_ERROR, null, null, 'Could not drop the created database after unsuccessful creation attempt ('. $result2->getMessage().' ('.$result2->getUserinfo().'))'); } } return $result; } // }}} // {{{ compareDefinitions() /** * Compare a previous definition with the currently parsed definition * * @param array $current_definition multi dimensional array that contains the current definition * @param array $previous_definition multi dimensional array that contains the previous definition * * @return array|MDB2_Error array of changes on success, or a error object * @access public */ function compareDefinitions($current_definition, $previous_definition) { $changes = array(); if (!empty($current_definition['tables']) && is_array($current_definition['tables'])) { $changes['tables'] = $defined_tables = array(); foreach ($current_definition['tables'] as $table_name => $table) { $previous_tables = array(); if (!empty($previous_definition) && is_array($previous_definition)) { $previous_tables = $previous_definition['tables']; } $change = $this->compareTableDefinitions($table_name, $table, $previous_tables, $defined_tables); if (PEAR::isError($change)) { return $change; } if (!empty($change)) { $changes['tables'] = MDB2_Schema::arrayMergeClobber($changes['tables'], $change); } } if (!empty($previous_definition['tables']) && is_array($previous_definition['tables'])) { foreach ($previous_definition['tables'] as $table_name => $table) { if (empty($defined_tables[$table_name])) { $changes['tables']['remove'][$table_name] = true; } } } } if (!empty($current_definition['sequences']) && is_array($current_definition['sequences'])) { $changes['sequences'] = $defined_sequences = array(); foreach ($current_definition['sequences'] as $sequence_name => $sequence) { $previous_sequences = array(); if (!empty($previous_definition) && is_array($previous_definition)) { $previous_sequences = $previous_definition['sequences']; } $change = $this->compareSequenceDefinitions($sequence_name, $sequence, $previous_sequences, $defined_sequences); if (PEAR::isError($change)) { return $change; } if (!empty($change)) { $changes['sequences'] = MDB2_Schema::arrayMergeClobber($changes['sequences'], $change); } } if (!empty($previous_definition['sequences']) && is_array($previous_definition['sequences'])) { foreach ($previous_definition['sequences'] as $sequence_name => $sequence) { if (empty($defined_sequences[$sequence_name])) { $changes['sequences']['remove'][$sequence_name] = true; } } } } return $changes; } // }}} // {{{ compareTableFieldsDefinitions() /** * Compare a previous definition with the currently parsed definition * * @param string $table_name name of the table * @param array $current_definition multi dimensional array that contains the current definition * @param array $previous_definition multi dimensional array that contains the previous definition * * @return array|MDB2_Error array of changes on success, or a error object * @access public */ function compareTableFieldsDefinitions($table_name, $current_definition, $previous_definition) { $changes = $defined_fields = array(); if (is_array($current_definition)) { foreach ($current_definition as $field_name => $field) { $was_field_name = $field['was']; if (!empty($previous_definition[$field_name]) && ( (isset($previous_definition[$field_name]['was']) && $previous_definition[$field_name]['was'] == $was_field_name) || !isset($previous_definition[$was_field_name]) )) { $was_field_name = $field_name; } if (!empty($previous_definition[$was_field_name])) { if ($was_field_name != $field_name) { $changes['rename'][$was_field_name] = array('name' => $field_name, 'definition' => $field); } if (!empty($defined_fields[$was_field_name])) { return $this->raiseError(MDB2_SCHEMA_ERROR_INVALID, null, null, 'the field "'.$was_field_name. '" was specified for more than one field of table'); } $defined_fields[$was_field_name] = true; $change = $this->db->compareDefinition($field, $previous_definition[$was_field_name]); if (PEAR::isError($change)) { return $change; } if (!empty($change)) { if (array_key_exists('default', $change) && $change['default'] && !array_key_exists('default', $field)) { $field['default'] = null; } $change['definition'] = $field; $changes['change'][$field_name] = $change; } } else { if ($field_name != $was_field_name) { return $this->raiseError(MDB2_SCHEMA_ERROR_INVALID, null, null, 'it was specified a previous field name ("'. $was_field_name.'") for field "'.$field_name.'" of table "'. $table_name.'" that does not exist'); } $changes['add'][$field_name] = $field; } } } if (isset($previous_definition) && is_array($previous_definition)) { foreach ($previous_definition as $field_previous_name => $field_previous) { if (empty($defined_fields[$field_previous_name])) { $changes['remove'][$field_previous_name] = true; } } } return $changes; } // }}} // {{{ compareTableIndexesDefinitions() /** * Compare a previous definition with the currently parsed definition * * @param string $table_name name of the table * @param array $current_definition multi dimensional array that contains the current definition * @param array $previous_definition multi dimensional array that contains the previous definition * * @return array|MDB2_Error array of changes on success, or a error object * @access public */ function compareTableIndexesDefinitions($table_name, $current_definition, $previous_definition) { $changes = $defined_indexes = array(); if (is_array($current_definition)) { foreach ($current_definition as $index_name => $index) { $was_index_name = $index['was']; if (!empty($previous_definition[$index_name]) && isset($previous_definition[$index_name]['was']) && $previous_definition[$index_name]['was'] == $was_index_name ) { $was_index_name = $index_name; } if (!empty($previous_definition[$was_index_name])) { $change = array(); if ($was_index_name != $index_name) { $change['name'] = $was_index_name; } if (!empty($defined_indexes[$was_index_name])) { return $this->raiseError(MDB2_SCHEMA_ERROR_INVALID, null, null, 'the index "'.$was_index_name.'" was specified for'. ' more than one index of table "'.$table_name.'"'); } $defined_indexes[$was_index_name] = true; $previous_unique = array_key_exists('unique', $previous_definition[$was_index_name]) ? $previous_definition[$was_index_name]['unique'] : false; $unique = array_key_exists('unique', $index) ? $index['unique'] : false; if ($previous_unique != $unique) { $change['unique'] = $unique; } $previous_primary = array_key_exists('primary', $previous_definition[$was_index_name]) ? $previous_definition[$was_index_name]['primary'] : false; $primary = array_key_exists('primary', $index) ? $index['primary'] : false; if ($previous_primary != $primary) { $change['primary'] = $primary; } $defined_fields = array(); $previous_fields = $previous_definition[$was_index_name]['fields']; if (!empty($index['fields']) && is_array($index['fields'])) { foreach ($index['fields'] as $field_name => $field) { if (!empty($previous_fields[$field_name])) { $defined_fields[$field_name] = true; $previous_sorting = array_key_exists('sorting', $previous_fields[$field_name]) ? $previous_fields[$field_name]['sorting'] : ''; $sorting = array_key_exists('sorting', $field) ? $field['sorting'] : ''; if ($previous_sorting != $sorting) { $change['change'] = true; } } else { $change['change'] = true; } } } if (isset($previous_fields) && is_array($previous_fields)) { foreach ($previous_fields as $field_name => $field) { if (empty($defined_fields[$field_name])) { $change['change'] = true; } } } if (!empty($change)) { $changes['change'][$index_name] = $current_definition[$index_name]; } } else { if ($index_name != $was_index_name) { return $this->raiseError(MDB2_SCHEMA_ERROR_INVALID, null, null, 'it was specified a previous index name ("'.$was_index_name. ') for index "'.$index_name.'" of table "'.$table_name.'" that does not exist'); } $changes['add'][$index_name] = $current_definition[$index_name]; } } } foreach ($previous_definition as $index_previous_name => $index_previous) { if (empty($defined_indexes[$index_previous_name])) { $changes['remove'][$index_previous_name] = $index_previous; } } return $changes; } // }}} // {{{ compareTableDefinitions() /** * Compare a previous definition with the currently parsed definition * * @param string $table_name name of the table * @param array $current_definition multi dimensional array that contains the current definition * @param array $previous_definition multi dimensional array that contains the previous definition * @param array &$defined_tables table names in the schema * * @return array|MDB2_Error array of changes on success, or a error object * @access public */ function compareTableDefinitions($table_name, $current_definition, $previous_definition, &$defined_tables) { $changes = array(); if (is_array($current_definition)) { $was_table_name = $table_name; if (!empty($current_definition['was'])) { $was_table_name = $current_definition['was']; } if (!empty($previous_definition[$was_table_name])) { $changes['change'][$was_table_name] = array(); if ($was_table_name != $table_name) { $changes['change'][$was_table_name] = array('name' => $table_name); } if (!empty($defined_tables[$was_table_name])) { return $this->raiseError(MDB2_SCHEMA_ERROR_INVALID, null, null, 'the table "'.$was_table_name. '" was specified for more than one table of the database'); } $defined_tables[$was_table_name] = true; if (!empty($current_definition['fields']) && is_array($current_definition['fields'])) { $previous_fields = array(); if (isset($previous_definition[$was_table_name]['fields']) && is_array($previous_definition[$was_table_name]['fields'])) { $previous_fields = $previous_definition[$was_table_name]['fields']; } $change = $this->compareTableFieldsDefinitions($table_name, $current_definition['fields'], $previous_fields); if (PEAR::isError($change)) { return $change; } if (!empty($change)) { $changes['change'][$was_table_name] = MDB2_Schema::arrayMergeClobber($changes['change'][$was_table_name], $change); } } if (!empty($current_definition['indexes']) && is_array($current_definition['indexes'])) { $previous_indexes = array(); if (isset($previous_definition[$was_table_name]['indexes']) && is_array($previous_definition[$was_table_name]['indexes'])) { $previous_indexes = $previous_definition[$was_table_name]['indexes']; } $change = $this->compareTableIndexesDefinitions($table_name, $current_definition['indexes'], $previous_indexes); if (PEAR::isError($change)) { return $change; } if (!empty($change)) { $changes['change'][$was_table_name]['indexes'] = $change; } } if (empty($changes['change'][$was_table_name])) { unset($changes['change'][$was_table_name]); } if (empty($changes['change'])) { unset($changes['change']); } } else { if ($table_name != $was_table_name) { return $this->raiseError(MDB2_SCHEMA_ERROR_INVALID, null, null, 'it was specified a previous table name ("'.$was_table_name. '") for table "'.$table_name.'" that does not exist'); } $changes['add'][$table_name] = true; } } return $changes; } // }}} // {{{ compareSequenceDefinitions() /** * Compare a previous definition with the currently parsed definition * * @param string $sequence_name name of the sequence * @param array $current_definition multi dimensional array that contains the current definition * @param array $previous_definition multi dimensional array that contains the previous definition * @param array &$defined_sequences names in the schema * * @return array|MDB2_Error array of changes on success, or a error object * @access public */ function compareSequenceDefinitions($sequence_name, $current_definition, $previous_definition, &$defined_sequences) { $changes = array(); if (is_array($current_definition)) { $was_sequence_name = $sequence_name; if (!empty($previous_definition[$sequence_name]) && isset($previous_definition[$sequence_name]['was']) && $previous_definition[$sequence_name]['was'] == $was_sequence_name ) { $was_sequence_name = $sequence_name; } elseif (!empty($current_definition['was'])) { $was_sequence_name = $current_definition['was']; } if (!empty($previous_definition[$was_sequence_name])) { if ($was_sequence_name != $sequence_name) { $changes['change'][$was_sequence_name]['name'] = $sequence_name; } if (!empty($defined_sequences[$was_sequence_name])) { return $this->raiseError(MDB2_SCHEMA_ERROR_INVALID, null, null, 'the sequence "'.$was_sequence_name.'" was specified as base'. ' of more than of sequence of the database'); } $defined_sequences[$was_sequence_name] = true; $change = array(); if (!empty($current_definition['start']) && isset($previous_definition[$was_sequence_name]['start']) && $current_definition['start'] != $previous_definition[$was_sequence_name]['start'] ) { $change['start'] = $previous_definition[$sequence_name]['start']; } if (isset($current_definition['on']['table']) && isset($previous_definition[$was_sequence_name]['on']['table']) && $current_definition['on']['table'] != $previous_definition[$was_sequence_name]['on']['table'] && isset($current_definition['on']['field']) && isset($previous_definition[$was_sequence_name]['on']['field']) && $current_definition['on']['field'] != $previous_definition[$was_sequence_name]['on']['field'] ) { $change['on'] = $current_definition['on']; } if (!empty($change)) { $changes['change'][$was_sequence_name][$sequence_name] = $change; } } else { if ($sequence_name != $was_sequence_name) { return $this->raiseError(MDB2_SCHEMA_ERROR_INVALID, null, null, 'it was specified a previous sequence name ("'.$was_sequence_name. '") for sequence "'.$sequence_name.'" that does not exist'); } $changes['add'][$sequence_name] = true; } } return $changes; } // }}} // {{{ verifyAlterDatabase() /** * Verify that the changes requested are supported * * @param array $changes associative array that contains the definition of the changes * that are meant to be applied to the database structure. * * @return bool|MDB2_Error MDB2_OK or error object * @access public */ function verifyAlterDatabase($changes) { if (!empty($changes['tables']['change']) && is_array($changes['tables']['change'])) { foreach ($changes['tables']['change'] as $table_name => $table) { if (!empty($table['indexes']) && is_array($table['indexes'])) { if (!$this->db->supports('indexes')) { return $this->raiseError(MDB2_SCHEMA_ERROR_UNSUPPORTED, null, null, 'indexes are not supported'); } $table_changes = count($table['indexes']); if (!empty($table['indexes']['add'])) { $table_changes--; } if (!empty($table['indexes']['remove'])) { $table_changes--; } if (!empty($table['indexes']['change'])) { $table_changes--; } if ($table_changes) { return $this->raiseError(MDB2_SCHEMA_ERROR_UNSUPPORTED, null, null, 'index alteration not yet supported: '.implode(', ', array_keys($table['indexes']))); } } unset($table['indexes']); $result = $this->db->manager->alterTable($table_name, $table, true); if (PEAR::isError($result)) { return $result; } } } if (!empty($changes['sequences']) && is_array($changes['sequences'])) { if (!$this->db->supports('sequences')) { return $this->raiseError(MDB2_SCHEMA_ERROR_UNSUPPORTED, null, null, 'sequences are not supported'); } $sequence_changes = count($changes['sequences']); if (!empty($changes['sequences']['add'])) { $sequence_changes--; } if (!empty($changes['sequences']['remove'])) { $sequence_changes--; } if (!empty($changes['sequences']['change'])) { $sequence_changes--; } if ($sequence_changes) { return $this->raiseError(MDB2_SCHEMA_ERROR_UNSUPPORTED, null, null, 'sequence alteration not yet supported: '.implode(', ', array_keys($changes['sequences']))); } } return MDB2_OK; } // }}} // {{{ alterDatabaseIndexes() /** * Execute the necessary actions to implement the requested changes * in the indexes inside a database structure. * * @param string $table_name name of the table * @param array $changes associative array that contains the definition of the changes * that are meant to be applied to the database structure. * * @return bool|MDB2_Error MDB2_OK or error object * @access public */ function alterDatabaseIndexes($table_name, $changes) { $alterations = 0; if (empty($changes)) { return $alterations; } if (!empty($changes['remove']) && is_array($changes['remove'])) { foreach ($changes['remove'] as $index_name => $index) { $this->db->expectError(MDB2_ERROR_NOT_FOUND); if (!empty($index['primary']) || !empty($index['unique'])) { $result = $this->db->manager->dropConstraint($table_name, $index_name, !empty($index['primary'])); } else { $result = $this->db->manager->dropIndex($table_name, $index_name); } $this->db->popExpect(); if (PEAR::isError($result) && !MDB2::isError($result, MDB2_ERROR_NOT_FOUND)) { return $result; } $alterations++; } } if (!empty($changes['change']) && is_array($changes['change'])) { foreach ($changes['change'] as $index_name => $index) { /** * Drop existing index/constraint first. * Since $changes doesn't tell us whether it's an index or a constraint before the change, * we have to find out and call the appropriate method. */ if (in_array($index_name, $this->db->manager->listTableIndexes($table_name))) { $result = $this->db->manager->dropIndex($table_name, $index_name); } elseif (in_array($index_name, $this->db->manager->listTableConstraints($table_name))) { $result = $this->db->manager->dropConstraint($table_name, $index_name); } if (!empty($result) && PEAR::isError($result)) { return $result; } if (!empty($index['primary']) || !empty($index['unique'])) { $result = $this->db->manager->createConstraint($table_name, $index_name, $index); } else { $result = $this->db->manager->createIndex($table_name, $index_name, $index); } if (PEAR::isError($result)) { return $result; } $alterations++; } } if (!empty($changes['add']) && is_array($changes['add'])) { foreach ($changes['add'] as $index_name => $index) { if (!empty($index['primary']) || !empty($index['unique'])) { $result = $this->db->manager->createConstraint($table_name, $index_name, $index); } else { $result = $this->db->manager->createIndex($table_name, $index_name, $index); } if (PEAR::isError($result)) { return $result; } $alterations++; } } return $alterations; } // }}} // {{{ alterDatabaseTables() /** * Execute the necessary actions to implement the requested changes * in the tables inside a database structure. * * @param array $current_definition multi dimensional array that contains the current definition * @param array $previous_definition multi dimensional array that contains the previous definition * @param array $changes associative array that contains the definition of the changes * that are meant to be applied to the database structure. * * @return bool|MDB2_Error MDB2_OK or error object * @access public */ function alterDatabaseTables($current_definition, $previous_definition, $changes) { /* FIXME: tables marked to be added are initialized by createTable(), others don't */ $alterations = 0; if (empty($changes)) { return $alterations; } if (!empty($changes['add']) && is_array($changes['add'])) { foreach ($changes['add'] as $table_name => $table) { $result = $this->createTable($table_name, $current_definition[$table_name]); if (PEAR::isError($result)) { return $result; } $alterations++; } } if ($this->options['drop_missing_tables'] && !empty($changes['remove']) && is_array($changes['remove'])) { foreach ($changes['remove'] as $table_name => $table) { $result = $this->db->manager->dropTable($table_name); if (PEAR::isError($result)) { return $result; } $alterations++; } } if (!empty($changes['change']) && is_array($changes['change'])) { foreach ($changes['change'] as $table_name => $table) { $indexes = array(); if (!empty($table['indexes'])) { $indexes = $table['indexes']; unset($table['indexes']); } if (!empty($indexes['remove'])) { $result = $this->alterDatabaseIndexes($table_name, array('remove' => $indexes['remove'])); if (PEAR::isError($result)) { return $result; } unset($indexes['remove']); $alterations += $result; } $result = $this->db->manager->alterTable($table_name, $table, false); if (PEAR::isError($result)) { return $result; } $alterations++; // table may be renamed at this point if (!empty($table['name'])) { $table_name = $table['name']; } if (!empty($indexes)) { $result = $this->alterDatabaseIndexes($table_name, $indexes); if (PEAR::isError($result)) { return $result; } $alterations += $result; } } } return $alterations; } // }}} // {{{ alterDatabaseSequences() /** * Execute the necessary actions to implement the requested changes * in the sequences inside a database structure. * * @param array $current_definition multi dimensional array that contains the current definition * @param array $previous_definition multi dimensional array that contains the previous definition * @param array $changes associative array that contains the definition of the changes * that are meant to be applied to the database structure. * * @return bool|MDB2_Error MDB2_OK or error object * @access public */ function alterDatabaseSequences($current_definition, $previous_definition, $changes) { $alterations = 0; if (empty($changes)) { return $alterations; } if (!empty($changes['add']) && is_array($changes['add'])) { foreach ($changes['add'] as $sequence_name => $sequence) { $result = $this->createSequence($sequence_name, $current_definition[$sequence_name]); if (PEAR::isError($result)) { return $result; } $alterations++; } } if (!empty($changes['remove']) && is_array($changes['remove'])) { foreach ($changes['remove'] as $sequence_name => $sequence) { $result = $this->db->manager->dropSequence($sequence_name); if (PEAR::isError($result)) { return $result; } $alterations++; } } if (!empty($changes['change']) && is_array($changes['change'])) { foreach ($changes['change'] as $sequence_name => $sequence) { $result = $this->db->manager->dropSequence($previous_definition[$sequence_name]['was']); if (PEAR::isError($result)) { return $result; } $result = $this->createSequence($sequence_name, $sequence); if (PEAR::isError($result)) { return $result; } $alterations++; } } return $alterations; } // }}} // {{{ alterDatabase() /** * Execute the necessary actions to implement the requested changes * in a database structure. * * @param array $current_definition multi dimensional array that contains the current definition * @param array $previous_definition multi dimensional array that contains the previous definition * @param array $changes associative array that contains the definition of the changes * that are meant to be applied to the database structure. * * @return bool|MDB2_Error MDB2_OK or error object * @access public */ function alterDatabase($current_definition, $previous_definition, $changes) { $alterations = 0; if (empty($changes)) { return $alterations; } $result = $this->verifyAlterDatabase($changes); if (PEAR::isError($result)) { return $result; } if (!empty($current_definition['name'])) { $previous_database_name = $this->db->setDatabase($current_definition['name']); } if (($support_transactions = $this->db->supports('transactions')) && PEAR::isError($result = $this->db->beginNestedTransaction()) ) { return $result; } if (!empty($changes['tables']) && !empty($current_definition['tables'])) { $current_tables = isset($current_definition['tables']) ? $current_definition['tables'] : array(); $previous_tables = isset($previous_definition['tables']) ? $previous_definition['tables'] : array(); $result = $this->alterDatabaseTables($current_tables, $previous_tables, $changes['tables']); if (is_numeric($result)) { $alterations += $result; } } if (!PEAR::isError($result) && !empty($changes['sequences'])) { $current_sequences = isset($current_definition['sequences']) ? $current_definition['sequences'] : array(); $previous_sequences = isset($previous_definition['sequences']) ? $previous_definition['sequences'] : array(); $result = $this->alterDatabaseSequences($current_sequences, $previous_sequences, $changes['sequences']); if (is_numeric($result)) { $alterations += $result; } } if ($support_transactions) { $res = $this->db->completeNestedTransaction(); if (PEAR::isError($res)) { $result = $this->raiseError(MDB2_SCHEMA_ERROR, null, null, 'Could not end transaction ('. $res->getMessage().' ('.$res->getUserinfo().'))'); } } elseif (PEAR::isError($result) && $alterations) { $result = $this->raiseError(MDB2_SCHEMA_ERROR, null, null, 'the requested database alterations were only partially implemented ('. $result->getMessage().' ('.$result->getUserinfo().'))'); } if (isset($previous_database_name)) { $this->db->setDatabase($previous_database_name); } return $result; } // }}} // {{{ dumpDatabaseChanges() /** * Dump the changes between two database definitions. * * @param array $changes associative array that specifies the list of database * definitions changes as returned by the _compareDefinitions * manager class function. * * @return bool|MDB2_Error MDB2_OK or error object * @access public */ function dumpDatabaseChanges($changes) { if (!empty($changes['tables'])) { if (!empty($changes['tables']['add']) && is_array($changes['tables']['add'])) { foreach ($changes['tables']['add'] as $table_name => $table) { $this->db->debug("$table_name:", __FUNCTION__); $this->db->debug("\tAdded table '$table_name'", __FUNCTION__); } } if (!empty($changes['tables']['remove']) && is_array($changes['tables']['remove'])) { if ($this->options['drop_missing_tables']) { foreach ($changes['tables']['remove'] as $table_name => $table) { $this->db->debug("$table_name:", __FUNCTION__); $this->db->debug("\tRemoved table '$table_name'", __FUNCTION__); } } else { foreach ($changes['tables']['remove'] as $table_name => $table) { $this->db->debug("\tObsolete table '$table_name' left as is", __FUNCTION__); } } } if (!empty($changes['tables']['change']) && is_array($changes['tables']['change'])) { foreach ($changes['tables']['change'] as $table_name => $table) { if (array_key_exists('name', $table)) { $this->db->debug("\tRenamed table '$table_name' to '".$table['name']."'", __FUNCTION__); } if (!empty($table['add']) && is_array($table['add'])) { foreach ($table['add'] as $field_name => $field) { $this->db->debug("\tAdded field '".$field_name."'", __FUNCTION__); } } if (!empty($table['remove']) && is_array($table['remove'])) { foreach ($table['remove'] as $field_name => $field) { $this->db->debug("\tRemoved field '".$field_name."'", __FUNCTION__); } } if (!empty($table['rename']) && is_array($table['rename'])) { foreach ($table['rename'] as $field_name => $field) { $this->db->debug("\tRenamed field '".$field_name."' to '".$field['name']."'", __FUNCTION__); } } if (!empty($table['change']) && is_array($table['change'])) { foreach ($table['change'] as $field_name => $field) { $field = $field['definition']; if (array_key_exists('type', $field)) { $this->db->debug("\tChanged field '$field_name' type to '".$field['type']."'", __FUNCTION__); } if (array_key_exists('unsigned', $field)) { $this->db->debug("\tChanged field '$field_name' type to '". (!empty($field['unsigned']) && $field['unsigned'] ? '' : 'not ')."unsigned'", __FUNCTION__); } if (array_key_exists('length', $field)) { $this->db->debug("\tChanged field '$field_name' length to '". (!empty($field['length']) ? $field['length']: 'no length')."'", __FUNCTION__); } if (array_key_exists('default', $field)) { $this->db->debug("\tChanged field '$field_name' default to ". (isset($field['default']) ? "'".$field['default']."'" : 'NULL'), __FUNCTION__); } if (array_key_exists('notnull', $field)) { $this->db->debug("\tChanged field '$field_name' notnull to ". (!empty($field['notnull']) && $field['notnull'] ? 'true' : 'false'), __FUNCTION__); } } } if (!empty($table['indexes']) && is_array($table['indexes'])) { if (!empty($table['indexes']['add']) && is_array($table['indexes']['add'])) { foreach ($table['indexes']['add'] as $index_name => $index) { $this->db->debug("\tAdded index '".$index_name. "' of table '$table_name'", __FUNCTION__); } } if (!empty($table['indexes']['remove']) && is_array($table['indexes']['remove'])) { foreach ($table['indexes']['remove'] as $index_name => $index) { $this->db->debug("\tRemoved index '".$index_name. "' of table '$table_name'", __FUNCTION__); } } if (!empty($table['indexes']['change']) && is_array($table['indexes']['change'])) { foreach ($table['indexes']['change'] as $index_name => $index) { if (array_key_exists('name', $index)) { $this->db->debug("\tRenamed index '".$index_name."' to '".$index['name']. "' on table '$table_name'", __FUNCTION__); } if (array_key_exists('unique', $index)) { $this->db->debug("\tChanged index '".$index_name."' unique to '". !empty($index['unique'])."' on table '$table_name'", __FUNCTION__); } if (array_key_exists('primary', $index)) { $this->db->debug("\tChanged index '".$index_name."' primary to '". !empty($index['primary'])."' on table '$table_name'", __FUNCTION__); } if (array_key_exists('change', $index)) { $this->db->debug("\tChanged index '".$index_name. "' on table '$table_name'", __FUNCTION__); } } } } } } } if (!empty($changes['sequences'])) { if (!empty($changes['sequences']['add']) && is_array($changes['sequences']['add'])) { foreach ($changes['sequences']['add'] as $sequence_name => $sequence) { $this->db->debug("$sequence_name:", __FUNCTION__); $this->db->debug("\tAdded sequence '$sequence_name'", __FUNCTION__); } } if (!empty($changes['sequences']['remove']) && is_array($changes['sequences']['remove'])) { foreach ($changes['sequences']['remove'] as $sequence_name => $sequence) { $this->db->debug("$sequence_name:", __FUNCTION__); $this->db->debug("\tAdded sequence '$sequence_name'", __FUNCTION__); } } if (!empty($changes['sequences']['change']) && is_array($changes['sequences']['change'])) { foreach ($changes['sequences']['change'] as $sequence_name => $sequence) { if (array_key_exists('name', $sequence)) { $this->db->debug("\tRenamed sequence '$sequence_name' to '". $sequence['name']."'", __FUNCTION__); } if (!empty($sequence['change']) && is_array($sequence['change'])) { foreach ($sequence['change'] as $sequence_name => $sequence) { if (array_key_exists('start', $sequence)) { $this->db->debug("\tChanged sequence '$sequence_name' start to '". $sequence['start']."'", __FUNCTION__); } } } } } } return MDB2_OK; } // }}} // {{{ dumpDatabase() /** * Dump a previously parsed database structure in the Metabase schema * XML based format suitable for the Metabase parser. This function * may optionally dump the database definition with initialization * commands that specify the data that is currently present in the tables. * * @param array $database_definition multi dimensional array that contains the current definition * @param array $arguments associative array that takes pairs of tag * names and values that define dump options. *
array (
     *                     'output_mode'    =>    String
     *                         'file' :   dump into a file
     *                         default:   dump using a function
     *                     'output'        =>    String
     *                         depending on the 'Output_Mode'
     *                                  name of the file
     *                                  name of the function
     *                     'end_of_line'        =>    String
     *                         end of line delimiter that should be used
     *                         default: "\n"
     *                 );
* @param int $dump Int that determines what data to dump * + MDB2_SCHEMA_DUMP_ALL : the entire db * + MDB2_SCHEMA_DUMP_STRUCTURE : only the structure of the db * + MDB2_SCHEMA_DUMP_CONTENT : only the content of the db * * @return bool|MDB2_Error MDB2_OK or error object * @access public */ function dumpDatabase($database_definition, $arguments, $dump = MDB2_SCHEMA_DUMP_ALL) { $class_name = $this->options['writer']; $result = MDB2::loadClass($class_name, $this->db->getOption('debug')); if (PEAR::isError($result)) { return $result; } // get initialization data if (isset($database_definition['tables']) && is_array($database_definition['tables']) && $dump == MDB2_SCHEMA_DUMP_ALL || $dump == MDB2_SCHEMA_DUMP_CONTENT ) { foreach ($database_definition['tables'] as $table_name => $table) { $fields = array(); $fieldsq = array(); foreach ($table['fields'] as $field_name => $field) { $fields[$field_name] = $field['type']; $fieldsq[] = $this->db->quoteIdentifier($field_name, true); } $query = 'SELECT '.implode(', ', $fieldsq).' FROM '; $query .= $this->db->quoteIdentifier($table_name, true); $data = $this->db->queryAll($query, $fields, MDB2_FETCHMODE_ASSOC); if (PEAR::isError($data)) { return $data; } if (!empty($data)) { $initialization = array(); $lob_buffer_length = $this->db->getOption('lob_buffer_length'); foreach ($data as $row) { $rows = array(); foreach ($row as $key => $lob) { if (is_resource($lob)) { $value = ''; while (!feof($lob)) { $value .= fread($lob, $lob_buffer_length); } $row[$key] = $value; } $rows[] = array('name' => $key, 'group' => array('type' => 'value', 'data' => $row[$key])); } $initialization[] = array('type' => 'insert', 'data' => array('field' => $rows)); } $database_definition['tables'][$table_name]['initialization'] = $initialization; } } } $writer =& new $class_name($this->options['valid_types']); return $writer->dumpDatabase($database_definition, $arguments, $dump); } // }}} // {{{ writeInitialization() /** * Write initialization and sequences * * @param string|array $data data file or data array * @param string|array $structure structure file or array * @param array $variables associative array that is passed to the argument * of the same name to the parseDatabaseDefinitionFile function. (there third * param) * * @return bool|MDB2_Error MDB2_OK or error object * @access public */ function writeInitialization($data, $structure = false, $variables = array()) { if ($structure) { $structure = $this->parseDatabaseDefinition($structure, false, $variables); if (PEAR::isError($structure)) { return $structure; } } $data = $this->parseDatabaseDefinition($data, false, $variables, false, $structure); if (PEAR::isError($data)) { return $data; } $previous_database_name = null; if (!empty($data['name'])) { $previous_database_name = $this->db->setDatabase($data['name']); } elseif (!empty($structure['name'])) { $previous_database_name = $this->db->setDatabase($structure['name']); } if (!empty($data['tables']) && is_array($data['tables'])) { foreach ($data['tables'] as $table_name => $table) { if (empty($table['initialization'])) { continue; } $result = $this->initializeTable($table_name, $table); if (PEAR::isError($result)) { return $result; } } } if (!empty($structure['sequences']) && is_array($structure['sequences'])) { foreach ($structure['sequences'] as $sequence_name => $sequence) { if (isset($data['sequences'][$sequence_name]) || !isset($sequence['on']['table']) || !isset($data['tables'][$sequence['on']['table']]) ) { continue; } $result = $this->createSequence($sequence_name, $sequence, true); if (PEAR::isError($result)) { return $result; } } } if (!empty($data['sequences']) && is_array($data['sequences'])) { foreach ($data['sequences'] as $sequence_name => $sequence) { $result = $this->createSequence($sequence_name, $sequence, true); if (PEAR::isError($result)) { return $result; } } } if (isset($previous_database_name)) { $this->db->setDatabase($previous_database_name); } return MDB2_OK; } // }}} // {{{ updateDatabase() /** * Compare the correspondent files of two versions of a database schema * definition: the previously installed and the one that defines the schema * that is meant to update the database. * If the specified previous definition file does not exist, this function * will create the database from the definition specified in the current * schema file. * If both files exist, the function assumes that the database was previously * installed based on the previous schema file and will update it by just * applying the changes. * If this function succeeds, the contents of the current schema file are * copied to replace the previous schema file contents. Any subsequent schema * changes should only be done on the file specified by the $current_schema_file * to let this function make a consistent evaluation of the exact changes that * need to be applied. * * @param string|array $current_schema filename or array of the updated database schema definition. * @param string|array $previous_schema filename or array of the previously installed database schema definition. * @param array $variables associative array that is passed to the argument of the same * name to the parseDatabaseDefinitionFile function. (there third param) * @param bool $disable_query determines if the disable_query option should be set to true * for the alterDatabase() or createDatabase() call * @param bool $overwrite_old_schema_file Overwrite? * * @return bool|MDB2_Error MDB2_OK or error object * @access public */ function updateDatabase($current_schema, $previous_schema = false, $variables = array(), $disable_query = false, $overwrite_old_schema_file = false) { $current_definition = $this->parseDatabaseDefinition($current_schema, false, $variables, $this->options['fail_on_invalid_names']); if (PEAR::isError($current_definition)) { return $current_definition; } $previous_definition = false; if ($previous_schema) { $previous_definition = $this->parseDatabaseDefinition($previous_schema, true, $variables, $this->options['fail_on_invalid_names']); if (PEAR::isError($previous_definition)) { return $previous_definition; } } if ($previous_definition) { $dbExists = $this->db->databaseExists($current_definition['name']); if (PEAR::isError($dbExists)) { return $dbExists; } if (!$dbExists) { return $this->raiseError(MDB2_SCHEMA_ERROR, null, null, 'database to update does not exist: '.$current_definition['name']); } $changes = $this->compareDefinitions($current_definition, $previous_definition); if (PEAR::isError($changes)) { return $changes; } if (is_array($changes)) { $this->db->setOption('disable_query', $disable_query); $result = $this->alterDatabase($current_definition, $previous_definition, $changes); $this->db->setOption('disable_query', false); if (PEAR::isError($result)) { return $result; } $copy = true; if ($this->db->options['debug']) { $result = $this->dumpDatabaseChanges($changes); if (PEAR::isError($result)) { return $result; } } } } else { $this->db->setOption('disable_query', $disable_query); $result = $this->createDatabase($current_definition); $this->db->setOption('disable_query', false); if (PEAR::isError($result)) { return $result; } } if ($overwrite_old_schema_file && !$disable_query && is_string($previous_schema) && is_string($current_schema) && !copy($current_schema, $previous_schema)) { return $this->raiseError(MDB2_SCHEMA_ERROR, null, null, 'Could not copy the new database definition file to the current file'); } return MDB2_OK; } // }}} // {{{ errorMessage() /** * Return a textual error message for a MDB2 error code * * @param int|array $value integer error code, null to get the * current error code-message map, * or an array with a new error code-message map * * @return string error message, or false if the error code was not recognized * @access public */ function errorMessage($value = null) { static $errorMessages; if (is_array($value)) { $errorMessages = $value; return MDB2_OK; } elseif (!isset($errorMessages)) { $errorMessages = array( MDB2_SCHEMA_ERROR => 'unknown error', MDB2_SCHEMA_ERROR_PARSE => 'schema parse error', MDB2_SCHEMA_ERROR_VALIDATE => 'schema validation error', MDB2_SCHEMA_ERROR_INVALID => 'invalid', MDB2_SCHEMA_ERROR_UNSUPPORTED => 'not supported', MDB2_SCHEMA_ERROR_WRITER => 'schema writer error', ); } if (is_null($value)) { return $errorMessages; } if (PEAR::isError($value)) { $value = $value->getCode(); } return !empty($errorMessages[$value]) ? $errorMessages[$value] : $errorMessages[MDB2_SCHEMA_ERROR]; } // }}} // {{{ raiseError() /** * This method is used to communicate an error and invoke error * callbacks etc. Basically a wrapper for PEAR::raiseError * without the message string. * * @param int|PEAR_Error $code integer error code or and PEAR_Error instance * @param int $mode error mode, see PEAR_Error docs * error level (E_USER_NOTICE etc). If error mode is * PEAR_ERROR_CALLBACK, this is the callback function, * either as a function name, or as an array of an * object and method name. For other error modes this * parameter is ignored. * @param array $options Options, depending on the mode, @see PEAR::setErrorHandling * @param string $userinfo Extra debug information. Defaults to the last * query and native error code. * * @return object a PEAR error object * @access public * @see PEAR_Error */ function &raiseError($code = null, $mode = null, $options = null, $userinfo = null) { $err =& PEAR::raiseError(null, $code, $mode, $options, $userinfo, 'MDB2_Schema_Error', true); return $err; } // }}} // {{{ isError() /** * Tell whether a value is an MDB2_Schema error. * * @param mixed $data the value to test * @param int $code if $data is an error object, return true only if $code is * a string and $db->getMessage() == $code or * $code is an integer and $db->getCode() == $code * * @return bool true if parameter is an error * @access public */ function isError($data, $code = null) { if (is_a($data, 'MDB2_Schema_Error')) { if (is_null($code)) { return true; } elseif (is_string($code)) { return $data->getMessage() === $code; } else { $code = (array)$code; return in_array($data->getCode(), $code); } } return false; } // }}} } /** * MDB2_Schema_Error implements a class for reporting portable database error * messages. * * @category Database * @package MDB2_Schema * @author Stig Bakken * @license BSD http://www.opensource.org/licenses/bsd-license.php * @link http://pear.php.net/packages/MDB2_Schema */ class MDB2_Schema_Error extends PEAR_Error { /** * MDB2_Schema_Error constructor. * * @param mixed $code error code, or string with error message. * @param int $mode what 'error mode' to operate in * @param int $level what error level to use for $mode & PEAR_ERROR_TRIGGER * @param mixed $debuginfo additional debug info, such as the last query * * @access public */ function MDB2_Schema_Error($code = MDB2_SCHEMA_ERROR, $mode = PEAR_ERROR_RETURN, $level = E_USER_NOTICE, $debuginfo = null) { $this->PEAR_Error('MDB2_Schema Error: ' . MDB2_Schema::errorMessage($code), $code, $mode, $level, $debuginfo); } } ?> MDB2_Schema-0.8.5/scripts/mdb2_schematool100755 765 765 123 11150346546 13324 #!@php_bin@ MDB2_Schema-0.8.5/tests/clitest.php100644 765 765 12723 11150346546 12240 | // +----------------------------------------------------------------------+ // // $Id: clitest.php,v 1.3 2006/10/20 16:36:41 lsmith Exp $ /* This is a small test suite for MDB2 using PHPUnit This is the command line version and should be used like so; php -q clitest.php This will run through all tests in all testcases (as defined in test_setup.php). To run individual tests add their names to the command line and all testcases will be searched for matching test names, e.g. php -q clitest.php teststorage testreplace */ require_once 'test_setup.php'; require_once 'PHPUnit.php'; require_once 'testUtils.php'; require_once 'MDB2.php'; require_once 'Console_TestListener.php'; MDB2::loadFile('Date'); foreach ($testcases as $testcase) { include_once $testcase.'.php'; } $database = 'driver_test'; $inputMethods = $argv; if ($argc > 1) { array_shift($inputMethods); $exclude = false; if ($inputMethods[0] == '-exclude') { array_shift($inputMethods); $exclude = true; } foreach ($testcases as $testcase) { $possibleMethods = getTests($testcase); if ($exclude) { $intersect = array_diff($possibleMethods, $inputMethods); } else { $intersect = array_intersect($possibleMethods, $inputMethods); } if (count($intersect) > 0) { $testmethods[$testcase] = array_flip($intersect); } } } $database = 'driver_test'; if (!isset($testmethods) || !is_array($testmethods)) { foreach ($testcases as $testcase) { $testmethods[$testcase] = array_flip(getTests($testcase)); } } foreach ($dbarray as $db) { $dsn = $db['dsn']; $options = array_key_exists('options', $db) ? $db['options'] : array(); $GLOBALS['_show_silenced'] = array_key_exists('debug', $options) ? $options['debug'] :false; $display_dsn = $dsn['phptype'] . "://" . $dsn['username'] . ":" . $dsn['password'] . "@" . $dsn['hostspec'] . "/" . $database; echo "=== Start test of $display_dsn on ".PHP_VERSION." ===\n"; $suite = new PHPUnit_TestSuite(); foreach ($testcases as $testcase) { if (is_array($testmethods[$testcase])) { $methods = array_keys($testmethods[$testcase]); foreach ($methods as $method) { $suite->addTest(new $testcase($method)); } } } $result = new PHPUnit_TestResult; $result->addListener(new Console_TestListener); $suite->run($result); echo "=== End test of $display_dsn ===\n\n"; } ?>MDB2_Schema-0.8.5/tests/Console_TestListener.php100644 765 765 1607 11150346546 14657 _errors += 1; echo(" Error $this->_errors in ".$test->getName()." : $t\n"); } function addFailure(&$test, &$t) { $this->_fails += 1; if ($this->_fails == 1) { echo("\n"); } echo("Failure $this->_fails : $t\n"); } function endTest(&$test) { if ($this->_fails == 0 && $this->_errors == 0) { echo(' Test passed'); } else { echo("There were $this->_fails failures for ".$test->getName()."\n"); echo("There were $this->_errors errors for ".$test->getName()."\n"); } echo("\n"); } function startTest(&$test) { $this->_fails = 0; $this->_errors = 0; echo(get_class($test).' : Starting '.$test->getName().' ...'); } } ?>MDB2_Schema-0.8.5/tests/driver_test.schema100644 765 765 2746 11150346546 13560 name create users user_name text 12 false user_password text 8 true subscribed boolean user_id integer 0 1 quota decimal weight float access_date date access_time time approved timestamp users_id_index 1 user_id
MDB2_Schema-0.8.5/tests/HTML_TestListener.php100644 765 765 1746 11150346546 14025 _errors += 1; echo("
Error $this->_errors in ".$test->getName()." : $t
"); } function addFailure(&$test, &$t) { $this->_fails += 1; if ($this->_fails == 1) { echo("\n
"); } echo("Failure $this->_fails : $t
\n"); } function endTest(&$test) { if ($this->_fails == 0 && $this->_errors == 0) { echo(' Test passed'); } else { echo("There were $this->_fails failures for ".$test->getName()."
\n"); echo("There were $this->_errors errors for ".$test->getName()."
\n"); } echo(''); } function startTest(&$test) { $this->_fails = 0; $this->_errors = 0; echo("\n
".get_class($test).' : Starting '.$test->getName().' ...'); } } ?>MDB2_Schema-0.8.5/tests/lob_test.schema100644 765 765 1520 11150346546 13026 name 0 files id integer 0 1 document clob picture blob lob_id_index 1 id
mysequence files
id
MDB2_Schema-0.8.5/tests/MDB2_Schema_testcase.php100644 765 765 20525 11150346546 14427 | // +----------------------------------------------------------------------+ // // $Id: MDB2_Schema_testcase.php,v 1.5 2008/10/25 01:16:48 ifeghali Exp $ require_once 'MDB2/Schema.php'; class MDB2_Schema_TestCase extends PHPUnit_TestCase { //contains the dsn of the database we are testing var $dsn; //contains the options that should be used during testing var $options; //contains the name of the database we are testing var $database; //contains the MDB2_Schema object of the db once we have connected var $schema; //contains the name of the driver_test schema var $driver_input_file = 'driver_test.schema'; //contains the name of the lob_test schema var $lob_input_file = 'lob_test.schema'; //contains the name of the extension to use for backup schemas var $backup_extension = '.before'; //contains the name of the extension to use for dump schemas var $dump_extension = '.dump'; function MDB2_Schema_Test($name) { $this->PHPUnit_TestCase($name); } function setUp() { $this->dsn = $GLOBALS['dsn']; $this->options = $GLOBALS['options']; $this->database = $GLOBALS['database']; $backup_file = $this->driver_input_file.$this->backup_extension; if (file_exists($backup_file)) { unlink($backup_file); } $backup_file = $this->lob_input_file.$this->backup_extension; if (file_exists($backup_file)) { unlink($backup_file); } $this->schema =& MDB2_Schema::factory($this->dsn, $this->options); if (PEAR::isError($this->schema)) { $this->assertTrue(false, 'Could not connect to manager in setUp'); exit; } } function tearDown() { unset($this->dsn); if (!PEAR::isError($this->schema)) { $this->schema->disconnect(); } unset($this->schema); } function methodExists(&$class, $name) { if (is_object($class) && array_key_exists(strtolower($name), array_change_key_case(array_flip(get_class_methods($class)), CASE_LOWER)) ) { return true; } $this->assertTrue(false, 'method '. $name.' not implemented in '.get_class($class)); return false; } function testCreateDatabase() { if (!$this->methodExists($this->schema->db->manager, 'dropDatabase')) { return; } $this->schema->db->expectError('*'); $result = $this->schema->db->manager->dropDatabase($this->database); $this->schema->db->popExpect(); if (PEAR::isError($result)) { $this->assertTrue(false, 'Database dropping failed: please manually delete the database if needed'); } if (!$this->methodExists($this->schema, 'updateDatabase')) { return; } $result = $this->schema->updateDatabase( $this->driver_input_file, false, array('create' => '1', 'name' => $this->database) ); if (PEAR::isError($result)) { $result = $this->schema->updateDatabase( $this->driver_input_file, false, array('create' => '0', 'name' => $this->database) ); } if (!PEAR::isError($result)) { $result = $this->schema->updateDatabase( $this->lob_input_file, false, array('create' => '0', 'name' => $this->database) ); } $this->assertFalse(PEAR::isError($result), 'Error creating database'); } function testUpdateDatabase() { if (!$this->methodExists($this->schema, 'updateDatabase')) { return; } $backup_file = $this->driver_input_file.$this->backup_extension; if (!file_exists($backup_file)) { copy($this->driver_input_file, $backup_file); } $result = $this->schema->updateDatabase( $this->driver_input_file, $backup_file, array('create' =>'0', 'name' =>$this->database) ); if (!PEAR::isError($result)) { $backup_file = $this->lob_input_file.$this->backup_extension; if (!file_exists($backup_file)) { copy($this->lob_input_file, $backup_file); } $result = $this->schema->updateDatabase( $this->lob_input_file, $backup_file, array('create' =>'0', 'name' => $this->database) ); } $this->assertFalse(PEAR::isError($result), 'Error updating database'); } function testDumpDatabase() { if (!$this->methodExists($this->schema, 'getDefinitionFromDatabase')) { return; } $definition = $this->schema->getDefinitionFromDatabase(); $this->assertFalse(PEAR::isError($definition), 'Error getting definition from database'); if (!$this->methodExists($this->schema, 'dumpDatabase')) { return; } $dump_file = $this->lob_input_file.'.'.$this->dsn['phptype'].$this->dump_extension; $result = $this->schema->dumpDatabase( $definition, array('output_mode' => 'file', 'output' => $dump_file, 'end_of_line' => "\n", ), MDB2_SCHEMA_DUMP_ALL); $this->assertFalse(PEAR::isError($result), 'Error dumping database'); } } ?> MDB2_Schema-0.8.5/tests/README100644 765 765 2221 11150346546 10710 *** The contents of this directory are outdated *** This is a test framework for MDB2_Schema built using PHPUnit. These tests directly access the MDB2_Schema API - hopefully this framework should give better feedback as to where or what caused when error are encountered. Usage: In order for the tests to work you need to ensure that the user you configure is allowed to create a new database. To setup the tests * requires PHPUnit to be installed * requires MDB2 (with the given driver) as well as MDB2_Schema to be installed in a php include path. * copy the file test_setup.php.dist to test_setup.php * edit test_setup.php. The array $testarray specifies which testcases to carry out. $dbarray is an array of databases to test. * point your browser at test.php or your CLI at clitest.php for the results, and then fix the bugs! * by default test.php/clitest.php will use all tests in the testcases - if you want to pick specific tests, use testchoose.php to pick just the tests you want to run Writing tests: The tests are written using PHPUnit so first make sure you have the latest stable release, and have read the docs. http://www.phpunit.deMDB2_Schema-0.8.5/tests/test.php100644 765 765 12347 11150346546 11552 | // +----------------------------------------------------------------------+ // // $Id: test.php,v 1.3 2006/10/20 16:36:41 lsmith Exp $ /* This is a small test suite for MDB2 using PHPUnit */ require_once 'test_setup.php'; require_once 'PHPUnit.php'; require_once 'testUtils.php'; require_once 'MDB2.php'; require_once 'HTML_TestListener.php'; function htmlErrorHandler($errno, $errstr, $errfile, $errline) { if ((!$GLOBALS['_show_silenced'] && !error_reporting()) || $errno == 2048) { return; } echo '
';
    errorHandler($errno, $errstr, $errfile, $errline);
    echo '
'; } set_error_handler('htmlErrorHandler'); function htmlErrorHandlerPEAR($error_obj) { echo '
';
    errorHandlerPEAR($error_obj);
    echo '
'; } PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'htmlErrorHandlerPEAR'); MDB2::loadFile('Date'); foreach ($testcases as $testcase) { include_once $testcase.'.php'; } $database = 'driver_test'; $testmethods = array_key_exists('testmethods', $_POST) ? $_POST['testmethods'] : null; if (!is_array($testmethods)) { foreach ($testcases as $testcase) { $testmethods[$testcase] = array_flip(getTests($testcase)); } } ?> MDB2 Tests \n"; echo "
Testing $display_dsn on ".PHP_VERSION."
\n"; $suite = new PHPUnit_TestSuite(); foreach ($testcases as $testcase) { if (isset($testmethods[$testcase]) && is_array($testmethods[$testcase])) { $methods = array_keys($testmethods[$testcase]); foreach ($methods as $method) { $suite->addTest(new $testcase($method)); } } } $result = new PHPUnit_TestResult; $result->addListener(new HTML_TestListener); $suite->run($result); echo "\n
\n"; } ?> MDB2_Schema-0.8.5/tests/testchoose.php100644 765 765 3475 11150346546 12735 '."\n"; $output.= ' TestCase : '.$testcase.''."\n"; $testmethods[$testcase] = getTests($testcase); foreach ($testmethods[$testcase] as $method) { $output.= testCheck($testcase, $method); } $output.= "
\n\n"; $output.= "

\n\n"; } ?> MDB2 Tests
MDB2_Schema-0.8.5/tests/tests.css100644 765 765 735 11150346546 11674 body { background-color: #ffffff; color: #000000; } div.failure { border: 2px #FF0000 solid; margin : 1em; } h1 { font-size: x-small } div.test { border : 1px #000000 solid; width : 100%; margin-top : 1em; padding : 2px; } .title { top : 0px; left : 0px; text-align : center; background : #000000; color : #FFFFFF; padding : 4px; } div.testlineup { border: 2px #000000 solid; } MDB2_Schema-0.8.5/tests/testUtils.php100644 765 765 6541 11150346546 12552 $testmethod
\n"; } /** * Little helper function that gets a backtrace if available */ function getBacktrace() { $message = ''; if (!function_exists('debug_backtrace')) { $message.= 'function debug_backtrace does not exists'."\n"; } $debug_backtrace = debug_backtrace(); array_shift($debug_backtrace); $message.= 'Debug backtrace:'."\n"; foreach ($debug_backtrace as $trace_item) { $message.= "\t" . ' @ '; if (array_key_exists('file', $trace_item)) { $message.= basename($trace_item['file']) . ':' . $trace_item['line']; } else { $message.= '- PHP inner-code - '; } $message.= ' -- '; if (array_key_exists('class', $trace_item)) { $message.= $trace_item['class'] . $trace_item['type']; } $message.= $trace_item['function']; if (!empty($trace_item['args']) && is_array($trace_item['args'])) { $args = array(); foreach ($trace_item['args'] as $arg) { $args[] = is_scalar($arg) ? $arg : (is_object($arg) ? get_class($arg) : gettype($arg)); } $message.= '('.implode(', ', $args).')'; } else { $message.= '()'; } $message.= "\n"; } return $message; } require_once 'PEAR.php'; function errorHandlerPEAR($error_obj) { $message = "-- PEAR-Error --\n"; $message.= $error_obj->getMessage().': '.$error_obj->getUserinfo()."\n"; $message.= getBacktrace(); print_r($message); } PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'errorHandlerPEAR'); $GLOBALS['_show_silenced'] = false; function errorHandler($errno, $errstr, $errfile, $errline) { if ((!$GLOBALS['_show_silenced'] && !error_reporting()) || $errno == 2048) { return; } $message = "\n"; switch($errno) { case E_USER_ERROR: $message.= "FATAL [$errno] $errstr\n"; $message.= " Fatal error in line $errline of file $errfile"; $message.= ", PHP " . PHP_VERSION . " (" . PHP_OS . ")\n"; $message.= "Aborting...\n"; die($message); break; case E_USER_WARNING: $message.= "ERROR [$errno] $errstr in line $errline of file $errfile\n"; break; case E_USER_NOTICE: $message.= "WARNING [$errno] $errstr in line $errline of file $errfile\n"; break; default: $message.= "Unkown error type: [$errno] $errstr in line $errline of file $errfile\n"; break; } $message.= getBacktrace(); print_r($message); } set_error_handler('errorHandler'); if (function_exists('xdebug_disable')) { xdebug_disable(); } ?>MDB2_Schema-0.8.5/tests/test_setup.php.dist100644 765 765 4306 11150346546 13710 array( 'phptype' => 'mysql', 'username' => 'username', 'password' => 'password', 'hostspec' => 'hostname', 'database' => 'driver_test', ), 'options' => array( 'use_transactions' => true ) ); $pgsql = array( 'dsn' => array( 'phptype' => 'pgsql', 'username' => 'username', 'password' => 'password', 'hostspec' => 'hostname', ) ); $oci8 = array( 'dsn' => array( 'phptype' => 'oci8', 'username' => '', 'password' => 'password', 'hostspec' => 'hostname', ), 'options' => array( 'DBA_username' => 'username', 'DBA_password' => 'password' ) ); $sqlite = array( 'dsn' => array( 'phptype' => 'sqlite', 'username' => '', 'password' => 'password', 'hostspec' => 'hostname', 'database' => 'driver_test', ), 'options' => array( 'database_path' => '', 'database_extension' => '', ) ); // must be a user with system administrator privileges $mssql = array( 'dsn' => array( 'phptype' => 'mssql', 'username' => 'username', 'password' => 'password', 'hostspec' => 'hostname', ) ); $fbsql = array( 'dsn' => array( 'phptype' => 'fbsql', 'username' => 'username', 'password' => 'password', 'hostspec' => 'hostname', ) ); $ibase = array( 'dsn' => array( 'phptype' => 'ibase', 'username' => 'username', 'password' => 'password', 'hostspec' => 'hostname', ) ); $dbarray = array(); #$dbarray[] = $mysql; #$dbarray[] = $pgsql; #$dbarray[] = $oci8; #$dbarray[] = $sqlite; #$dbarray[] = $mssql; #$dbarray[] = $fbsql; #$dbarray[] = $ibase; // you may need to uncomment the line and modify the multiplier as you see fit #set_time_limit(60*count($dbarray)); ?> MDB2_Schema-0.8.5/www/mdb2_schematool/action.php100644 765 765 20536 11150346546 14573 | // | Author: Igor Feghali | // +----------------------------------------------------------------------+ // // $Id: action.php,v 1.3 2009/02/22 13:30:40 ifeghali Exp $ // /** * This is all rather ugly code, thats probably very much XSS exploitable etc. * However the idea was to keep the magic and dependencies low, to just * illustrate the MDB2_Schema API a bit. */ setcookie('error',''); require_once 'MDB2/Schema.php'; require_once 'class.inc.php'; $data =& MDB2_Schema_Example::factory($_GET); if (PEAR::isError($data)) { setcookie('error', $data->getMessage()); header('location: index.php'); exit; } $schema =& MDB2_Schema::factory($data->dsn, $data->options); if (PEAR::isError($schema)) { $error = $schema->getMessage() . ' ' . $schema->getUserInfo(); setcookie('error', $error); header('location: index.php'); exit; } switch ($data->action) { /* DUMP DATABASE */ case 'dump': switch ($data->dumptype) { case 'structure': $dump_what = MDB2_SCHEMA_DUMP_STRUCTURE; break; case 'content': $dump_what = MDB2_SCHEMA_DUMP_CONTENT; break; default: $dump_what = MDB2_SCHEMA_DUMP_ALL; break; } $dump_config = array( 'output_mode' => 'file', 'output' => $data->file ); $definition = $schema->getDefinitionFromDatabase(); if (PEAR::isError($definition)) { $error = $definition->getMessage() . ' ' . $definition->getUserInfo(); } else { $operation = $schema->dumpDatabase($definition, $dump_config, $dump_what); if (PEAR::isError($operation)) { $error = $operation->getMessage() . ' ' . $operation->getUserInfo(); } } break; /* UPDATE DATABASE */ case 'update': if ($data->disable_query) { $debug_tmp = $schema->db->getOption('debug'); $schema->db->setOption('debug', true); $debug_handler_tmp = $schema->db->getOption('debug_handler'); $schema->db->setOption('debug_handler', 'printQueries'); } $dump_config = array( 'output_mode' => 'file', 'output' => $data->file.'.old' ); $definition = $schema->getDefinitionFromDatabase(); if (PEAR::isError($definition)) { $error = $definition->getMessage() . ' ' . $definition->getUserInfo(); } else { $operation = $schema->dumpDatabase($definition, $dump_config, MDB2_SCHEMA_DUMP_ALL); if (PEAR::isError($operation)) { $error = $operation->getMessage() . ' ' . $operation->getUserInfo(); } else { $operation = $schema->updateDatabase($data->file , $data->file.'.old', array(), $data->disable_query ); if (PEAR::isError($operation)) { $error = $operation->getMessage() . ' ' . $operation->getUserInfo(); } } } if ($data->disable_query) { $schema->db->setOption('debug', $debug_tmp); $schema->db->setOption('debug_handler', $debug_handler_tmp); } break; /* CREATE DATABASE */ case 'create': if ($data->disable_query) { $debug_tmp = $schema->db->getOption('debug'); $schema->db->setOption('debug', true); $debug_handler_tmp = $schema->db->getOption('debug_handler'); $schema->db->setOption('debug_handler', 'printQueries'); } $definition = $schema->parseDatabaseDefinition( $data->file, false, array(), $schema->options['fail_on_invalid_names'] ); if (PEAR::isError($definition)) { $error = $definition->getMessage() . ' ' . $definition->getUserInfo(); } else { $schema->db->setOption('disable_query', $data->disable_query); $operation = $schema->createDatabase($definition); $schema->db->setOption('disable_query', false); if (PEAR::isError($operation)) { $error = $operation->getMessage() . ' ' . $operation->getUserInfo(); } } if ($data->disable_query) { $schema->db->setOption('debug', $debug_tmp); $schema->db->setOption('debug_handler', $debug_handler_tmp); } break; /* INITIALIZE DATABASE */ case 'initialize': if ($data->disable_query) { $debug_tmp = $schema->db->getOption('debug'); $schema->db->setOption('debug', true); $debug_handler_tmp = $schema->db->getOption('debug_handler'); $schema->db->setOption('debug_handler', 'printQueries'); } $definition = $schema->getDefinitionFromDatabase(); if (PEAR::isError($definition)) { $error = $definition->getMessage() . ' ' . $definition->getUserInfo(); } else { $schema->db->setOption('disable_query', $data->disable_query); $operation = $schema->writeInitialization($data->file, $definition); if (PEAR::isError($operation)) { $error = $operation->getMessage() . ' ' . $operation->getUserInfo(); } $schema->db->setOption('disable_query', false); } if ($data->disable_query) { $schema->db->setOption('debug', $debug_tmp); $schema->db->setOption('debug_handler', $debug_handler_tmp); } break; } include 'result.php'; $schema->disconnect(); function printQueries(&$db, $scope, $message) { if ($scope == 'query') { echo $message.$db->getOption('log_line_break'); } MDB2_defaultDebugOutput($db, $scope, $message); } ?> MDB2_Schema-0.8.5/www/mdb2_schematool/class.inc.php100644 765 765 17723 11150346546 15177 | // +----------------------------------------------------------------------+ // // $Id: class.inc.php,v 1.4 2009/02/22 13:33:24 ifeghali Exp $ // /** * This is all rather ugly code, thats probably very much XSS exploitable etc. * However the idea was to keep the magic and dependencies low, to just * illustrate the MDB2_Schema API a bit. */ class MDB2_Schema_Example { var $options = array( 'log_line_break' => '
', 'idxname_format' => '%s', 'DBA_username' => '', 'DBA_password' => '', 'default_table_type' => 'MyISAM', 'debug' => true, 'use_transactions' => true, 'quote_identifier' => true, 'force_defaults' => false, 'portability' => false, 'drop_missing_tables' => false, ); var $dsn = array( 'phptype' => '', 'username' => 'root', 'password' => '', 'hostspec' => 'localhost', 'database' => 'MDB2Example', 'charset' => 'utf8' ); var $show_structure = false; var $disable_query = false; var $action = ''; var $dumptype = ''; var $file = ''; function factory($input) { $obj = new MDB2_Schema_Example($input); if ($error = $obj->validateInput($input)) { return PEAR::raiseError($error); } else { $obj->saveCookies(); $obj->setOptions($input); return $obj; } } function setOptions($options) { foreach ($this->options as $k => $v) { if (is_string($v)) { if (isset($options[$k])) { $this->options[$k] = $options[$k]; } else { $this->options[$k] = ''; } } else { if ((isset($options[$k])) && (!empty($options[$k]))) { $this->options[$k] = true; } else { $this->options[$k] = false; } } } $this->dsn = array( 'phptype' => $options['type'], 'username' => $options['user'], 'password' => $options['pass'], 'hostspec' => $options['host'], 'database' => $options['name'], 'charset' => $options['char'] ); } function validateInput($input) { if (!array_key_exists('action', $input)) { return 'Script Error: no action selected'; } switch ($input['action']) { case 'dump': if (!array_key_exists('dumptype', $input)) { return 'no dump type specified'; } $this->dumptype = $input['dumptype']; if (!array_key_exists('file', $input)) { return 'no output file specified'; } $this->file = $input['file']; break; case 'update': case 'create': case 'initialize': if (!array_key_exists('file', $input)) { return 'no input file specified'; } $this->file = $input['file']; break; default: return 'Script Error: invalid action'; } $this->action = $input['action']; if (isset($input['show_structure'])) { $this->show_structure = $input['show_structure']; } else { $this->show_structure = false; } if (isset($input['disable_query'])) { $this->disable_query = $input['disable_query']; } else { $this->disable_query = false; } return false; } function saveCookies() { setcookie('use_transactions', $this->options['use_transactions']); setcookie('default_table_type', $this->options['default_table_type']); setcookie('log_line_break', $this->options['log_line_break']); setcookie('idxname_format', $this->options['idxname_format']); setcookie('DBA_username', $this->options['DBA_username']); setcookie('DBA_password', $this->options['DBA_password']); setcookie('debug', $this->options['debug']); setcookie('quote_identifier', $this->options['quote_identifier']); setcookie('force_defaults', $this->options['force_defaults']); setcookie('portability', $this->options['portability']); setcookie('drop_missing_tables', $this->options['drop_missing_tables']); setcookie('disable_query', $this->disable_query); setcookie('action', $this->action); setcookie('dumptype', $this->dumptype); setcookie('file', $this->file); setcookie('show_structure', $this->show_structure); setcookie('username', $this->dsn['username']); setcookie('password', $this->dsn['password']); setcookie('hostspec', $this->dsn['hostspec']); setcookie('database', $this->dsn['database']); setcookie('charset', $this->dsn['charset']); setcookie('loaded', '1'); } } ?> MDB2_Schema-0.8.5/www/mdb2_schematool/index.php100644 765 765 26103 11150346546 14421 | // | Author: Igor Feghali | // +----------------------------------------------------------------------+ // // $Id: index.php,v 1.3 2009/02/22 21:43:22 ifeghali Exp $ // /** * This is all rather ugly code, thats probably very much XSS exploitable etc. * However the idea was to keep the magic and dependencies low, to just * illustrate the MDB2_Schema API a bit. */ $error = ''; if (isset($_COOKIE['error']) && $_COOKIE['error']) { $error = $_COOKIE['error']; setcookie('error',''); } if (!isset($_REQUEST['loaded'])) { require_once 'class.inc.php'; $defaults = new MDB2_Schema_Example(); $defaults->saveCookies(); header('location: index.php?loaded=1'); exit; } $databases = array( 'mysql' => 'MySQL', 'mysqli' => 'MySQLi', 'pgsql' => 'PostGreSQL', 'sqlite' => 'SQLite' ); ?> MDB2_Schema Web Frontend Error'; echo '
    '; echo "
  • $error
  • "; echo '
'; } ?>
Database information
/>
/>
/>
/>
Options
/>
/>
/>
/>
/>
/>
/>
/>

MDB2_Schema-0.8.5/www/mdb2_schematool/result.php100644 765 765 10506 11150346546 14630 | // | Author: Igor Feghali | // +----------------------------------------------------------------------+ // // $Id: result.php,v 1.2 2008/11/17 00:24:52 ifeghali Exp $ // /** * This is all rather ugly code, thats probably very much XSS exploitable etc. * However the idea was to keep the magic and dependencies low, to just * illustrate the MDB2_Schema API a bit. */ ?> MDB2_Schema Web Frontend getWarnings(); if (count($warnings) > 0) { echo '

Warnings

'; echo '
';
    var_dump($warnings);
    echo '
'; } if ($schema->db->getOption('debug')) { echo '

Debug messages

'; echo $schema->db->getDebugOutput().'
'; } if ($data->show_structure && isset($definition) && is_array($definition) ) { echo '

Database structure

'; $var_dump($definition); } if (isset($error) && $error) { echo '

Error

'; echo '
    '; echo '
  • ' . $error . '
  • '; echo '
'; } ?>