$this->assertTrue(count($reserved) > 1);
}
+ public function test_index_max_bytes() {
+ $DB = $this->tdb;
+ $dbman = $DB->get_manager();
+
+ $maxstr = '';
+ for($i=0; $i<255; $i++) {
+ $maxstr .= '言'; // random long string that should fix exactly the limit for one char column
+ }
+
+ $table = new xmldb_table('testtable');
+ $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+ $table->add_field('name', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL, null);
+ $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+ $table->add_index('name', XMLDB_INDEX_NOTUNIQUE, array('name'));
+
+ // Drop if exists
+ if ($dbman->table_exists($table)) {
+ $dbman->drop_table($table);
+ }
+ $dbman->create_table($table);
+ $tablename = $table->getName();
+ $this->tables[$tablename] = $table;
+
+ $rec = new stdClass();
+ $rec->name = $maxstr;
+
+ $id = $DB->insert_record($tablename, $rec);
+ $this->assertTrue(!empty($id));
+
+ $rec = $DB->get_record($tablename, array('id'=>$id));
+ $this->assertIdentical($rec->name, $maxstr);
+
+ $dbman->drop_table($table);
+
+
+ $table = new xmldb_table('testtable');
+ $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+ $table->add_field('name', XMLDB_TYPE_CHAR, 255+1, null, XMLDB_NOTNULL, null);
+ $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+ $table->add_index('name', XMLDB_INDEX_NOTUNIQUE, array('name'));
+
+ try {
+ $dbman->create_table($table);
+ $this->assertTrue(false);
+ } catch (Exception $e) {
+ $this->assertTrue($e instanceof coding_exception);
+ }
+ }
+
+ public function test_index_composed_max_bytes() {
+ $DB = $this->tdb;
+ $dbman = $DB->get_manager();
+
+ $maxstr = '';
+ for($i=0; $i<200; $i++) {
+ $maxstr .= '言';
+ }
+ $reststr = '';
+ for($i=0; $i<133; $i++) {
+ $reststr .= '言';
+ }
+
+ $table = new xmldb_table('testtable');
+ $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+ $table->add_field('name1', XMLDB_TYPE_CHAR, 200, null, XMLDB_NOTNULL, null);
+ $table->add_field('name2', XMLDB_TYPE_CHAR, 133, null, XMLDB_NOTNULL, null);
+ $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+ $table->add_index('name1-name2', XMLDB_INDEX_NOTUNIQUE, array('name1','name2'));
+
+ // Drop if exists
+ if ($dbman->table_exists($table)) {
+ $dbman->drop_table($table);
+ }
+ $dbman->create_table($table);
+ $tablename = $table->getName();
+ $this->tables[$tablename] = $table;
+
+ $rec = new stdClass();
+ $rec->name1 = $maxstr;
+ $rec->name2 = $reststr;
+
+ $id = $DB->insert_record($tablename, $rec);
+ $this->assertTrue(!empty($id));
+
+ $rec = $DB->get_record($tablename, array('id'=>$id));
+ $this->assertIdentical($rec->name1, $maxstr);
+ $this->assertIdentical($rec->name2, $reststr);
+
+
+ $table = new xmldb_table('testtable');
+ $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+ $table->add_field('name1', XMLDB_TYPE_CHAR, 201, null, XMLDB_NOTNULL, null);
+ $table->add_field('name2', XMLDB_TYPE_CHAR, 133, null, XMLDB_NOTNULL, null);
+ $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+ $table->add_index('name1-name2', XMLDB_INDEX_NOTUNIQUE, array('name1','name2'));
+
+ // Drop if exists
+ if ($dbman->table_exists($table)) {
+ $dbman->drop_table($table);
+ }
+
+ try {
+ $dbman->create_table($table);
+ $this->assertTrue(false);
+ } catch (Exception $e) {
+ $this->assertTrue($e instanceof coding_exception);
+ }
+ }
+
// Following methods are not supported == Do not test
/*
public function testRenameIndex() {
var $unique;
var $fields;
+ /**
+ * Note:
+ * - MySQL: MyISAM has a limit of 1000 bytes for any key including composed, InnoDB has limit 3500 bytes.
+ *
+ * @const max length of composed indexes, one utf-8 char is 3 bytes in the worst case
+ */
+ const INDEX_COMPOSED_MAX_BYTES = 999;
+
+ /**
+ * Note:
+ * - MySQL: InnoDB limits size of index on single column to 767bytes (256 chars)
+ *
+ * @const single column index length limit, one utf-8 char is 3 bytes in the worst case
+ */
+ const INDEX_MAX_BYTES = 765;
+
/**
* Creates one new xmldb_index
*/
return $o;
}
+
+ /**
+ * Validates the index restrictions.
+ *
+ * The error message should not be localised because it is intended for developers,
+ * end users and admins should never see these problems!
+ *
+ * @param xmldb_table $xmldb_table optional when object is table
+ * @return string null if ok, error message if problem found
+ */
+ function validateDefinition(xmldb_table $xmldb_table=null) {
+ if (!$xmldb_table) {
+ return 'Invalid xmldb_index->validateDefinition() call, $xmldb_table si required.';
+ }
+
+ $total = 0;
+ foreach ($this->getFields() as $fieldname) {
+ if (!$field = $xmldb_table->getField($fieldname)) {
+ // argh, we do not have the fields loaded yet, this should not happen during install
+ continue;
+ }
+
+ switch ($field->getType()) {
+ case XMLDB_TYPE_INTEGER:
+ $total += 8; // big int
+ break;
+
+ case XMLDB_TYPE_NUMBER:
+ $total += 12; // this is just a guess
+ break;
+
+ case XMLDB_TYPE_FLOAT:
+ $total += 8; // double precision
+ break;
+
+ case XMLDB_TYPE_CHAR:
+ if ($field->getLength() > self::INDEX_MAX_BYTES / 3) {
+ return 'Invalid index definition in table {'.$xmldb_table->getName(). '}: XMLDB_TYPE_CHAR field "'.$field->getName().'" can not be indexed because it is too long.'
+ .' Limit is '.(self::INDEX_MAX_BYTES/3).' chars.';
+ }
+ $total += ($field->getLength() * 3); // the most complex utf-8 chars have 3 bytes
+ break;
+
+ case XMLDB_TYPE_TEXT:
+ return 'Invalid index definition in table {'.$xmldb_table->getName(). '}: XMLDB_TYPE_TEXT field "'.$field->getName().'" can not be indexed';
+ break;
+
+ case XMLDB_TYPE_BINARY:
+ return 'Invalid index definition in table {'.$xmldb_table->getName(). '}: XMLDB_TYPE_BINARY field "'.$field->getName().'" can not be indexed';
+ break;
+
+ case XMLDB_TYPE_DATETIME:
+ $total += 8; // this is just a guess
+ break;
+
+ case XMLDB_TYPE_TIMESTAMP:
+ $total += 8; // this is just a guess
+ break;
+ }
+ }
+
+ if ($total > self::INDEX_COMPOSED_MAX_BYTES) {
+ return 'Invalid index definition in table {'.$xmldb_table->getName(). '}: the composed index on fields "'.implode(',', $this->getFields()).'" is too long.'
+ .' Limit is '.self::INDEX_COMPOSED_MAX_BYTES.' bytes / '.(self::INDEX_COMPOSED_MAX_BYTES/3).' chars.';
+ }
+
+ return null;
+ }
+
}
/// TODO: Delete for 2.1 (deprecated in 2.0).