diff options
author | Frank Karlitschek <karlitschek@kde.org> | 2011-08-07 17:36:49 +0200 |
---|---|---|
committer | Frank Karlitschek <karlitschek@kde.org> | 2011-08-07 17:36:49 +0200 |
commit | f5a030f4ae5298c2b3325a27e8d05153f0488ea0 (patch) | |
tree | 3317cc1a238a0caaabb23a8c9a26451106f24ec1 /3rdparty/MDB2/Schema/Validate.php | |
parent | 51caa624bb0874fff878a00fb2883e58ad60cde3 (diff) | |
download | nextcloud-server-f5a030f4ae5298c2b3325a27e8d05153f0488ea0.tar.gz nextcloud-server-f5a030f4ae5298c2b3325a27e8d05153f0488ea0.zip |
remove the ownCloud 3D support and add lot's of usefull 3rd party libraries instead.
Diffstat (limited to '3rdparty/MDB2/Schema/Validate.php')
-rw-r--r-- | 3rdparty/MDB2/Schema/Validate.php | 917 |
1 files changed, 917 insertions, 0 deletions
diff --git a/3rdparty/MDB2/Schema/Validate.php b/3rdparty/MDB2/Schema/Validate.php new file mode 100644 index 00000000000..217cf51b959 --- /dev/null +++ b/3rdparty/MDB2/Schema/Validate.php @@ -0,0 +1,917 @@ +<?php +/** + * PHP versions 4 and 5 + * + * Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, + * Stig. S. Bakken, Lukas Smith, Igor Feghali + * All rights reserved. + * + * MDB2_Schema enables users to maintain RDBMS independant schema files + * in XML that can be used to manipulate both data and database schemas + * This LICENSE is in the BSD license style. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, + * Lukas Smith, Igor Feghali nor the names of his contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Christian Dickmann <dickmann@php.net> + * Author: Igor Feghali <ifeghali@php.net> + * + * @category Database + * @package MDB2_Schema + * @author Christian Dickmann <dickmann@php.net> + * @author Igor Feghali <ifeghali@php.net> + * @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 <ifeghali@php.net> + * @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; + } + + // }}} + // {{{ 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: + // <length>8,4</length> 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; + } +} + +?> |