From 91496d15bc4e28a07c012b2e903a58d8a7b60a75 Mon Sep 17 00:00:00 2001 From: stronk7 Date: Wed, 16 Aug 2006 17:28:41 +0000 Subject: [PATCH] Initial commit of the base generator class. --- .../generators/XMLDBGenerator.class.php | 473 ++++++++++++++++++ 1 file changed, 473 insertions(+) create mode 100644 lib/xmldb/classes/generators/XMLDBGenerator.class.php diff --git a/lib/xmldb/classes/generators/XMLDBGenerator.class.php b/lib/xmldb/classes/generators/XMLDBGenerator.class.php new file mode 100644 index 00000000000..0926dafebda --- /dev/null +++ b/lib/xmldb/classes/generators/XMLDBGenerator.class.php @@ -0,0 +1,473 @@ +prefix = ''; + $this->reserved_words = $this->getReservedWords(); + } + +/// ALL THESE FUNCTION ARE SHARED BY ALL THE XMLDGenerator classes + + /** + * Set the prefix + */ + function setPrefix($prefix) { + $this->prefix = $prefix; + } + + /** + * Given one correct XMLDBTable, returns the complete SQL lines to create it + */ + function getCreateTableSQL($xmldb_table) { + + /// Table header + $table = 'CREATE TABLE ' . $this->getEncQuoted($this->prefix . $xmldb_table->getName()) . ' ('; + + if (!$xmldb_fields = $xmldb_table->getFields()) { + return false; + } + /// Add the fields, separated by commas + foreach ($xmldb_fields as $xmldb_field) { + $table .= "\n " . $this->getFieldSQL($xmldb_field) . ','; + } + /// Add the keys, separated by commas + if ($xmldb_keys = $xmldb_table->getKeys()) { + foreach ($xmldb_keys as $xmldb_key) { + if ($keytext = $this->getKeySQL($xmldb_table, $xmldb_key)) { + $table .= "\nCONSTRAINT " . $keytext . ','; + } + /// If the key is XMLDB_KEY_FOREIGN_UNIQUE, create it as UNIQUE too + if ($xmldb_key->getType() == XMLDB_KEY_FOREIGN_UNIQUE) { + ///Duplicate the key + $xmldb_key->setType(XMLDB_KEY_UNIQUE); + if ($keytext = $this->getKeySQL($xmldb_table, $xmldb_key)) { + $table .= "\nCONSTRAINT " . $keytext . ','; + } + } + } + } + /// Add enum extra code if needed + if ($this->enum_extra_code) { + /// Iterate over fields looking for sequences + foreach ($xmldb_fields as $xmldb_field) { + if ($xmldb_field->getEnum()) { + $table .= "\n" . $this->getEnumExtraSQL($xmldb_table, $xmldb_field) . ','; + } + } + } + /// Table footer, trim the latest comma + $table = trim($table,','); + $table .= "\n)"; + + /// Add comments if specified + if ($this->add_table_comments) { + $table .= $this->getCommentSQL ($xmldb_table) . "\n"; + } + /// Add the indexes (each one, one statement) + $indexcombs = array(); //To store all the key combinations used + if ($xmldb_indexes = $xmldb_table->getIndexes()) { + foreach ($xmldb_indexes as $xmldb_index) { + $fieldsarr = $xmldb_index->getFields(); + sort ($fieldsarr); + $currentcomb = strtolower(implode('-', $fieldsarr)); + if ($indextext = $this->getCreateIndexSQL($xmldb_table, $xmldb_index)) { + /// Only create the index if the combination hasn't been used before + if (!in_array($currentcomb, $indexcombs)) { + $table .= "\n" . $indextext; + } + } + /// Add the index to the array of used combinations + $indexcombs[] = $currentcomb; + } + } + /// Also, add the indexes needed from keys, based on configuration (each one, one statement) + if ($xmldb_keys = $xmldb_table->getKeys()) { + foreach ($xmldb_keys as $xmldb_key) { + $index = null; + switch ($xmldb_key->getType()) { + case XMLDB_KEY_PRIMARY: + if ($this->primary_index) { + $index = new XMLDBIndex('temp_index'); + $index->setUnique(true); + $index->setFields($xmldb_key->getFields()); + } + break; + case XMLDB_KEY_UNIQUE: + case XMLDB_KEY_FOREIGN_UNIQUE: + if ($this->unique_index) { + $index = new XMLDBIndex('temp_index'); + $index->setUnique(true); + $index->setFields($xmldb_key->getFields()); + } + break; + case XMLDB_KEY_FOREIGN: + if ($this->foreign_index) { + $index = new XMLDBIndex('temp_index'); + $index->setUnique(false); + $index->setFields($xmldb_key->getFields()); + } + break; + } + if ($index) { + if ($indextext = $this->getCreateIndexSQL($xmldb_table, $index)) { + $fieldsarr = $index->getFields(); + sort ($fieldsarr); + $currentcomb = strtolower(implode('-', $fieldsarr)); + /// Only create the index if the combination hasn't been used before + if (!in_array($currentcomb, $indexcombs)) { + $table .= "\n" . $indextext; + } + } + /// Add the index to the array of used combinations + $indexcombs[] = $currentcomb; + } + } + } + + /// Add sequence extra code if needed + if ($this->sequence_extra_code) { + /// Iterate over fields looking for sequences + foreach ($xmldb_fields as $xmldb_field) { + if ($xmldb_field->getSequence()) { + $table .= "\n" . $this->getCreateSequenceSQL($xmldb_table, $xmldb_field); + } + } + } + + return $table; + } + + /** + * Given one correct XMLDBIndex, returns the complete SQL line to create it + */ + function getCreateIndexSQL ($xmldb_table, $xmldb_index) { + + $unique = ''; + $suffix = 'ix'; + if ($xmldb_index->getUnique()) { + $unique = ' UNIQUE'; + $suffix = 'uix'; + } + + $index = 'CREATE' . $unique . ' INDEX '; + $index .= $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_index->getFields()), $suffix); + $index .= ' ON ' . $this->prefix . $this->getEncQuoted($xmldb_table->getName()); + $index .= ' (' . implode(', ', $this->getEncQuoted($xmldb_index->getFields())) . ');'; + + return $index; + } + + /** + * Given one correct XMLDBField, returns the complete SQL line to create it + */ + function getFieldSQL($xmldb_field) { + + /// First of all, convert integers to numbers if defined + if ($this->integer_to_number) { + if ($xmldb_field->getType() == XMLDB_TYPE_INTEGER) { + $xmldb_field->setType(XMLDB_TYPE_NUMBER); + } + } + /// Same for floats + if ($this->float_to_number) { + if ($xmldb_field->getType() == XMLDB_TYPE_FLOAT) { + $xmldb_field->setType(XMLDB_TYPE_NUMBER); + } + } + + /// The name + $field = $this->getEncQuoted($xmldb_field->getName()); + /// The type and length (if the field isn't enum) + if (!$xmldb_field->getEnum()) { + $field .= ' ' . $this->getTypeSQL($xmldb_field->getType(), $xmldb_field->getLength(), $xmldb_field->getDecimals()); + } else { + /// call to custom function + $field .= ' ' . $this->getEnumSQL($xmldb_field); + } + /// The unsigned if supported + if ($this->unsigned_allowed && ($xmldb_field->getType() == XMLDB_TYPE_INTEGER || + $xmldb_field->getType() == XMLDB_TYPE_NUMBER || + $xmldb_field->getType() == XMLDB_TYPE_FLOAT)) { + if ($xmldb_field->getUnsigned()) { + $field .= ' unsigned'; + } + } + /// The not null + if ($xmldb_field->getNotNull()) { + $field .= ' NOT NULL'; + } + /// The sequence + if ($xmldb_field->getSequence()) { + $field .= ' ' . $this->sequence_name; + if ($this->sequence_only) { + /// We only want the field name and sequence name to be printed + /// so, calculate it and return + return $this->getEncQuoted($xmldb_field->getName()) . ' ' . $this->sequence_name; + } + } + /// The default + if ($xmldb_field->getDefault() != NULL) { + $field .= ' default '; + if ($xmldb_field->getType() == XMLDB_TYPE_CHAR || + $xmldb_field->getType() == XMLDB_TYPE_TEXT) { + $field .= "'" . $xmldb_field->getDefault() . "'"; + } else { + $field .= $xmldb_field->getDefault(); + } + } else { + /// We force default '' for not null char columns without proper default + /// some day this should be out! + if ($this->default_for_char !== NULL && + $xmldb_field->getType() == XMLDB_TYPE_CHAR && + $xmldb_field->getNotNull()) { + $field .= ' default ' . "'" . $this->default_for_char . "'"; + } + } + return $field; + } + + /** + * Given one correct XMLDBKey, returns its specs + */ + function getKeySQL ($xmldb_table, $xmldb_key) { + + $key = ''; + + switch ($xmldb_key->getType()) { + case XMLDB_KEY_PRIMARY: + if ($this->primary_keys) { + if ($this->primary_key_name !== null) { + $key = $this->primary_key_name; + } else { + $key = $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_key->getFields()), 'pk'); + } + $key .= ' PRIMARY KEY (' . implode(', ', $this->getEncQuoted($xmldb_key->getFields())) . ')'; + } + break; + case XMLDB_KEY_UNIQUE: + if ($this->unique_keys) { + $key = $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_key->getFields()), 'uk'); + $key .= ' UNIQUE KEY (' . implode(', ', $this->getEncQuoted($xmldb_key->getFields())) . ')'; + } + break; + case XMLDB_KEY_FOREIGN: + case XMLDB_KEY_FOREIGN_UNIQUE: + if ($this->foreign_keys) { + $key = $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_key->getFields()), 'fk'); + $key .= ' FOREIGN KEY (' . implode(', ', $this->getEncQuoted($xmldb_key->getFields())) . ')'; + $key .= ' REFERENCES ' . $this->getEncQuoted($xmldb_key->getRefTable()); + $key .= ' (' . implode(', ', $this->getEncQuoted($xmldb_key->getRefFields())) . ')'; + } + break; + } + + return $key; + } + + /** + * Given three strings (table name, list of fields (comma separated) and suffix), create the proper object name + */ + function getNameForObject($tablename, $fields, $suffix) { + + $name = ''; + + /// Implement one basic cache to avoid object name duplication + if (!isset($used_names)) { + static $used_names = array(); + } + + /// Use standard naming. See http://docs.moodle.org/en/XMLDB_key_and_index_naming + $tablearr = explode ('_', $tablename); + foreach ($tablearr as $table) { + $name .= substr(trim($table),0,3); + } + $name .= '_'; + $fieldsarr = explode (',', $fields); + foreach ($fieldsarr as $field) { + $name .= substr(trim($field),0,3); + } + /// Prepend the prefix if required + if ($this->prefix_on_names) { + $name = $this->prefix . $name; + } + $name = substr(trim($name), 0, $this->names_max_length - 1 - strlen($suffix)); //Max names_max_length + + /// Add the suffix + $namewithsuffix = $name . '_' . $suffix; + + /// If the calculated name is in the cache, let's modify if + if (in_array($namewithsuffix, $used_names)) { + $counter = 2; + /// If have free space, we add 2 + if (strlen($namewithsuffix) < 30) { + $newname = $name . $counter; + /// Else replace the last char by 2 + } else { + $newname = substr($name, 0, strlen($name)-1) . $counter; + } + $newnamewithsuffix = $newname . '_' . $suffix; + /// Now iterate until not used name is found, incrementing the counter + while (in_array($newnamewithsuffix, $used_names)) { + $newname = substr($name, 0, strlen($newname)-1) . $counter; + $newnamewithsuffix = $newname . '_' . $suffix; + $counter++; + } + $namewithsuffix = $newnamewithsuffix; + } + + /// Add the name to the cache + $used_names[] = $namewithsuffix; + + return $namewithsuffix; + } + + /** + * Given any string (or one array), enclose it by the proper quotes + */ + function getEncQuoted($input) { + + if (is_array($input)) { + foreach ($input as $key=>$content) { + $input[$key] = $this->getEncQuoted($content); + } + return $input; + } else { + /// Always lowercase + $input = strtolower($input); + /// if reserved or quote_all, quote it + if ($this->quote_all || in_array($input, $this->reserved_words)) { + $input = $this->quote_string . $input . $this->quote_string; + } + return $input; + } + } + +/// ALL THESE FUNCTION MUST BE CUSTOMISED BY ALL THE XMLDGenerator classes + + /** + * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type + */ + function getTypeSQL ($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) { + return 'code for type(precision) goes to function getTypeSQL()'; + } + + /** + * Given one XMLDB Field, return its enum SQL + */ + function getEnumSQL ($xmldb_field) { + return 'code for inline enum declaration goes to function getEnumSQL()'; + } + + /** + * Returns the code needed to create one enum for the xmldb_table and xmldb_field passes + */ + function getEnumExtraSQL ($xmldb_table, $xmldb_field) { + return 'Code for extra enum SQL goes to getEnumExtraSQL(). Can be disabled with enum_extra_code=false'; + } + + /** + * Returns the code needed to create one sequence for the xmldb_table and xmldb_field passes + */ + function getCreateSequenceSQL ($xmldb_table, $xmldb_field) { + return 'Code for extra sequence SQL goes to getCreateSequenceSQL(). Can be disabled with sequence_extra_code=false'; + } + + /** + * Returns the code needed to add one comment to the table + */ + function getCommentSQL ($xmldb_table) { + return 'Code for table comment goes to getCommentSQL(). Can be disabled with add_table_comments=false;'; + } + + /** + * Returns an array of reserved words (lowercase) for this DB + * You MUST provide the real list for each DB inside every XMLDB class + */ + function getReservedWords() { + /// Some wel-know reserved words + $reserved_words = array ( + 'user', 'scale', 'type', 'comment' + ); + return $reserved_words; + } +} + +?>