3 ///////////////////////////////////////////////////////////////////////////
5 // NOTICE OF COPYRIGHT //
7 // Moodle - Modular Object-Oriented Dynamic Learning Environment //
8 // http://moodle.com //
10 // Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com //
11 // (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
13 // This program is free software; you can redistribute it and/or modify //
14 // it under the terms of the GNU General Public License as published by //
15 // the Free Software Foundation; either version 2 of the License, or //
16 // (at your option) any later version. //
18 // This program is distributed in the hope that it will be useful, //
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
21 // GNU General Public License for more details: //
23 // http://www.gnu.org/copyleft/gpl.html //
25 ///////////////////////////////////////////////////////////////////////////
27 /// This class represent one XMLDB Index
29 class xmldb_index
extends xmldb_object
{
36 * - MySQL: MyISAM has a limit of 1000 bytes for any key including composed, InnoDB has limit 3500 bytes.
38 * @const max length of composed indexes, one utf-8 char is 3 bytes in the worst case
40 const INDEX_COMPOSED_MAX_BYTES
= 999;
44 * - MySQL: InnoDB limits size of index on single column to 767bytes (256 chars)
46 * @const single column index length limit, one utf-8 char is 3 bytes in the worst case
48 const INDEX_MAX_BYTES
= 765;
51 * Creates one new xmldb_index
53 function __construct($name, $type=null, $fields=array()) {
54 $this->unique
= false;
55 $this->fields
= array();
56 parent
::__construct($name);
57 return $this->set_attributes($type, $fields);
60 /// TODO: Delete for 2.1 (deprecated in 2.0).
61 /// Deprecated API starts here
62 function setAttributes($type, $fields) {
64 debugging('XMLDBIndex->setAttributes() has been deprecated in Moodle 2.0. Will be out in Moodle 2.1. Please use xmldb_index->set_attributes() instead.', DEBUG_DEVELOPER
);
66 return $this->set_attributes($type, $fields);
68 /// Deprecated API ends here
71 * Set all the attributes of one xmldb_index
73 * @param string type XMLDB_INDEX_UNIQUE, XMLDB_INDEX_NOTUNIQUE
74 * @param array fields an array of fieldnames to build the index over
76 function set_attributes($type, $fields) {
77 $this->unique
= !empty($type) ?
true : false;
78 $this->fields
= $fields;
82 * Get the index unique
84 function getUnique() {
89 * Set the index unique
91 function setUnique($unique = true) {
92 $this->unique
= $unique;
96 * Set the index fields
98 function setFields($fields) {
99 $this->fields
= $fields;
103 * Get the index fields
105 function &getFields() {
106 return $this->fields
;
110 * Load data from XML to the index
112 function arr2xmldb_index($xmlarr) {
117 /// traverse_xmlize($xmlarr); //Debug
118 /// print_object ($GLOBALS['traverse_array']); //Debug
119 /// $GLOBALS['traverse_array']=""; //Debug
121 /// Process key attributes (name, unique, fields, comment, previous, next)
122 if (isset($xmlarr['@']['NAME'])) {
123 $this->name
= trim($xmlarr['@']['NAME']);
125 $this->errormsg
= 'Missing NAME attribute';
126 $this->debug($this->errormsg
);
130 if (isset($xmlarr['@']['UNIQUE'])) {
131 $unique = strtolower(trim($xmlarr['@']['UNIQUE']));
132 if ($unique == 'true') {
133 $this->unique
= true;
134 } else if ($unique == 'false') {
135 $this->unique
= false;
137 $this->errormsg
= 'Incorrect UNIQUE attribute (true/false allowed)';
138 $this->debug($this->errormsg
);
142 $this->errormsg
= 'Undefined UNIQUE attribute';
143 $this->debug($this->errormsg
);
147 if (isset($xmlarr['@']['FIELDS'])) {
148 $fields = strtolower(trim($xmlarr['@']['FIELDS']));
150 $fieldsarr = explode(',',$fields);
152 foreach ($fieldsarr as $key => $element) {
153 $fieldsarr [$key] = trim($element);
156 $this->errormsg
= 'Incorrect FIELDS attribute (comma separated of fields)';
157 $this->debug($this->errormsg
);
161 $this->errormsg
= 'Empty FIELDS attribute';
162 $this->debug($this->errormsg
);
166 $this->errormsg
= 'Missing FIELDS attribute';
167 $this->debug($this->errormsg
);
170 /// Finally, set the array of fields
171 $this->fields
= $fieldsarr;
173 if (isset($xmlarr['@']['COMMENT'])) {
174 $this->comment
= trim($xmlarr['@']['COMMENT']);
177 if (isset($xmlarr['@']['PREVIOUS'])) {
178 $this->previous
= trim($xmlarr['@']['PREVIOUS']);
181 if (isset($xmlarr['@']['NEXT'])) {
182 $this->next
= trim($xmlarr['@']['NEXT']);
185 /// Set some attributes
187 $this->loaded
= true;
189 $this->calculateHash();
194 * This function calculate and set the hash of one xmldb_index
196 function calculateHash($recursive = false) {
197 if (!$this->loaded
) {
200 $key = $this->unique
. implode (', ', $this->fields
);
201 $this->hash
= md5($key);
206 *This function will output the XML text for one index
208 function xmlOutput() {
210 $o.= ' <INDEX NAME="' . $this->name
. '"';
216 $o.= ' UNIQUE="' . $unique . '"';
217 $o.= ' FIELDS="' . implode(', ', $this->fields
) . '"';
218 if ($this->comment
) {
219 $o.= ' COMMENT="' . htmlspecialchars($this->comment
) . '"';
221 if ($this->previous
) {
222 $o.= ' PREVIOUS="' . $this->previous
. '"';
225 $o.= ' NEXT="' . $this->next
. '"';
233 * This function will set all the attributes of the xmldb_index object
234 * based on information passed in one ADOindex
236 function setFromADOIndex($adoindex) {
238 /// Set the unique field
239 $this->unique
= false;
240 /// Set the fields, converting all them to lowercase
241 $fields = array_flip(array_change_key_case(array_flip($adoindex['columns'])));
242 $this->fields
= $fields;
244 $this->loaded
= true;
245 $this->changed
= true;
249 * Returns the PHP code needed to define one xmldb_index
256 $unique = $this->getUnique();
257 if (!empty($unique)) {
258 $result .= 'XMLDB_INDEX_UNIQUE, ';
260 $result .= 'XMLDB_INDEX_NOTUNIQUE, ';
263 $indexfields = $this->getFields();
264 if (!empty($indexfields)) {
265 $result .= 'array(' . "'". implode("', '", $indexfields) . "')";
274 * Shows info in a readable format
276 function readableInfo() {
285 $o .= ' (' . implode(', ', $this->fields
) . ')';
291 * Validates the index restrictions.
293 * The error message should not be localised because it is intended for developers,
294 * end users and admins should never see these problems!
296 * @param xmldb_table $xmldb_table optional when object is table
297 * @return string null if ok, error message if problem found
299 function validateDefinition(xmldb_table
$xmldb_table=null) {
301 return 'Invalid xmldb_index->validateDefinition() call, $xmldb_table si required.';
305 foreach ($this->getFields() as $fieldname) {
306 if (!$field = $xmldb_table->getField($fieldname)) {
307 // argh, we do not have the fields loaded yet, this should not happen during install
311 switch ($field->getType()) {
312 case XMLDB_TYPE_INTEGER
:
313 $total +
= 8; // big int
316 case XMLDB_TYPE_NUMBER
:
317 $total +
= 12; // this is just a guess
320 case XMLDB_TYPE_FLOAT
:
321 $total +
= 8; // double precision
324 case XMLDB_TYPE_CHAR
:
325 if ($field->getLength() > self
::INDEX_MAX_BYTES
/ 3) {
326 return 'Invalid index definition in table {'.$xmldb_table->getName(). '}: XMLDB_TYPE_CHAR field "'.$field->getName().'" can not be indexed because it is too long.'
327 .' Limit is '.(self
::INDEX_MAX_BYTES
/3).' chars.';
329 $total +
= ($field->getLength() * 3); // the most complex utf-8 chars have 3 bytes
332 case XMLDB_TYPE_TEXT
:
333 return 'Invalid index definition in table {'.$xmldb_table->getName(). '}: XMLDB_TYPE_TEXT field "'.$field->getName().'" can not be indexed';
336 case XMLDB_TYPE_BINARY
:
337 return 'Invalid index definition in table {'.$xmldb_table->getName(). '}: XMLDB_TYPE_BINARY field "'.$field->getName().'" can not be indexed';
340 case XMLDB_TYPE_DATETIME
:
341 $total +
= 8; // this is just a guess
344 case XMLDB_TYPE_TIMESTAMP
:
345 $total +
= 8; // this is just a guess
350 if ($total > self
::INDEX_COMPOSED_MAX_BYTES
) {
351 return 'Invalid index definition in table {'.$xmldb_table->getName(). '}: the composed index on fields "'.implode(',', $this->getFields()).'" is too long.'
352 .' Limit is '.self
::INDEX_COMPOSED_MAX_BYTES
.' bytes / '.(self
::INDEX_COMPOSED_MAX_BYTES
/3).' chars.';
360 /// TODO: Delete for 2.1 (deprecated in 2.0).
361 /// Deprecated API starts here
362 class XMLDBIndex
extends xmldb_index
{
364 function __construct($name) {
365 parent
::__construct($name);
369 /// Deprecated API ends here