Initial commit on HEAD of all the XMLDB stuff.
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
<?php // $Id$
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// NOTICE OF COPYRIGHT //
|
||||
// //
|
||||
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
|
||||
// http://moodle.com //
|
||||
// //
|
||||
// Copyright (C) 2001-3001 Martin Dougiamas http://dougiamas.com //
|
||||
// (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details: //
|
||||
// //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// This file contains all the constants and variables used
|
||||
/// by the XMLDB interface
|
||||
|
||||
/// First, some constants to be used by actions
|
||||
define('ACTION_NONE', 0); //Default flags for class
|
||||
define('ACTION_GENERATE_HTML', 1); //The invoke function will return HTML
|
||||
define('ACTION_GENERATE_XML', 2); //The invoke function will return HTML
|
||||
define('ACTION_HAVE_SUBACTIONS', 1); //The class can have subaction
|
||||
|
||||
/// Now the allowed DB Field Types
|
||||
define ('XMLDB_TYPE_INCORRECT', 0); //Wrong DB Type
|
||||
define ('XMLDB_TYPE_INTEGER', 1); //Integer
|
||||
define ('XMLDB_TYPE_NUMBER', 2); //Decimal number
|
||||
define ('XMLDB_TYPE_FLOAT', 3); //Floating Point number
|
||||
define ('XMLDB_TYPE_CHAR', 4); //String
|
||||
define ('XMLDB_TYPE_TEXT', 5); //Text
|
||||
define ('XMLDB_TYPE_BINARY', 6); //Binary
|
||||
define ('XMLDB_TYPE_DATETIME', 7); //Datetime
|
||||
define ('XMLDB_TYPE_TIMESTAMP', 8); //Timestamp
|
||||
|
||||
/// Now the allowed DB Keys
|
||||
define ('XMLDB_KEY_INCORRECT', 0); //Wrong DB Key
|
||||
define ('XMLDB_KEY_PRIMARY', 1); //Primary Keys
|
||||
define ('XMLDB_KEY_UNIQUE', 2); //Unique Keys
|
||||
define ('XMLDB_KEY_FOREIGN', 3); //Foreign Keys
|
||||
define ('XMLDB_KEY_CHECK', 4); //Check Constraints - NOT USED!
|
||||
define ('XMLDB_KEY_FOREIGN_UNIQUE',5); //Foreign Key + Unique Key
|
||||
|
||||
/// Now the allowed Statement Types
|
||||
define ('XMLDB_STATEMENT_INCORRECT', 0); //Wrong Statement Type
|
||||
define ('XMLDB_STATEMENT_INSERT', 1); //Insert Statements
|
||||
define ('XMLDB_STATEMENT_UPDATE', 2); //Update Statements
|
||||
define ('XMLDB_STATEMENT_DELETE', 3); //Delete Statements
|
||||
define ('XMLDB_STATEMENT_CUSTOM', 4); //Custom Statements
|
||||
|
||||
/// Some other useful Constants
|
||||
define ('XMLDB_UNSIGNED', true); //If the field is going to be unsigned
|
||||
define ('XMLDB_NOTNULL', true); //If the field is going to be not null
|
||||
define ('XMLDB_SEQUENCE', true); //If the field is going to be a sequence
|
||||
define ('XMLDB_ENUM', true); //If the field is going to be a enumeration of possible fields
|
||||
define ('XMLDB_INDEX_UNIQUE', true); //If the index is going to be unique
|
||||
define ('XMLDB_INDEX_NOTUNIQUE',false); //If the index is NOT going to be unique
|
||||
?>
|
||||
@@ -0,0 +1,733 @@
|
||||
<?php // $Id$
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// NOTICE OF COPYRIGHT //
|
||||
// //
|
||||
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
|
||||
// http://moodle.com //
|
||||
// //
|
||||
// Copyright (C) 2001-3001 Martin Dougiamas http://dougiamas.com //
|
||||
// (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details: //
|
||||
// //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// This class represent one XMLDB Field
|
||||
|
||||
class XMLDBField extends XMLDBObject {
|
||||
|
||||
var $type;
|
||||
var $length;
|
||||
var $unsigned;
|
||||
var $notnull;
|
||||
var $default;
|
||||
var $sequence;
|
||||
var $enum;
|
||||
var $enumvalues;
|
||||
var $decimals;
|
||||
|
||||
/**
|
||||
* Creates one new XMLDBField
|
||||
*/
|
||||
function XMLDBField($name) {
|
||||
parent::XMLDBObject($name);
|
||||
$this->type = NULL;
|
||||
$this->length = NULL;
|
||||
$this->unsigned = false;
|
||||
$this->notnull = false;
|
||||
$this->default = NULL;
|
||||
$this->sequence = false;
|
||||
$this->enum = false;
|
||||
$this->enumvalues = NULL;
|
||||
$this->decimals = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type
|
||||
*/
|
||||
function getType() {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the length
|
||||
*/
|
||||
function getLength() {
|
||||
return $this->length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the decimals
|
||||
*/
|
||||
function getDecimals() {
|
||||
return $this->decimals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notnull
|
||||
*/
|
||||
function getNotNull() {
|
||||
return $this->notnull;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unsigned
|
||||
*/
|
||||
function getUnsigned() {
|
||||
return $this->unsigned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sequence
|
||||
*/
|
||||
function getSequence() {
|
||||
return $this->sequence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the enum
|
||||
*/
|
||||
function getEnum() {
|
||||
return $this->enum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the enumvalues
|
||||
*/
|
||||
function getEnumValues() {
|
||||
return $this->enumvalues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default
|
||||
*/
|
||||
function getDefault() {
|
||||
return $this->default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the field type
|
||||
*/
|
||||
function setType($type) {
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the field length
|
||||
*/
|
||||
function setLength($length) {
|
||||
$this->length = $length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the field decimals
|
||||
*/
|
||||
function setDecimals($decimals) {
|
||||
$this->decimals = $decimals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the field unsigned
|
||||
*/
|
||||
function setUnsigned($unsigned=true) {
|
||||
$this->unsigned = $unsigned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the field notnull
|
||||
*/
|
||||
function setNotNull($notnull=true) {
|
||||
$this->notnull = $notnull;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the field sequence
|
||||
*/
|
||||
function setSequence($sequence=true) {
|
||||
$this->sequence = $sequence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the field enum
|
||||
*/
|
||||
function setEnum($enum=true) {
|
||||
$this->enum = $enum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the field enumvalues
|
||||
*/
|
||||
function setEnumValues($enumvalues) {
|
||||
$this->enumvalues = $enumvalues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the field default
|
||||
*/
|
||||
function setDefault($default) {
|
||||
$this->default = $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load data from XML to the table
|
||||
*/
|
||||
function arr2XMLDBField($xmlarr) {
|
||||
|
||||
$result = true;
|
||||
|
||||
/// Debug the table
|
||||
/// traverse_xmlize($xmlarr); //Debug
|
||||
/// print_object ($GLOBALS['traverse_array']); //Debug
|
||||
/// $GLOBALS['traverse_array']=""; //Debug
|
||||
|
||||
/// Process table attributes (name, type, length, unsigned,
|
||||
/// notnull, sequence, enum, enumvalues, decimals, comment,
|
||||
/// previous, next)
|
||||
if (isset($xmlarr['@']['NAME'])) {
|
||||
$this->name = trim($xmlarr['@']['NAME']);
|
||||
} else {
|
||||
$this->errormsg = 'Missing NAME attribute';
|
||||
$result = false;
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['TYPE'])) {
|
||||
/// Check for valid type
|
||||
$type = $this->getXMLDBFieldType(trim($xmlarr['@']['TYPE']));
|
||||
if ($type) {
|
||||
$this->type = $type;
|
||||
} else {
|
||||
$this->errormsg = 'Invalid TYPE attribute';
|
||||
$result = false;
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Missing TYPE attribute';
|
||||
$result = false;
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['LENGTH'])) {
|
||||
$length = trim($xmlarr['@']['LENGTH']);
|
||||
/// Check for integer values
|
||||
if ($this->type == XMLDB_TYPE_INTEGER ||
|
||||
$this->type == XMLDB_TYPE_NUMBER ||
|
||||
$this->type == XMLDB_TYPE_CHAR) {
|
||||
if (!(is_numeric($length)&&(intval($length)==floatval($length)))) {
|
||||
$this->errormsg = 'Incorrect LENGTH attribute for int, number or char fields';
|
||||
$result = false;
|
||||
} else if (!$length) {
|
||||
$this->errormsg = 'Zero LENGTH attribute';
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
/// Check for big, medium, small to be applied to text and binary
|
||||
if ($this->type == XMLDB_TYPE_TEXT ||
|
||||
$this->type == XMLDB_TYPE_BINARY) {
|
||||
if (!$length) {
|
||||
$length == 'big';
|
||||
}
|
||||
if ($length != 'big' &&
|
||||
$length != 'medium' &&
|
||||
$length != 'small') {
|
||||
$this->errormsg = 'Incorrect LENGTH attribute for text and binary fields (only big, medium and small allowed)';
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
/// Finally, set the length
|
||||
$this->length = $length;
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['UNSIGNED'])) {
|
||||
$unsigned = strtolower(trim($xmlarr['@']['UNSIGNED']));
|
||||
if ($unsigned == 'true') {
|
||||
$this->unsigned = true;
|
||||
} else if ($unsigned == 'false') {
|
||||
$this->unsigned = false;
|
||||
} else {
|
||||
$this->errormsg = 'Incorrect UNSIGNED attribute (true/false allowed)';
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['NOTNULL'])) {
|
||||
$notnull = strtolower(trim($xmlarr['@']['NOTNULL']));
|
||||
if ($notnull == 'true') {
|
||||
$this->notnull = true;
|
||||
} else if ($notnull == 'false') {
|
||||
$this->notnull = false;
|
||||
} else {
|
||||
$this->errormsg = 'Incorrect NOTNULL attribute (true/false allowed)';
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['SEQUENCE'])) {
|
||||
$sequence = strtolower(trim($xmlarr['@']['SEQUENCE']));
|
||||
if ($sequence == 'true') {
|
||||
$this->sequence = true;
|
||||
} else if ($sequence == 'false') {
|
||||
$this->sequence = false;
|
||||
} else {
|
||||
$this->errormsg = 'Incorrect SEQUENCE attribute (true/false allowed)';
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['DEFAULT'])) {
|
||||
$this->default = trim($xmlarr['@']['DEFAULT']);
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['ENUM'])) {
|
||||
$enum = strtolower(trim($xmlarr['@']['ENUM']));
|
||||
if ($enum == 'true') {
|
||||
$this->enum = true;
|
||||
} else if ($enum == 'false') {
|
||||
$this->enum = false;
|
||||
} else {
|
||||
$this->errormsg = 'Incorrect ENUM attribute (true/false allowed)';
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['ENUMVALUES'])) {
|
||||
$enumvalues = strtolower(trim($xmlarr['@']['ENUMVALUES']));
|
||||
if (!$this->enum) {
|
||||
$this->errormsg = 'Wrong ENUMVALUES attribute (not ENUM)';
|
||||
$result = false;
|
||||
$this->enumvalues = $enumvalues;
|
||||
} else {
|
||||
/// Check we have a valid list (comma separated of quoted values)
|
||||
$enumarr = explode(',',$enumvalues);
|
||||
if ($enumarr) {
|
||||
foreach ($enumarr as $key => $enumelement) {
|
||||
/// Clear some spaces
|
||||
$enumarr[$key] = trim($enumelement);
|
||||
$enumelement = trim($enumelement);
|
||||
/// Skip if under error
|
||||
if (!$result) {
|
||||
continue;
|
||||
}
|
||||
/// Look for quoted strings
|
||||
if (substr($enumelement, 0, 1) != "'" ||
|
||||
substr($enumelement, -1, 1) != "'") {
|
||||
$this->errormsg = 'Incorrect ENUMVALUES attribute (some value is not properly quoted)';
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Incorrect ENUMVALUES attribute (comma separated of quoted values)';
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
} else if ($this->enum) {
|
||||
$this->errormsg = 'Incorrect ENUMVALUES attribute (field is not declared as ENUM)';
|
||||
$result = false;
|
||||
}
|
||||
/// Finally, set the value
|
||||
if ($this->enum) {
|
||||
$this->enumvalues = $enumarr;
|
||||
}
|
||||
|
||||
$decimals = NULL;
|
||||
if (isset($xmlarr['@']['DECIMALS'])) {
|
||||
$decimals = trim($xmlarr['@']['DECIMALS']);
|
||||
/// Check for integer values
|
||||
if ($this->type == XMLDB_TYPE_NUMBER ||
|
||||
$this->type == XMLDB_TYPE_FLOAT) {
|
||||
if (!(is_numeric($decimals)&&(intval($decimals)==floatval($decimals)))) {
|
||||
$this->errormsg = 'Incorrect DECIMALS attribute for number field';
|
||||
$result = false;
|
||||
} else if ($this->length <= $decimals){
|
||||
$this->errormsg = 'Incorrect DECIMALS attribute (bigget than length)';
|
||||
$result = false;
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Incorrect DECIMALS attribute for non-number field';
|
||||
$result = false;
|
||||
}
|
||||
} else {
|
||||
if ($this->type == XMLDB_TYPE_NUMBER) {
|
||||
$decimals = 0;
|
||||
}
|
||||
}
|
||||
// Finally, set the decimals
|
||||
if ($this->type == XMLDB_TYPE_NUMBER ||
|
||||
$this->type == XMLDB_TYPE_FLOAT) {
|
||||
$this->decimals = $decimals;
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['COMMENT'])) {
|
||||
$this->comment = trim($xmlarr['@']['COMMENT']);
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['PREVIOUS'])) {
|
||||
$this->previous = trim($xmlarr['@']['PREVIOUS']);
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['NEXT'])) {
|
||||
$this->next = trim($xmlarr['@']['NEXT']);
|
||||
}
|
||||
|
||||
/// Set some attributes
|
||||
if ($result) {
|
||||
$this->loaded = true;
|
||||
}
|
||||
$this->calculateHash();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the correct XMLDB_TYPE_XXX value for the
|
||||
* string passed as argument
|
||||
*/
|
||||
function getXMLDBFieldType($type) {
|
||||
|
||||
$result = XMLDB_TYPE_INCORRECT;
|
||||
|
||||
switch (strtolower($type)) {
|
||||
case 'int':
|
||||
$result = XMLDB_TYPE_INTEGER;
|
||||
break;
|
||||
case 'number':
|
||||
$result = XMLDB_TYPE_NUMBER;
|
||||
break;
|
||||
case 'float':
|
||||
$result = XMLDB_TYPE_FLOAT;
|
||||
break;
|
||||
case 'char':
|
||||
$result = XMLDB_TYPE_CHAR;
|
||||
break;
|
||||
case 'text':
|
||||
$result = XMLDB_TYPE_TEXT;
|
||||
break;
|
||||
case 'binary':
|
||||
$result = XMLDB_TYPE_BINARY;
|
||||
break;
|
||||
case 'datetime':
|
||||
$result = XMLDB_TYPE_DATETIME;
|
||||
break;
|
||||
}
|
||||
/// Return the normalized XMLDB_TYPE
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the correct name value for the
|
||||
* XMLDB_TYPE_XXX passed as argument
|
||||
*/
|
||||
function getXMLDBTypeName($type) {
|
||||
|
||||
$result = "";
|
||||
|
||||
switch (strtolower($type)) {
|
||||
case XMLDB_TYPE_INTEGER:
|
||||
$result = 'int';
|
||||
break;
|
||||
case XMLDB_TYPE_NUMBER:
|
||||
$result = 'number';
|
||||
break;
|
||||
case XMLDB_TYPE_FLOAT:
|
||||
$result = 'float';
|
||||
break;
|
||||
case XMLDB_TYPE_CHAR:
|
||||
$result = 'char';
|
||||
break;
|
||||
case XMLDB_TYPE_TEXT:
|
||||
$result = 'text';
|
||||
break;
|
||||
case XMLDB_TYPE_BINARY:
|
||||
$result = 'binary';
|
||||
break;
|
||||
case XMLDB_TYPE_DATETIME:
|
||||
$result = 'datetime';
|
||||
break;
|
||||
}
|
||||
/// Return the normalized name
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function calculate and set the hash of one XMLDBField
|
||||
*/
|
||||
function calculateHash($recursive = false) {
|
||||
if (!$this->loaded) {
|
||||
$this->hash = NULL;
|
||||
} else {
|
||||
$key = $this->name . $this->type . $this->length .
|
||||
$this->unsigned . $this->notnull . $this->sequence .
|
||||
$this->decimals . $this->comment;
|
||||
if ($this->enum) {
|
||||
$key .= implode(', ',$this->enumvalues);
|
||||
}
|
||||
$this->hash = md5($key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*This function will output the XML text for one field
|
||||
*/
|
||||
function xmlOutput() {
|
||||
$o = '';
|
||||
$o.= ' <FIELD NAME="' . $this->name . '"';
|
||||
$o.= ' TYPE="' . $this->getXMLDBTypeName($this->type) . '"';
|
||||
if ($this->length) {
|
||||
$o.= ' LENGTH="' . $this->length . '"';
|
||||
}
|
||||
if ($this->notnull) {
|
||||
$notnull = 'true';
|
||||
} else {
|
||||
$notnull = 'false';
|
||||
}
|
||||
$o.= ' NOTNULL="' . $notnull . '"';
|
||||
if ($this->unsigned) {
|
||||
$unsigned = 'true';
|
||||
} else {
|
||||
$unsigned = 'false';
|
||||
}
|
||||
if ($this->type == XMLDB_TYPE_INTEGER ||
|
||||
$this->type == XMLDB_TYPE_NUMBER ||
|
||||
$this->type == XMLDB_TYPE_FLOAT) {
|
||||
if ($this->unsigned) {
|
||||
$unsigned = 'true';
|
||||
} else {
|
||||
$unsigned = 'false';
|
||||
}
|
||||
$o.= ' UNSIGNED="' . $unsigned . '"';
|
||||
}
|
||||
if (!$this->sequence && $this->default !== NULL) {
|
||||
$o.= ' DEFAULT="' . $this->default . '"';
|
||||
}
|
||||
if ($this->sequence) {
|
||||
$sequence = 'true';
|
||||
} else {
|
||||
$sequence = 'false';
|
||||
}
|
||||
$o.= ' SEQUENCE="' . $sequence . '"';
|
||||
if ($this->enum) {
|
||||
$enum = 'true';
|
||||
} else {
|
||||
$enum = 'false';
|
||||
}
|
||||
$o.= ' ENUM="' . $enum . '"';
|
||||
if ($this->enum) {
|
||||
$o.= ' ENUMVALUES="' . implode(', ', $this->enumvalues) . '"';
|
||||
}
|
||||
if ($this->decimals !== NULL) {
|
||||
$o.= ' DECIMALS="' . $this->decimals . '"';
|
||||
}
|
||||
if ($this->comment) {
|
||||
$o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
|
||||
}
|
||||
if ($this->previous) {
|
||||
$o.= ' PREVIOUS="' . $this->previous . '"';
|
||||
}
|
||||
if ($this->next) {
|
||||
$o.= ' NEXT="' . $this->next . '"';
|
||||
}
|
||||
$o.= '/>' . "\n";
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set all the attributes of the XMLDBField object
|
||||
* based on information passed in one ADOField
|
||||
*/
|
||||
function setFromADOField($adofield) {
|
||||
|
||||
/// Calculate the XMLDB_TYPE
|
||||
switch (strtolower($adofield->type)) {
|
||||
case 'int':
|
||||
case 'tinyint':
|
||||
case 'smallint':
|
||||
case 'bigint':
|
||||
case 'integer':
|
||||
$this->type = XMLDB_TYPE_INTEGER;
|
||||
break;
|
||||
case 'number':
|
||||
case 'decimal':
|
||||
case 'dec':
|
||||
case 'numeric':
|
||||
$this->type = XMLDB_TYPE_NUMBER;
|
||||
break;
|
||||
case 'float':
|
||||
case 'double':
|
||||
$this->type = XMLDB_TYPE_FLOAT;
|
||||
break;
|
||||
case 'char':
|
||||
case 'varchar':
|
||||
case 'enum':
|
||||
$this->type = XMLDB_TYPE_CHAR;
|
||||
break;
|
||||
case 'text':
|
||||
case 'tinytext':
|
||||
case 'mediumtext':
|
||||
case 'longtext':
|
||||
$this->type = XMLDB_TYPE_TEXT;
|
||||
break;
|
||||
case 'blob':
|
||||
case 'tinyblob':
|
||||
case 'mediumblob':
|
||||
case 'longblob':
|
||||
$this->type = XMLDB_TYPE_BINARY;
|
||||
break;
|
||||
case 'datetime':
|
||||
case 'timestamp':
|
||||
$this->type = XMLDB_TYPE_DATETIME;
|
||||
break;
|
||||
default:
|
||||
$this->type = XMLDB_TYPE_TEXT;
|
||||
}
|
||||
/// Calculate the length of the field
|
||||
if ($adofield->max_length > 0 &&
|
||||
($this->type == XMLDB_TYPE_INTEGER ||
|
||||
$this->type == XMLDB_TYPE_NUMBER ||
|
||||
$this->type == XMLDB_TYPE_FLOAT ||
|
||||
$this->type == XMLDB_TYPE_CHAR)) {
|
||||
$this->length = $adofield->max_length;
|
||||
}
|
||||
if ($this->type == XMLDB_TYPE_TEXT) {
|
||||
switch (strtolower($adofield->type)) {
|
||||
case 'tinytext':
|
||||
case 'text':
|
||||
$this->length = 'small';
|
||||
break;
|
||||
case 'mediumtext':
|
||||
$this->length = 'medium';
|
||||
break;
|
||||
case 'longtext':
|
||||
$this->length = 'big';
|
||||
break;
|
||||
default:
|
||||
$this->length = 'small';
|
||||
}
|
||||
}
|
||||
if ($this->type == XMLDB_TYPE_BINARY) {
|
||||
switch (strtolower($adofield->type)) {
|
||||
case 'tinyblob':
|
||||
case 'blob':
|
||||
$this->length = 'small';
|
||||
break;
|
||||
case 'mediumblob':
|
||||
$this->length = 'medium';
|
||||
break;
|
||||
case 'longblob':
|
||||
$this->length = 'big';
|
||||
break;
|
||||
default:
|
||||
$this->length = 'small';
|
||||
}
|
||||
}
|
||||
/// Calculate the decimals of the field
|
||||
if ($adofield->max_length > 0 &&
|
||||
$adofield->scale &&
|
||||
($this->type == XMLDB_TYPE_NUMBER ||
|
||||
$this->type == XMLDB_TYPE_FLOAT)) {
|
||||
$this->decimals = $adofield->scale;
|
||||
}
|
||||
/// Calculate the unsigned field
|
||||
if ($adofield->unsigned &&
|
||||
($this->type == XMLDB_TYPE_INTEGER ||
|
||||
$this->type == XMLDB_TYPE_NUMBER ||
|
||||
$this->type == XMLDB_TYPE_FLOAT)) {
|
||||
$this->unsigned = true;
|
||||
}
|
||||
/// Calculate the notnull field
|
||||
if ($adofield->not_null) {
|
||||
$this->notnull = true;
|
||||
}
|
||||
/// Calculate the default field
|
||||
if ($adofield->has_default) {
|
||||
$this->default = $adofield->default_value;
|
||||
}
|
||||
/// Calculate the sequence field
|
||||
if ($adofield->auto_increment) {
|
||||
$this->sequence = true;
|
||||
/// Sequence fields are always unsigned
|
||||
$this->unsigned = true;
|
||||
}
|
||||
/// Calculate the enum and enumvalues field
|
||||
if ($adofield->type == 'enum') {
|
||||
$this->enum = true;
|
||||
$this->enumvalues = $adofield->enums;
|
||||
}
|
||||
/// Some more fields
|
||||
$this->loaded = true;
|
||||
$this->changed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows info in a readable format
|
||||
*/
|
||||
function readableInfo() {
|
||||
$o = '';
|
||||
/// type
|
||||
$o .= $this->getXMLDBTypeName($this->type);
|
||||
/// length
|
||||
if ($this->type == XMLDB_TYPE_INTEGER ||
|
||||
$this->type == XMLDB_TYPE_NUMBER ||
|
||||
$this->type == XMLDB_TYPE_FLOAT ||
|
||||
$this->type == XMLDB_TYPE_CHAR) {
|
||||
if ($this->length) {
|
||||
$o .= ' (' . $this->length;
|
||||
if ($this->type == XMLDB_TYPE_NUMBER ||
|
||||
$this->type == XMLDB_TYPE_FLOAT) {
|
||||
if ($this->decimals !== NULL) {
|
||||
$o .= ', ' . $this->decimals;
|
||||
}
|
||||
}
|
||||
$o .= ')';
|
||||
}
|
||||
}
|
||||
if ($this->type == XMLDB_TYPE_TEXT ||
|
||||
$this->type == XMLDB_TYPE_BINARY) {
|
||||
$o .= ' (' . $this->length . ')';
|
||||
}
|
||||
/// enum
|
||||
if ($this->enum) {
|
||||
$o .= ' enum(' . implode(', ', $this->enumvalues) . ')';
|
||||
}
|
||||
/// unsigned
|
||||
if ($this->type == XMLDB_TYPE_INTEGER ||
|
||||
$this->type == XMLDB_TYPE_NUMBER ||
|
||||
$this->type == XMLDB_TYPE_FLOAT) {
|
||||
if ($this->unsigned) {
|
||||
$o .= ' unsigned';
|
||||
} else {
|
||||
$o .= ' signed';
|
||||
}
|
||||
}
|
||||
/// not null
|
||||
if ($this->notnull) {
|
||||
$o .= ' not null';
|
||||
}
|
||||
/// default
|
||||
if ($this->default !== NULL) {
|
||||
$o .= ' default ';
|
||||
if ($this->type == XMLDB_TYPE_CHAR ||
|
||||
$this->type == XMLDB_TYPE_TEXT) {
|
||||
$o .= "'" . $this->default . "'";
|
||||
} else {
|
||||
$o .= $this->default;
|
||||
}
|
||||
}
|
||||
/// sequence
|
||||
if ($this->sequence) {
|
||||
$o .= ' auto-numbered';
|
||||
}
|
||||
|
||||
return $o;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php // $Id$
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// NOTICE OF COPYRIGHT //
|
||||
// //
|
||||
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
|
||||
// http://moodle.com //
|
||||
// //
|
||||
// Copyright (C) 2001-3001 Martin Dougiamas http://dougiamas.com //
|
||||
// (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details: //
|
||||
// //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// This class represents an entire XMLDB file
|
||||
|
||||
class XMLDBFile extends XMLDBObject {
|
||||
|
||||
var $path;
|
||||
var $xmldb_structure;
|
||||
|
||||
/**
|
||||
* Constructor of the XMLDBFile
|
||||
*/
|
||||
function XMLDBFile ($path) {
|
||||
parent::XMLDBObject($path);
|
||||
$this->path = $path;
|
||||
$this->xmldb_structure = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the XML file exists
|
||||
*/
|
||||
function fileExists() {
|
||||
if (file_exists($this->path) && is_readable($this->path)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the XML is writeable
|
||||
*/
|
||||
function fileWriteable() {
|
||||
if (is_writeable(dirname($this->path))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function &getStructure() {
|
||||
return $this->xmldb_structure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and the XMLDB structure from file
|
||||
*/
|
||||
function loadXMLStructure() {
|
||||
if ($this->fileExists()) {
|
||||
/// File exists, so let's process it
|
||||
/// Load everything to a big array
|
||||
$xmlarr = xmlize(file_get_contents($this->path));
|
||||
/// Convert array to xmldb structure
|
||||
$this->xmldb_structure = $this->arr2XMLDBStructure($xmlarr);
|
||||
/// Analize results
|
||||
if ($this->xmldb_structure->isLoaded()) {
|
||||
$this->loaded = true;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function takes an xmlized array and put it into one XMLDBStructure
|
||||
*/
|
||||
function arr2XMLDBStructure ($xmlarr) {
|
||||
$structure = new XMLDBStructure($this->path);
|
||||
$structure->arr2XMLDBStructure($xmlarr);
|
||||
return $structure;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function saves the whole XMLDBStructure to its file
|
||||
*/
|
||||
function saveXMLFile() {
|
||||
|
||||
$result = true;
|
||||
|
||||
$structure =& $this->getStructure();
|
||||
|
||||
$result = file_put_contents($this->path, $structure->xmlOutput());
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,221 @@
|
||||
<?php // $Id$
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// NOTICE OF COPYRIGHT //
|
||||
// //
|
||||
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
|
||||
// http://moodle.com //
|
||||
// //
|
||||
// Copyright (C) 2001-3001 Martin Dougiamas http://dougiamas.com //
|
||||
// (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details: //
|
||||
// //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// This class represent one XMLDB Index
|
||||
|
||||
class XMLDBIndex extends XMLDBObject {
|
||||
|
||||
var $unique;
|
||||
var $fields;
|
||||
|
||||
/**
|
||||
* Creates one new XMLDBIndex
|
||||
*/
|
||||
function XMLDBIndex($name) {
|
||||
parent::XMLDBObject($name);
|
||||
$this->unique = false;
|
||||
$this->fields = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index unique
|
||||
*/
|
||||
function getUnique() {
|
||||
return $this->unique;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the index unique
|
||||
*/
|
||||
function setUnique($unique = true) {
|
||||
$this->unique = $unique;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the index fields
|
||||
*/
|
||||
function setFields($fields) {
|
||||
$this->fields = $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index fields
|
||||
*/
|
||||
function &getFields() {
|
||||
return $this->fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load data from XML to the index
|
||||
*/
|
||||
function arr2XMLDBIndex($xmlarr) {
|
||||
|
||||
$result = true;
|
||||
|
||||
/// Debug the table
|
||||
/// traverse_xmlize($xmlarr); //Debug
|
||||
/// print_object ($GLOBALS['traverse_array']); //Debug
|
||||
/// $GLOBALS['traverse_array']=""; //Debug
|
||||
|
||||
/// Process key attributes (name, unique, fields, comment, previous, next)
|
||||
if (isset($xmlarr['@']['NAME'])) {
|
||||
$this->name = trim($xmlarr['@']['NAME']);
|
||||
} else {
|
||||
$this->errormsg = 'Missing NAME attribute';
|
||||
$result = false;
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['UNIQUE'])) {
|
||||
$unique = strtolower(trim($xmlarr['@']['UNIQUE']));
|
||||
if ($unique == 'true') {
|
||||
$this->unique = true;
|
||||
} else if ($unique == 'false') {
|
||||
$this->unique = false;
|
||||
} else {
|
||||
$this->errormsg = 'Incorrect UNIQUE attribute (true/false allowed)';
|
||||
$result = false;
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Undefined UNIQUE attribute';
|
||||
$result = false;
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['FIELDS'])) {
|
||||
$fields = strtolower(trim($xmlarr['@']['FIELDS']));
|
||||
if ($fields) {
|
||||
$fieldsarr = explode(',',$fields);
|
||||
if ($fieldsarr) {
|
||||
foreach ($fieldsarr as $key => $element) {
|
||||
$fieldsarr [$key] = trim($element);
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Incorrect FIELDS attribute (comma separated of fields)';
|
||||
$result = false;
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Empty FIELDS attribute';
|
||||
$result = false;
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Missing FIELDS attribute';
|
||||
$result = false;
|
||||
}
|
||||
/// Finally, set the array of fields
|
||||
$this->fields = $fieldsarr;
|
||||
|
||||
if (isset($xmlarr['@']['COMMENT'])) {
|
||||
$this->comment = trim($xmlarr['@']['COMMENT']);
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['PREVIOUS'])) {
|
||||
$this->previous = trim($xmlarr['@']['PREVIOUS']);
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['NEXT'])) {
|
||||
$this->next = trim($xmlarr['@']['NEXT']);
|
||||
}
|
||||
|
||||
/// Set some attributes
|
||||
if ($result) {
|
||||
$this->loaded = true;
|
||||
}
|
||||
$this->calculateHash();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function calculate and set the hash of one XMLDBIndex
|
||||
*/
|
||||
function calculateHash($recursive = false) {
|
||||
if (!$this->loaded) {
|
||||
$this->hash = NULL;
|
||||
} else {
|
||||
$key = $this->unique . implode (', ', $this->fields);
|
||||
$this->hash = md5($key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*This function will output the XML text for one index
|
||||
*/
|
||||
function xmlOutput() {
|
||||
$o = '';
|
||||
$o.= ' <INDEX NAME="' . $this->name . '"';
|
||||
if ($this->unique) {
|
||||
$unique = 'true';
|
||||
} else {
|
||||
$unique = 'false';
|
||||
}
|
||||
$o.= ' UNIQUE="' . $unique . '"';
|
||||
$o.= ' FIELDS="' . implode(', ', $this->fields) . '"';
|
||||
if ($this->comment) {
|
||||
$o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
|
||||
}
|
||||
if ($this->previous) {
|
||||
$o.= ' PREVIOUS="' . $this->previous . '"';
|
||||
}
|
||||
if ($this->next) {
|
||||
$o.= ' NEXT="' . $this->next . '"';
|
||||
}
|
||||
$o.= '/>' . "\n";
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set all the attributes of the XMLDBIndex object
|
||||
* based on information passed in one ADOindex
|
||||
*/
|
||||
function setFromADOIndex($adoindex) {
|
||||
|
||||
/// Set the unique field
|
||||
$this->unique = false;
|
||||
/// Set the fields
|
||||
$this->fields = $adoindex['columns'];
|
||||
/// Some more fields
|
||||
$this->loaded = true;
|
||||
$this->changed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows info in a readable format
|
||||
*/
|
||||
function readableInfo() {
|
||||
$o = '';
|
||||
/// unique
|
||||
if ($this->unique) {
|
||||
$o .= 'unique';
|
||||
} else {
|
||||
$o .= 'not unique';
|
||||
}
|
||||
/// fields
|
||||
$o .= ' (' . implode(', ', $this->fields) . ')';
|
||||
|
||||
return $o;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,381 @@
|
||||
<?php // $Id$
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// NOTICE OF COPYRIGHT //
|
||||
// //
|
||||
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
|
||||
// http://moodle.com //
|
||||
// //
|
||||
// Copyright (C) 2001-3001 Martin Dougiamas http://dougiamas.com //
|
||||
// (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details: //
|
||||
// //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// This class represent one XMLDB Key
|
||||
|
||||
class XMLDBKey extends XMLDBObject {
|
||||
|
||||
var $type;
|
||||
var $fields;
|
||||
var $reftable;
|
||||
var $reffields;
|
||||
|
||||
/**
|
||||
* Creates one new XMLDBKey
|
||||
*/
|
||||
function XMLDBKey($name) {
|
||||
parent::XMLDBObject($name);
|
||||
$this->type = NULL;
|
||||
$this->fields = array();
|
||||
$this->reftable = NULL;
|
||||
$this->reffields = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key type
|
||||
*/
|
||||
function getType() {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the key type
|
||||
*/
|
||||
function setType($type) {
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the key fields
|
||||
*/
|
||||
function setFields($fields) {
|
||||
$this->fields = $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the key reftable
|
||||
*/
|
||||
function setRefTable($reftable) {
|
||||
$this->reftable = $reftable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the key reffields
|
||||
*/
|
||||
function setRefFields($reffields) {
|
||||
$this->reffields = $reffields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key fields
|
||||
*/
|
||||
function &getFields() {
|
||||
return $this->fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key reftable
|
||||
*/
|
||||
function &getRefTable() {
|
||||
return $this->reftable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key reffields
|
||||
*/
|
||||
function &getRefFields() {
|
||||
return $this->reffields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load data from XML to the key
|
||||
*/
|
||||
function arr2XMLDBKey($xmlarr) {
|
||||
|
||||
$result = true;
|
||||
|
||||
/// Debug the table
|
||||
/// traverse_xmlize($xmlarr); //Debug
|
||||
/// print_object ($GLOBALS['traverse_array']); //Debug
|
||||
/// $GLOBALS['traverse_array']=""; //Debug
|
||||
|
||||
/// Process key attributes (name, type, fields, reftable,
|
||||
/// reffields, comment, previous, next)
|
||||
if (isset($xmlarr['@']['NAME'])) {
|
||||
$this->name = trim($xmlarr['@']['NAME']);
|
||||
} else {
|
||||
$this->errormsg = 'Missing NAME attribute';
|
||||
$result = false;
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['TYPE'])) {
|
||||
/// Check for valid type
|
||||
$type = $this->getXMLDBKeyType(trim($xmlarr['@']['TYPE']));
|
||||
if ($type) {
|
||||
$this->type = $type;
|
||||
} else {
|
||||
$this->errormsg = 'Invalid TYPE attribute';
|
||||
$result = false;
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Missing TYPE attribute';
|
||||
$result = false;
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['FIELDS'])) {
|
||||
$fields = strtolower(trim($xmlarr['@']['FIELDS']));
|
||||
if ($fields) {
|
||||
$fieldsarr = explode(',',$fields);
|
||||
if ($fieldsarr) {
|
||||
foreach ($fieldsarr as $key => $element) {
|
||||
$fieldsarr [$key] = trim($element);
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Incorrect FIELDS attribute (comma separated of fields)';
|
||||
$result = false;
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Empty FIELDS attribute';
|
||||
$result = false;
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Missing FIELDS attribute';
|
||||
$result = false;
|
||||
}
|
||||
/// Finally, set the array of fields
|
||||
$this->fields = $fieldsarr;
|
||||
|
||||
if (isset($xmlarr['@']['REFTABLE'])) {
|
||||
/// Check we are in a FK
|
||||
if ($this->type == XMLDB_KEY_FOREIGN ||
|
||||
$this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
|
||||
$reftable = strtolower(trim($xmlarr['@']['REFTABLE']));
|
||||
if (!$reftable) {
|
||||
$this->errormsg = 'Empty REFTABLE attribute';
|
||||
$result = false;
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Wrong REFTABLE attribute (only FK can have it)';
|
||||
$result = false;
|
||||
}
|
||||
} else if ($this->type == XMLDB_KEY_FOREIGN ||
|
||||
$this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
|
||||
$this->errormsg = 'Missing REFTABLE attribute';
|
||||
$result = false;
|
||||
}
|
||||
/// Finally, set the reftable
|
||||
if ($this->type == XMLDB_KEY_FOREIGN ||
|
||||
$this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
|
||||
$this->reftable = $reftable;
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['REFFIELDS'])) {
|
||||
/// Check we are in a FK
|
||||
if ($this->type == XMLDB_KEY_FOREIGN ||
|
||||
$this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
|
||||
$reffields = strtolower(trim($xmlarr['@']['REFFIELDS']));
|
||||
if ($reffields) {
|
||||
$reffieldsarr = explode(',',$reffields);
|
||||
if ($reffieldsarr) {
|
||||
foreach ($reffieldsarr as $key => $element) {
|
||||
$reffieldsarr [$key] = trim($element);
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Incorrect REFFIELDS attribute (comma separated of fields)';
|
||||
$result = false;
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Empty REFFIELDS attribute';
|
||||
$result = false;
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Wrong REFFIELDS attribute (only FK can have it)';
|
||||
$result = false;
|
||||
}
|
||||
} else if ($this->type == XMLDB_KEY_FOREIGN ||
|
||||
$this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
|
||||
$this->errormsg = 'Missing REFFIELDS attribute';
|
||||
$result = false;
|
||||
}
|
||||
/// Finally, set the array of reffields
|
||||
if ($this->type == XMLDB_KEY_FOREIGN ||
|
||||
$this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
|
||||
$this->reffields = $reffieldsarr;
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['COMMENT'])) {
|
||||
$this->comment = trim($xmlarr['@']['COMMENT']);
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['PREVIOUS'])) {
|
||||
$this->previous = trim($xmlarr['@']['PREVIOUS']);
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['NEXT'])) {
|
||||
$this->next = trim($xmlarr['@']['NEXT']);
|
||||
}
|
||||
|
||||
/// Set some attributes
|
||||
if ($result) {
|
||||
$this->loaded = true;
|
||||
}
|
||||
$this->calculateHash();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the correct XMLDB_KEY_XXX value for the
|
||||
* string passed as argument
|
||||
*/
|
||||
function getXMLDBKeyType($type) {
|
||||
|
||||
$result = XMLDB_KEY_INCORRECT;
|
||||
|
||||
switch (strtolower($type)) {
|
||||
case 'primary':
|
||||
$result = XMLDB_KEY_PRIMARY;
|
||||
break;
|
||||
case 'unique':
|
||||
$result = XMLDB_KEY_UNIQUE;
|
||||
break;
|
||||
case 'foreign':
|
||||
$result = XMLDB_KEY_FOREIGN;
|
||||
break;
|
||||
case 'foreign-unique':
|
||||
$result = XMLDB_KEY_FOREIGN_UNIQUE;
|
||||
break;
|
||||
/// case 'check': //Not supported
|
||||
/// $result = XMLDB_KEY_CHECK;
|
||||
/// break;
|
||||
}
|
||||
/// Return the normalized XMLDB_KEY
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the correct name value for the
|
||||
* XMLDB_KEY_XXX passed as argument
|
||||
*/
|
||||
function getXMLDBKeyName($type) {
|
||||
|
||||
$result = '';
|
||||
|
||||
switch (strtolower($type)) {
|
||||
case XMLDB_KEY_PRIMARY:
|
||||
$result = 'primary';
|
||||
break;
|
||||
case XMLDB_KEY_UNIQUE:
|
||||
$result = 'unique';
|
||||
break;
|
||||
case XMLDB_KEY_FOREIGN:
|
||||
$result = 'foreign';
|
||||
break;
|
||||
case XMLDB_KEY_FOREIGN_UNIQUE:
|
||||
$result = 'foreign-unique';
|
||||
break;
|
||||
/// case XMLDB_KEY_CHECK: //Not supported
|
||||
/// $result = 'check';
|
||||
/// break;
|
||||
}
|
||||
/// Return the normalized name
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function calculate and set the hash of one XMLDBKey
|
||||
*/
|
||||
function calculateHash($recursive = false) {
|
||||
if (!$this->loaded) {
|
||||
$this->hash = NULL;
|
||||
} else {
|
||||
$key = $this->type . implode(', ', $this->fields);
|
||||
if ($this->type == XMLDB_KEY_FOREIGN ||
|
||||
$this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
|
||||
$key .= $this->reftable . implode(', ', $this->reffields);
|
||||
}
|
||||
;
|
||||
$this->hash = md5($key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*This function will output the XML text for one key
|
||||
*/
|
||||
function xmlOutput() {
|
||||
$o = '';
|
||||
$o.= ' <KEY NAME="' . $this->name . '"';
|
||||
$o.= ' TYPE="' . $this->getXMLDBKeyName($this->type) . '"';
|
||||
$o.= ' FIELDS="' . implode(', ', $this->fields) . '"';
|
||||
if ($this->type == XMLDB_KEY_FOREIGN ||
|
||||
$this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
|
||||
$o.= ' REFTABLE="' . $this->reftable . '"';
|
||||
$o.= ' REFFIELDS="' . implode(', ', $this->reffields) . '"';
|
||||
}
|
||||
if ($this->comment) {
|
||||
$o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
|
||||
}
|
||||
if ($this->previous) {
|
||||
$o.= ' PREVIOUS="' . $this->previous . '"';
|
||||
}
|
||||
if ($this->next) {
|
||||
$o.= ' NEXT="' . $this->next . '"';
|
||||
}
|
||||
$o.= '/>' . "\n";
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set all the attributes of the XMLDBKey object
|
||||
* based on information passed in one ADOkey
|
||||
*/
|
||||
function setFromADOKey($adokey) {
|
||||
|
||||
/// Calculate the XMLDB_KEY
|
||||
switch (strtolower($adokey['name'])) {
|
||||
case 'primary':
|
||||
$this->type = XMLDB_KEY_PRIMARY;
|
||||
break;
|
||||
default:
|
||||
$this->type = XMLDB_KEY_UNIQUE;
|
||||
}
|
||||
/// Set the fields
|
||||
$this->fields = $adokey['columns'];
|
||||
/// Some more fields
|
||||
$this->loaded = true;
|
||||
$this->changed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows info in a readable format
|
||||
*/
|
||||
function readableInfo() {
|
||||
$o = '';
|
||||
/// type
|
||||
$o .= $this->getXMLDBKeyName($this->type);
|
||||
/// fields
|
||||
$o .= ' (' . implode(', ', $this->fields) . ')';
|
||||
/// foreign key
|
||||
if ($this->type == XMLDB_KEY_FOREIGN ||
|
||||
$this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
|
||||
$o .= ' references ' . $this->reftable . ' (' . implode(', ', $this->reffields) . ')';
|
||||
}
|
||||
|
||||
return $o;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,387 @@
|
||||
<?php // $Id$
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// NOTICE OF COPYRIGHT //
|
||||
// //
|
||||
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
|
||||
// http://moodle.com //
|
||||
// //
|
||||
// Copyright (C) 2001-3001 Martin Dougiamas http://dougiamas.com //
|
||||
// (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details: //
|
||||
// //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// This class represent the XMLDB base class where all the common piezes
|
||||
/// are defined
|
||||
|
||||
class XMLDBObject {
|
||||
|
||||
var $name;
|
||||
var $comment;
|
||||
var $previous;
|
||||
var $next;
|
||||
var $hash;
|
||||
var $loaded;
|
||||
var $changed;
|
||||
var $errormsg;
|
||||
|
||||
/**
|
||||
* Creates one new XMLDBObject
|
||||
*/
|
||||
function XMLDBObject($name) {
|
||||
$this->name = $name;
|
||||
$this->comment = NULL;
|
||||
$this->previous = NULL;
|
||||
$this->next = NULL;
|
||||
$this->hash = NULL;
|
||||
$this->loaded = false;
|
||||
$this->changed = false;
|
||||
$this->errormsg = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns true/false, if the XMLDBObject has been loaded
|
||||
*/
|
||||
function isLoaded() {
|
||||
return $this->loaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns true/false, if the XMLDBObject has changed
|
||||
*/
|
||||
function hasChanged() {
|
||||
return $this->changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the comment of one XMLDBObject
|
||||
*/
|
||||
function getComment() {
|
||||
return $this->comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the hash of one XMLDBObject
|
||||
*/
|
||||
function getHash() {
|
||||
return $this->hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return the name of the previous XMLDBObject
|
||||
*/
|
||||
function getPrevious() {
|
||||
return $this->previous;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return the name of the next XMLDBObject
|
||||
*/
|
||||
function getNext() {
|
||||
return $this->next;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return the name of the XMLDBObject
|
||||
*/
|
||||
function getName() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return the error detected in the object
|
||||
*/
|
||||
function getError() {
|
||||
return $this->errormsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set the comment of the XMLDB object
|
||||
*/
|
||||
function setComment($comment) {
|
||||
$this->comment = $comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set the previous of the XMLDB object
|
||||
*/
|
||||
function setPrevious($previous) {
|
||||
$this->previous = $previous;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set the next of the XMLDB object
|
||||
*/
|
||||
function setNext($next) {
|
||||
$this->next = $next;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set the hash of the XMLDB object
|
||||
*/
|
||||
function setHash($hash) {
|
||||
$this->hash = $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set the loaded field of the XMLDB object
|
||||
*/
|
||||
function setLoaded($loaded = true) {
|
||||
$this->loaded = $loaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set the changed field of the XMLDB object
|
||||
*/
|
||||
function setChanged($changed = true) {
|
||||
$this->changed = $changed;
|
||||
}
|
||||
/**
|
||||
* This function will set the name field of the XMLDB object
|
||||
*/
|
||||
function setName($name) {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will check if one key name is ok or no (true/false)
|
||||
* only lowercase a-z, 0-9 and _ are allowed
|
||||
*/
|
||||
function checkName () {
|
||||
$result = true;
|
||||
|
||||
if ($this->name != eregi_replace('[^a-z0-9_ -]', '', $this->name)) {
|
||||
$result = false;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will check that all the elements in one array
|
||||
* have a correct name [a-z0-9_]
|
||||
*/
|
||||
function checkNameValues(&$arr) {
|
||||
$result = true;
|
||||
/// TODO: Perhaps, add support for reserved words
|
||||
|
||||
/// Check the name only contains valid chars
|
||||
if ($arr) {
|
||||
foreach($arr as $element) {
|
||||
if (!$element->checkName()) {
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will check that all the elements in one array
|
||||
* have a consistent info in their previous/next fields
|
||||
*/
|
||||
function checkPreviousNextValues(&$arr) {
|
||||
$result = true;
|
||||
/// Check that only one element has the previous not set
|
||||
if ($arr) {
|
||||
$counter = 0;
|
||||
foreach($arr as $element) {
|
||||
if (!$element->getPrevious()) {
|
||||
$counter++;
|
||||
}
|
||||
}
|
||||
if ($counter != 1) {
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
/// Check that only one element has the next not set
|
||||
if ($result && $arr) {
|
||||
$counter = 0;
|
||||
foreach($arr as $element) {
|
||||
if (!$element->getNext()) {
|
||||
$counter++;
|
||||
}
|
||||
}
|
||||
if ($counter != 1) {
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
/// Check that all the previous elements are existing elements
|
||||
if ($result && $arr) {
|
||||
foreach($arr as $element) {
|
||||
if ($element->getPrevious()) {
|
||||
$i = $this->findObjectInArray($element->getPrevious(), $arr);
|
||||
if ($i === NULL) {
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Check that all the next elements are existing elements
|
||||
if ($result && $arr) {
|
||||
foreach($arr as $element) {
|
||||
if ($element->getNext()) {
|
||||
$i = $this->findObjectInArray($element->getNext(), $arr);
|
||||
if ($i === NULL) {
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Check that there aren't duplicates in the previous values
|
||||
if ($result && $arr) {
|
||||
$existarr = array();
|
||||
foreach($arr as $element) {
|
||||
if (in_array($element->getPrevious(), $existarr)) {
|
||||
$result = false;
|
||||
} else {
|
||||
$existarr[] = $element->getPrevious();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Check that there aren't duplicates in the next values
|
||||
if ($result && $arr) {
|
||||
$existarr = array();
|
||||
foreach($arr as $element) {
|
||||
if (in_array($element->getNext(), $existarr)) {
|
||||
$result = false;
|
||||
} else {
|
||||
$existarr[] = $element->getNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will order all the elements in one array, following
|
||||
* the previous/next rules
|
||||
*/
|
||||
function orderElements($arr) {
|
||||
$result = true;
|
||||
/// Create a new array
|
||||
$newarr = array();
|
||||
if (!empty($arr)) {
|
||||
$currentelement = NULL;
|
||||
/// Get the element without previous
|
||||
foreach($arr as $key => $element) {
|
||||
if (!$element->getPrevious()) {
|
||||
$currentelement = $arr[$key];
|
||||
$newarr[0] = $arr[$key];
|
||||
}
|
||||
}
|
||||
if (!$currentelement) {
|
||||
$result = false;
|
||||
}
|
||||
/// Follow the next rules
|
||||
$counter = 1;
|
||||
while ($result && $currentelement->getNext()) {
|
||||
$i = $this->findObjectInArray($currentelement->getNext(), $arr);
|
||||
$currentelement = $arr[$i];
|
||||
$newarr[$counter] = $arr[$i];
|
||||
$counter++;
|
||||
}
|
||||
/// Compare number of elements between original and new array
|
||||
if ($result && count($arr) != count($newarr)) {
|
||||
$result = false;
|
||||
}
|
||||
/// Check that previous/next is ok (redundant but...)
|
||||
if ($this->checkPreviousNextValues($newarr)) {
|
||||
$result = $newarr;
|
||||
} else {
|
||||
$result = false;
|
||||
}
|
||||
} else {
|
||||
$result = array();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position of one object in the array.
|
||||
*/
|
||||
function &findObjectInArray($objectname, $arr) {
|
||||
foreach ($arr as $i => $object) {
|
||||
if ($objectname == $object->getName()) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
$null = NULL;
|
||||
return $null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will display a readable info about the XMLDBObject
|
||||
* (should be implemented inside each XMLDBxxx object)
|
||||
*/
|
||||
function readableInfo() {
|
||||
return get_class($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one array of elements from one comma separated string,
|
||||
* supporting quoted strings containing commas and concat function calls
|
||||
*/
|
||||
function comma2array($string) {
|
||||
|
||||
$arr = array();
|
||||
|
||||
$foundquotes = array();
|
||||
$foundconcats = array();
|
||||
|
||||
/// Extract all the concat elements from the string
|
||||
preg_match_all("/(CONCAT\(.*?\))/is", $string, $matches);
|
||||
foreach (array_unique($matches[0]) as $key=>$value) {
|
||||
$foundconcats['<#'.$key.'#>'] = $value;
|
||||
}
|
||||
if (!empty($foundconcats)) {
|
||||
$string = str_replace($foundconcats,array_keys($foundconcats),$string);
|
||||
}
|
||||
|
||||
/// Extract all the quoted elements from the string
|
||||
preg_match_all("/('.*?')/is", $string, $matches);
|
||||
foreach (array_unique($matches[0]) as $key=>$value) {
|
||||
$foundquotes['<%'.$key.'%>'] = $value;
|
||||
}
|
||||
if (!empty($foundquotes)) {
|
||||
$string = str_replace($foundquotes,array_keys($foundquotes),$string);
|
||||
}
|
||||
|
||||
/// Explode safely the string
|
||||
$arr = explode (',', $string);
|
||||
|
||||
/// Put the concat and quoted elements back again, triming every element
|
||||
if ($arr) {
|
||||
foreach ($arr as $key => $element) {
|
||||
/// Clear some spaces
|
||||
$element = trim($element);
|
||||
/// Replace the quoted elements if exists
|
||||
if (!empty($foundquotes)) {
|
||||
$element = str_replace(array_keys($foundquotes), $foundquotes, $element);
|
||||
}
|
||||
/// Replace the concat elements if exists
|
||||
if (!empty($foundconcats)) {
|
||||
$element = str_replace(array_keys($foundconcats), $foundconcats, $element);
|
||||
}
|
||||
$arr[$key] = $element;
|
||||
}
|
||||
}
|
||||
|
||||
return $arr;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,365 @@
|
||||
<?php // $Id$
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// NOTICE OF COPYRIGHT //
|
||||
// //
|
||||
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
|
||||
// http://moodle.com //
|
||||
// //
|
||||
// Copyright (C) 2001-3001 Martin Dougiamas http://dougiamas.com //
|
||||
// (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details: //
|
||||
// //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// This class represent one XMLDB Statement
|
||||
/// (a group of SQL arbitrary sentences)
|
||||
/// (only INSERT is allowed for now)
|
||||
|
||||
class XMLDBStatement extends XMLDBObject {
|
||||
|
||||
var $table; // Table we are handling
|
||||
var $type; // XMLDB_STATEMENT_TYPE
|
||||
var $sentences; // Collection of sentences in the statement
|
||||
|
||||
/**
|
||||
* Creates one new XMLDBStatement
|
||||
*/
|
||||
function XMLDBStatement($name) {
|
||||
parent::XMLDBObject($name);
|
||||
$this->table = NULL;
|
||||
$this->type = XMLDB_STATEMENT_INCORRECT;
|
||||
$this->sentences = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the statement table
|
||||
*/
|
||||
function getTable() {
|
||||
return $this->table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the statement type
|
||||
*/
|
||||
function getType() {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the statement sentences
|
||||
*/
|
||||
function &getSentences() {
|
||||
return $this->sentences;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the statement table
|
||||
*/
|
||||
function setTable($table) {
|
||||
$this->table = $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the statement type
|
||||
*/
|
||||
function setType($type) {
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add one statement sentence
|
||||
*/
|
||||
function addSentence($sentence) {
|
||||
$this->sentences[] = $sentence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load data from XML to the index
|
||||
*/
|
||||
function arr2XMLDBStatement($xmlarr) {
|
||||
|
||||
$result = true;
|
||||
|
||||
/// Debug the table
|
||||
/// traverse_xmlize($xmlarr); //Debug
|
||||
/// print_object ($GLOBALS['traverse_array']); //Debug
|
||||
/// $GLOBALS['traverse_array']=""; //Debug
|
||||
|
||||
/// Process key attributes (table, type, comment, previous, next)
|
||||
if (isset($xmlarr['@']['TABLE'])) {
|
||||
$this->table = strtolower(trim($xmlarr['@']['TABLE']));
|
||||
} else {
|
||||
$this->errormsg = 'Missing TABLE attribute';
|
||||
$result = false;
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['TYPE'])) {
|
||||
/// Check for valid type
|
||||
$type = $this->getXMLDBStatementType(trim($xmlarr['@']['TYPE']));
|
||||
if ($type) {
|
||||
$this->type = $type;
|
||||
} else {
|
||||
$this->errormsg = 'Invalid TYPE attribute';
|
||||
$result = false;
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Missing TYPE attribute';
|
||||
$result = false;
|
||||
}
|
||||
|
||||
/// Look for sentences
|
||||
$sentencesarr = array();
|
||||
|
||||
if (isset($xmlarr['#']['SENTENCES'])) {
|
||||
$sentences = $xmlarr['#']['SENTENCES'][0]['#']['SENTENCE'];
|
||||
if ($sentences) {
|
||||
foreach ($sentences as $sentence) {
|
||||
if (isset($sentence['@']['TEXT'])) {
|
||||
$sentencesarr[] = trim($sentence['@']['TEXT']);
|
||||
} else {
|
||||
$this->errormsg = 'Missing TEXT attribute in sentence';
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Finally, set the array of sentences
|
||||
$this->sentences = $sentencesarr;
|
||||
|
||||
/// Now, perform some validations over sentences
|
||||
/// XMLDB_STATEMENT_INSERT checks
|
||||
if ($this->type == XMLDB_STATEMENT_INSERT) {
|
||||
/// Separate fields and values into two arrays
|
||||
if ($this->sentences) {
|
||||
foreach ($this->sentences as $sentence) {
|
||||
$fields = $this->getFieldsFromInsertSentence($sentence);
|
||||
$values = $this->getValuesFromInsertSentence($sentence);
|
||||
/// Check that we aren't inserting the id field
|
||||
if (in_array('id', $fields)) {
|
||||
$this->errormsg = 'Cannot insert the "id" field. It is an autonumeric column';
|
||||
$result = false;
|
||||
}
|
||||
if ($result && count($fields) == 0) {
|
||||
$this->errormsg = 'Missing fields in sentence "' . $sentence . '"';
|
||||
$result = false;
|
||||
}
|
||||
if ($result && count($values) == 0) {
|
||||
$this->errormsg = 'Missing values in sentence "' . $sentence . '"';
|
||||
$result = false;
|
||||
}
|
||||
if ($result && count($fields) != count($values)) {
|
||||
$this->errormsg = 'Incorrect number of fields (' .implode(', ', $fields) . ') or values (' . implode(', ', $values) . ')';
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/// Sentences different from INSERT are not valid for now
|
||||
$this->errormsg = 'Only INSERT statements are supported';
|
||||
$result = false;
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['COMMENT'])) {
|
||||
$this->comment = trim($xmlarr['@']['COMMENT']);
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['PREVIOUS'])) {
|
||||
$this->previous = trim($xmlarr['@']['PREVIOUS']);
|
||||
}
|
||||
|
||||
if (isset($xmlarr['@']['NEXT'])) {
|
||||
$this->next = trim($xmlarr['@']['NEXT']);
|
||||
}
|
||||
|
||||
/// Set some attributes
|
||||
if ($result) {
|
||||
$this->loaded = true;
|
||||
}
|
||||
$this->calculateHash();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the correct XMLDB_STATEMENT_XXX value for the
|
||||
* string passed as argument
|
||||
*/
|
||||
function getXMLDBStatementType($type) {
|
||||
|
||||
$result = XMLDB_STATEMENT_INCORRECT;
|
||||
|
||||
switch (strtolower($type)) {
|
||||
case 'insert':
|
||||
$result = XMLDB_STATEMENT_INSERT;
|
||||
break;
|
||||
case 'update':
|
||||
$result = XMLDB_STATEMENT_UPDATE;
|
||||
break;
|
||||
case 'delete':
|
||||
$result = XMLDB_STATEMENT_DELETE;
|
||||
break;
|
||||
case 'custom':
|
||||
$result = XMLDB_STATEMENT_CUSTOM;
|
||||
break;
|
||||
}
|
||||
/// Return the normalized XMLDB_STATEMENT
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the correct name value for the
|
||||
* XMLDB_STATEMENT_XXX passed as argument
|
||||
*/
|
||||
function getXMLDBStatementName($type) {
|
||||
|
||||
$result = '';
|
||||
|
||||
switch (strtolower($type)) {
|
||||
case XMLDB_STATEMENT_INSERT:
|
||||
$result = 'insert';
|
||||
break;
|
||||
case XMLDB_STATEMENT_UPDATE:
|
||||
$result = 'update';
|
||||
break;
|
||||
case XMLDB_STATEMENT_DELETE:
|
||||
$result = 'delete';
|
||||
break;
|
||||
case XMLDB_STATEMENT_CUSTOM:
|
||||
$result = 'custom';
|
||||
break;
|
||||
}
|
||||
/// Return the normalized name
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function calculate and set the hash of one XMLDBStatement
|
||||
*/
|
||||
function calculateHash($recursive = false) {
|
||||
if (!$this->loaded) {
|
||||
$this->hash = NULL;
|
||||
} else {
|
||||
$key = $this->table . $this->type . implode (', ', $this->sentences);
|
||||
$this->hash = md5($key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will output the XML text for one statement
|
||||
*/
|
||||
function xmlOutput() {
|
||||
$o = '';
|
||||
$o.= ' <STATEMENT NAME="' . $this->name . '" TYPE="' . XMLDBStatement::getXMLDBStatementName($this->type) . '" TABLE="' . $this->table . '"';
|
||||
if ($this->comment) {
|
||||
$o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
|
||||
}
|
||||
if ($this->previous) {
|
||||
$o.= ' PREVIOUS="' . $this->previous . '"';
|
||||
}
|
||||
if ($this->next) {
|
||||
$o.= ' NEXT="' . $this->next . '"';
|
||||
}
|
||||
if ($this->sentences) {
|
||||
$o.= '>' . "\n";
|
||||
$o.= ' <SENTENCES>' . "\n";
|
||||
foreach ($this->sentences as $sentence) {
|
||||
$o.= ' <SENTENCE TEXT="' . htmlspecialchars($sentence) . '" />' . "\n";
|
||||
}
|
||||
$o.= ' </SENTENCES>' . "\n";
|
||||
$o.= ' </STATEMENT>' . "\n";
|
||||
} else {
|
||||
$o.= '/>' . "\n";
|
||||
}
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set all the attributes of the XMLDBIndex object
|
||||
* based on information passed in one ADOindex
|
||||
*/
|
||||
function setFromADOIndex($adoindex) {
|
||||
|
||||
/// Set the unique field
|
||||
$this->unique = false;
|
||||
/// Set the fields
|
||||
$this->fields = $adoindex['columns'];
|
||||
/// Some more fields
|
||||
$this->loaded = true;
|
||||
$this->changed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows info in a readable format
|
||||
*/
|
||||
function readableInfo() {
|
||||
$o = '';
|
||||
/// unique
|
||||
if ($this->unique) {
|
||||
$o .= 'unique';
|
||||
} else {
|
||||
$o .= 'not unique';
|
||||
}
|
||||
/// fields
|
||||
$o .= ' (' . implode(', ', $this->fields) . ')';
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return an array of fields from one INSERT sentence
|
||||
*/
|
||||
function getFieldsFromInsertSentence($sentence) {
|
||||
|
||||
$fields = array();
|
||||
|
||||
/// Get first part from the sentence (before VALUES)
|
||||
preg_match('/^\((.*)\)\s+VALUES/is', $sentence, $matches);
|
||||
if (isset($matches[1])) {
|
||||
$part = $matches[1];
|
||||
/// Convert the comma separated string to an array
|
||||
$arr = $this->comma2array($part);
|
||||
if ($arr) {
|
||||
$fields = $arr;
|
||||
}
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return an array of values from one INSERT sentence
|
||||
*/
|
||||
function getValuesFromInsertSentence($sentence) {
|
||||
|
||||
$values = array();
|
||||
|
||||
/// Get second part from the sentence (after VALUES)
|
||||
preg_match('/VALUES\s+\((.*)\)$/is', $sentence, $matches);
|
||||
if (isset($matches[1])) {
|
||||
$part = $matches[1];
|
||||
/// Convert the comma separated string to an array
|
||||
$arr = $this->comma2array($part);
|
||||
if ($arr) {
|
||||
$values = $arr;
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,697 @@
|
||||
<?php // $Id$
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// NOTICE OF COPYRIGHT //
|
||||
// //
|
||||
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
|
||||
// http://moodle.com //
|
||||
// //
|
||||
// Copyright (C) 2001-3001 Martin Dougiamas http://dougiamas.com //
|
||||
// (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details: //
|
||||
// //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// This class represent one XMLDB structure
|
||||
|
||||
class XMLDBStructure extends XMLDBObject {
|
||||
|
||||
var $path;
|
||||
var $version;
|
||||
var $tables;
|
||||
var $statements;
|
||||
|
||||
/**
|
||||
* Creates one new XMLDBStructure
|
||||
*/
|
||||
function XMLDBStructure($name) {
|
||||
parent::XMLDBObject($name);
|
||||
$this->path = NULL;
|
||||
$this->version = NULL;
|
||||
$this->tables = array();
|
||||
$this->statements = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path of the structure
|
||||
*/
|
||||
function getPath() {
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version of the structure
|
||||
*/
|
||||
function getVersion() {
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one XMLDBTable
|
||||
*/
|
||||
function &getTable($tablename) {
|
||||
$i = $this->findTableInArray($tablename);
|
||||
if ($i !== NULL) {
|
||||
return $this->tables[$i];
|
||||
}
|
||||
$null = NULL;
|
||||
return $null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position of one table in the array.
|
||||
*/
|
||||
function &findTableInArray($tablename) {
|
||||
foreach ($this->tables as $i => $table) {
|
||||
if ($tablename == $table->getName()) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
$null = NULL;
|
||||
return $null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position of one statement in the array.
|
||||
*/
|
||||
function &findStatementInArray($statementname) {
|
||||
foreach ($this->statements as $i => $statement) {
|
||||
if ($statementname == $statement->getName()) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
$null = NULL;
|
||||
return $null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will reorder the array of tables
|
||||
*/
|
||||
function orderTables() {
|
||||
$result =& $this->orderElements($this->tables);
|
||||
if ($result) {
|
||||
$this->setTables($result);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will reorder the array of statements
|
||||
*/
|
||||
function orderStatements() {
|
||||
$result =& $this->orderElements($this->statements);
|
||||
if ($result) {
|
||||
$this->setStatements($result);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tables of the structure
|
||||
*/
|
||||
function &getTables() {
|
||||
return $this->tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one XMLDBStatement
|
||||
*/
|
||||
function &getStatement($statementname) {
|
||||
$i = $this->findStatementInArray($statementname);
|
||||
if ($i !== NULL) {
|
||||
return $this->statements[$i];
|
||||
}
|
||||
$null = NULL;
|
||||
return $null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the statements of the structure
|
||||
*/
|
||||
function &getStatements() {
|
||||
return $this->statements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the structure version
|
||||
*/
|
||||
function setVersion($version) {
|
||||
$this->version = $version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add one table to the structure, allowing to specify the desired order
|
||||
* If it's not specified, then the table is added at the end.
|
||||
*/
|
||||
function addTable(&$table, $after=NULL) {
|
||||
|
||||
/// Calculate the previous and next tables
|
||||
$prevtable = NULL;
|
||||
$nexttable = NULL;
|
||||
|
||||
if (!$after) {
|
||||
$alltables =& $this->getTables();
|
||||
if ($alltables) {
|
||||
end($alltables);
|
||||
$prevtable =& $alltables[key($alltables)];
|
||||
}
|
||||
} else {
|
||||
$prevtable =& $this->getTable($after);
|
||||
}
|
||||
if ($prevtable && $prevtable->getNext()) {
|
||||
$nexttable =& $this->getTable($prevtable->getNext());
|
||||
}
|
||||
|
||||
/// Set current table previous and next attributes
|
||||
if ($prevtable) {
|
||||
$table->setPrevious($prevtable->getName());
|
||||
$prevtable->setNext($table->getName());
|
||||
}
|
||||
if ($nexttable) {
|
||||
$table->setNext($nexttable->getName());
|
||||
$nexttable->setPrevious($table->getName());
|
||||
}
|
||||
/// Some more attributes
|
||||
$table->setLoaded(true);
|
||||
$table->setChanged(true);
|
||||
/// Add the new table
|
||||
$this->tables[] =& $table;
|
||||
/// Reorder the whole structure
|
||||
$this->orderTables($this->tables);
|
||||
/// Recalculate the hash
|
||||
$this->calculateHash(true);
|
||||
/// We have one new table, so the structure has changed
|
||||
$this->setVersion(userdate(time(), '%Y%m%d', 99, false));
|
||||
$this->setChanged(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add one statement to the structure, allowing to specify the desired order
|
||||
* If it's not specified, then the statement is added at the end.
|
||||
*/
|
||||
function addStatement(&$statement, $after=NULL) {
|
||||
|
||||
/// Calculate the previous and next tables
|
||||
$prevstatement = NULL;
|
||||
$nextstatement = NULL;
|
||||
|
||||
if (!$after) {
|
||||
$allstatements =& $this->getStatements();
|
||||
if ($allstatements) {
|
||||
end($allstatements);
|
||||
$prevstatement =& $allstatements[key($allstatements)];
|
||||
}
|
||||
} else {
|
||||
$prevstatement =& $this->getStatement($after);
|
||||
}
|
||||
if ($prevstatement && $prevstatement->getNext()) {
|
||||
$nextstatement =& $this->getStatement($prevstatement->getNext());
|
||||
}
|
||||
|
||||
/// Set current statement previous and next attributes
|
||||
if ($prevstatement) {
|
||||
$statement->setPrevious($prevstatement->getName());
|
||||
$prevstatement->setNext($statement->getName());
|
||||
}
|
||||
if ($nextstatement) {
|
||||
$statement->setNext($nextstatement->getName());
|
||||
$nextstatement->setPrevious($statement->getName());
|
||||
}
|
||||
/// Some more attributes
|
||||
$statement->setLoaded(true);
|
||||
$statement->setChanged(true);
|
||||
/// Add the new statement
|
||||
$this->statements[] =& $statement;
|
||||
/// Reorder the whole structure
|
||||
$this->orderStatements($this->statements);
|
||||
/// Recalculate the hash
|
||||
$this->calculateHash(true);
|
||||
/// We have one new statement, so the structure has changed
|
||||
$this->setVersion(userdate(time(), '%Y%m%d', 99, false));
|
||||
$this->setChanged(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete one table from the Structure
|
||||
*/
|
||||
function deleteTable($tablename) {
|
||||
|
||||
$table =& $this->getTable($tablename);
|
||||
if ($table) {
|
||||
$i = $this->findTableInArray($tablename);
|
||||
$prevtable = NULL;
|
||||
$nexttable = NULL;
|
||||
/// Look for prev and next table
|
||||
$prevtable =& $this->getTable($table->getPrevious());
|
||||
$nexttable =& $this->getTable($table->getNext());
|
||||
/// Change their previous and next attributes
|
||||
if ($prevtable) {
|
||||
$prevtable->setNext($table->getNext());
|
||||
}
|
||||
if ($nexttable) {
|
||||
$nexttable->setPrevious($table->getPrevious());
|
||||
}
|
||||
/// Delete the table
|
||||
unset($this->tables[$i]);
|
||||
/// Reorder the tables
|
||||
$this->orderTables($this->tables);
|
||||
/// Recalculate the hash
|
||||
$this->calculateHash(true);
|
||||
/// We have one deleted table, so the structure has changed
|
||||
$this->setVersion(userdate(time(), '%Y%m%d', 99, false));
|
||||
$this->setChanged(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete one statement from the Structure
|
||||
*/
|
||||
function deleteStatement($statementname) {
|
||||
|
||||
$statement =& $this->getStatement($statementname);
|
||||
if ($statement) {
|
||||
$i = $this->findStatementInArray($statementname);
|
||||
$prevstatement = NULL;
|
||||
$nextstatement = NULL;
|
||||
/// Look for prev and next statement
|
||||
$prevstatement =& $this->getStatement($statement->getPrevious());
|
||||
$nextstatement =& $this->getStatement($statement->getNext());
|
||||
/// Change their previous and next attributes
|
||||
if ($prevstatement) {
|
||||
$prevstatement->setNext($statement->getNext());
|
||||
}
|
||||
if ($nextstatement) {
|
||||
$nextstatement->setPrevious($statement->getPrevious());
|
||||
}
|
||||
/// Delete the statement
|
||||
unset($this->statements[$i]);
|
||||
/// Reorder the statements
|
||||
$this->orderStatements($this->statements);
|
||||
/// Recalculate the hash
|
||||
$this->calculateHash(true);
|
||||
/// We have one deleted statement, so the structure has changed
|
||||
$this->setVersion(userdate(time(), '%Y%m%d', 99, false));
|
||||
$this->setChanged(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tables
|
||||
*/
|
||||
function setTables(&$tables) {
|
||||
$this->tables = $tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the statements
|
||||
*/
|
||||
function setStatements(&$statements) {
|
||||
$this->statements = $statements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load data from XML to the structure
|
||||
*/
|
||||
function arr2XMLDBStructure($xmlarr) {
|
||||
|
||||
$result = true;
|
||||
|
||||
/// Debug the structure
|
||||
/// traverse_xmlize($xmlarr); //Debug
|
||||
/// print_object ($GLOBALS['traverse_array']); //Debug
|
||||
/// $GLOBALS['traverse_array']=""; //Debug
|
||||
|
||||
/// Process structure attributes (path, comment and version)
|
||||
if (isset($xmlarr['XMLDB']['@']['PATH'])) {
|
||||
$this->path = trim($xmlarr['XMLDB']['@']['PATH']);
|
||||
} else {
|
||||
$this->errormsg = 'Missing PATH attribute';
|
||||
$result = false;
|
||||
}
|
||||
if (isset($xmlarr['XMLDB']['@']['VERSION'])) {
|
||||
$this->version = trim($xmlarr['XMLDB']['@']['VERSION']);
|
||||
} else {
|
||||
$this->errormsg = 'Missing VERSION attribute';
|
||||
$result = false;
|
||||
}
|
||||
if (isset($xmlarr['XMLDB']['@']['COMMENT'])) {
|
||||
$this->comment = trim($xmlarr['XMLDB']['@']['COMMENT']);
|
||||
} else {
|
||||
$this->errormsg = 'Missing COMMENT attribute';
|
||||
$result = false;
|
||||
}
|
||||
|
||||
/// Iterate over tables
|
||||
if (isset($xmlarr['XMLDB']['#']['TABLES']['0']['#']['TABLE'])) {
|
||||
foreach ($xmlarr['XMLDB']['#']['TABLES']['0']['#']['TABLE'] as $xmltable) {
|
||||
if (!$result) { //Skip on error
|
||||
continue;
|
||||
}
|
||||
$name = trim($xmltable['@']['NAME']);
|
||||
$table = new XMLDBTable($name);
|
||||
$table->arr2XMLDBTable($xmltable);
|
||||
$this->tables[] = $table;
|
||||
if (!$table->isLoaded()) {
|
||||
$this->errormsg = 'Problem loading table ' . $name;
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Missing TABLES section';
|
||||
$result = false;
|
||||
}
|
||||
|
||||
/// Perform some general checks over tables
|
||||
if ($result && $this->tables) {
|
||||
/// Check tables names are ok (lowercase, a-z _-)
|
||||
if (!$this->checkNameValues($this->tables)) {
|
||||
$this->errormsg = 'Some TABLES name values are incorrect';
|
||||
$result = false;
|
||||
}
|
||||
/// Check previous & next are ok (duplicates and existing tables)
|
||||
if ($result && !$this->checkPreviousNextValues($this->tables)) {
|
||||
$this->errormsg = 'Some TABLES previous/next values are incorrect';
|
||||
$result = false;
|
||||
}
|
||||
/// Order tables
|
||||
if ($result && !$this->orderTables($this->tables)) {
|
||||
$this->errormsg = 'Error ordering the tables';
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterate over statements
|
||||
if (isset($xmlarr['XMLDB']['#']['STATEMENTS']['0']['#']['STATEMENT'])) {
|
||||
foreach ($xmlarr['XMLDB']['#']['STATEMENTS']['0']['#']['STATEMENT'] as $xmlstatement) {
|
||||
if (!$result) { //Skip on error
|
||||
continue;
|
||||
}
|
||||
$name = trim($xmlstatement['@']['NAME']);
|
||||
$statement = new XMLDBStatement($name);
|
||||
$statement->arr2XMLDBStatement($xmlstatement);
|
||||
$this->statements[] = $statement;
|
||||
if (!$statement->isLoaded()) {
|
||||
$this->errormsg = 'Problem loading statement ' . $name;
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform some general checks over statements
|
||||
if ($result && $this->statements) {
|
||||
/// Check statements names are ok (lowercase, a-z _-)
|
||||
if (!$this->checkNameValues($this->statements)) {
|
||||
$this->errormsg = 'Some STATEMENTS name values are incorrect';
|
||||
$result = false;
|
||||
}
|
||||
/// Check previous & next are ok (duplicates and existing statements)
|
||||
if ($result && !$this->checkPreviousNextValues($this->statements)) {
|
||||
$this->errormsg = 'Some STATEMENTS previous/next values are incorrect';
|
||||
$result = false;
|
||||
}
|
||||
/// Order statements
|
||||
if ($result && !$this->orderStatements($this->statements)) {
|
||||
$this->errormsg = 'Error ordering the statements';
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Set some attributes
|
||||
if ($result) {
|
||||
$this->loaded = true;
|
||||
}
|
||||
$this->calculateHash();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function calculate and set the hash of one XMLDBStructure
|
||||
*/
|
||||
function calculateHash($recursive = false) {
|
||||
if (!$this->loaded) {
|
||||
$this->hash = NULL;
|
||||
} else {
|
||||
$key = $this->name . $this->path . $this->comment;
|
||||
if ($this->tables) {
|
||||
foreach ($this->tables as $tbl) {
|
||||
$table =& $this->getTable($tbl->getName());
|
||||
if ($recursive) {
|
||||
$table->calculateHash($recursive);
|
||||
}
|
||||
$key .= $table->getHash();
|
||||
}
|
||||
}
|
||||
if ($this->statements) {
|
||||
foreach ($this->statements as $sta) {
|
||||
$statement =& $this->getStatement($sta->getName());
|
||||
if ($recursive) {
|
||||
$statement->calculateHash($recursive);
|
||||
}
|
||||
$key .= $statement->getHash();
|
||||
}
|
||||
}
|
||||
$this->hash = md5($key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will output the XML text for one structure
|
||||
*/
|
||||
function xmlOutput() {
|
||||
$o = '<?xml version="1.0" encoding="UTF-8" ?>' . "\n";
|
||||
$o.= '<XMLDB PATH="' . $this->path . '"';
|
||||
$o.= ' VERSION="' . $this->version . '"';
|
||||
if ($this->comment) {
|
||||
$o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
|
||||
}
|
||||
$o.= '>' . "\n";
|
||||
/// Now the tables
|
||||
if ($this->tables) {
|
||||
$o.= ' <TABLES>' . "\n";
|
||||
foreach ($this->tables as $table) {
|
||||
$o.= $table->xmlOutput();
|
||||
}
|
||||
$o.= ' </TABLES>' . "\n";
|
||||
}
|
||||
/// Now the statements
|
||||
if ($this->statements) {
|
||||
$o.= ' <STATEMENTS>' . "\n";
|
||||
foreach ($this->statements as $statement) {
|
||||
$o.= $statement->xmlOutput();
|
||||
}
|
||||
$o.= ' </STATEMENTS>' . "\n";
|
||||
}
|
||||
$o.= '</XMLDB>';
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the number of uses of one table inside
|
||||
* a whole XMLDStructure. Useful to detect if the table must be
|
||||
* locked. Return false if no uses are found.
|
||||
*/
|
||||
function getTableUses($tablename) {
|
||||
|
||||
$uses = array();
|
||||
|
||||
/// Check if some foreign key in the whole structure is using it
|
||||
/// (by comparing the reftable with the tablename)
|
||||
$alltables = $this->getTables();
|
||||
if ($alltables) {
|
||||
foreach ($alltables as $table) {
|
||||
$keys = $table->getKeys();
|
||||
if ($keys) {
|
||||
foreach ($keys as $key) {
|
||||
if ($key->getType() == XMLDB_KEY_FOREIGN) {
|
||||
if ($tablename == $key->getRefTable()) {
|
||||
$uses[] = 'table ' . $table->getName() . ' key ' . $key->getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return result
|
||||
if (!empty($uses)) {
|
||||
return $uses;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the number of uses of one field inside
|
||||
* a whole XMLDBStructure. Useful to detect if the field must be
|
||||
* locked. Return false if no uses are found.
|
||||
*/
|
||||
function getFieldUses($tablename, $fieldname) {
|
||||
|
||||
$uses = array();
|
||||
|
||||
/// Check if any key in the table is using it
|
||||
$table = $this->getTable($tablename);
|
||||
if ($keys = $table->getKeys()) {
|
||||
foreach ($keys as $key) {
|
||||
if (in_array($fieldname, $key->getFields()) ||
|
||||
in_array($fieldname, $key->getRefFields())) {
|
||||
$uses[] = 'table ' . $table->getName() . ' key ' . $key->getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Check if any index in the table is using it
|
||||
$table = $this->getTable($tablename);
|
||||
if ($indexes = $table->getIndexes()) {
|
||||
foreach ($indexes as $index) {
|
||||
if (in_array($fieldname, $index->getFields())) {
|
||||
$uses[] = 'table ' . $table->getName() . ' index ' . $index->getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Check if some foreign key in the whole structure is using it
|
||||
/// By comparing the reftable and refields with the field)
|
||||
$alltables = $this->getTables();
|
||||
if ($alltables) {
|
||||
foreach ($alltables as $table) {
|
||||
$keys = $table->getKeys();
|
||||
if ($keys) {
|
||||
foreach ($keys as $key) {
|
||||
if ($key->getType() == XMLDB_KEY_FOREIGN) {
|
||||
if ($tablename == $key->getRefTable()) {
|
||||
$reffieds = $key->getRefFields();
|
||||
if (in_array($fieldname, $key->getRefFields())) {
|
||||
$uses[] = 'table ' . $table->getName() . ' key ' . $key->getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return result
|
||||
if (!empty($uses)) {
|
||||
return $uses;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the number of uses of one key inside
|
||||
* a whole XMLDBStructure. Useful to detect if the key must be
|
||||
* locked. Return false if no uses are found.
|
||||
*/
|
||||
function getKeyUses($tablename, $keyname) {
|
||||
|
||||
$uses = array();
|
||||
|
||||
/// Check if some foreign key in the whole structure is using it
|
||||
/// (by comparing the reftable and reffields with the fields in the key)
|
||||
$mytable = $this->getTable($tablename);
|
||||
$mykey = $mytable->getKey($keyname);
|
||||
$alltables = $this->getTables();
|
||||
if ($alltables && $mykey) {
|
||||
foreach ($alltables as $table) {
|
||||
$allkeys = $table->getKeys();
|
||||
if ($allkeys) {
|
||||
foreach ($allkeys as $key) {
|
||||
if ($key->getType() != XMLDB_KEY_FOREIGN) {
|
||||
continue;
|
||||
}
|
||||
if ($key->getRefTable() == $tablename &&
|
||||
implode(',', $key->getRefFields()) == implode(',', $mykey->getFields())) {
|
||||
$uses[] = 'table ' . $table->getName() . ' key ' . $key->getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return result
|
||||
if (!empty($uses)) {
|
||||
return $uses;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the number of uses of one index inside
|
||||
* a whole XMLDBStructure. Useful to detect if the index must be
|
||||
* locked. Return false if no uses are found.
|
||||
*/
|
||||
function getIndexUses($tablename, $indexname) {
|
||||
|
||||
$uses = array();
|
||||
|
||||
/// Nothing to check, beause indexes haven't uses! Leave it here
|
||||
/// for future checks...
|
||||
|
||||
/// Return result
|
||||
if (!empty($uses)) {
|
||||
return $uses;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return all the errors found in one structure
|
||||
* looking recursively inside each table/statement. Returns
|
||||
* an array of errors or false
|
||||
*/
|
||||
function getAllErrors() {
|
||||
|
||||
$errors = array();
|
||||
/// First the structure itself
|
||||
if ($this->getError()) {
|
||||
$errors[] = $this->getError();
|
||||
}
|
||||
/// Delegate to tables
|
||||
if ($tables = $this->getTables()) {
|
||||
foreach ($tables as $table) {
|
||||
if ($tableerrors = $table->getAllErrors()) {
|
||||
|
||||
}
|
||||
}
|
||||
/// Add them to the errors array
|
||||
if ($tableerrors) {
|
||||
$errors = array_merge($errors, $tableerrors);
|
||||
}
|
||||
}
|
||||
/// Delegate to statements
|
||||
if ($statements = $this->getStatements()) {
|
||||
foreach ($statements as $statement) {
|
||||
if ($statement->getError()) {
|
||||
$errors[] = $statement->getError();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Return decision
|
||||
if (count($errors)) {
|
||||
return $errors;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,729 @@
|
||||
<?php // $Id$
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// NOTICE OF COPYRIGHT //
|
||||
// //
|
||||
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
|
||||
// http://moodle.com //
|
||||
// //
|
||||
// Copyright (C) 2001-3001 Martin Dougiamas http://dougiamas.com //
|
||||
// (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details: //
|
||||
// //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// This class represent one XMLDB table
|
||||
|
||||
class XMLDBTable extends XMLDBObject {
|
||||
|
||||
var $fields;
|
||||
var $keys;
|
||||
var $indexes;
|
||||
|
||||
/**
|
||||
* Creates one new XMLDBTable
|
||||
*/
|
||||
function XMLDBTable($name) {
|
||||
parent::XMLDBObject($name);
|
||||
$this->fields = array();
|
||||
$this->keys = array();
|
||||
$this->indexes = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add one field to the table, allowing to specify the desired order
|
||||
* If it's not specified, then the field is added at the end
|
||||
*/
|
||||
function addField(&$field, $after=NULL) {
|
||||
|
||||
/// Calculate the previous and next fields
|
||||
$prevfield = NULL;
|
||||
$nextfield = NULL;
|
||||
|
||||
if (!$after) {
|
||||
$allfields =& $this->getFields();
|
||||
if (!empty($allfields)) {
|
||||
end($allfields);
|
||||
$prevfield =& $allfields[key($allfields)];
|
||||
}
|
||||
} else {
|
||||
$prevfield =& $this->getField($after);
|
||||
}
|
||||
if ($prevfield && $prevfield->getNext()) {
|
||||
$nextfield =& $this->getField($prevfield->getNext());
|
||||
}
|
||||
|
||||
/// Set current field previous and next attributes
|
||||
if ($prevfield) {
|
||||
$field->setPrevious($prevfield->getName());
|
||||
$prevfield->setNext($field->getName());
|
||||
}
|
||||
if ($nextfield) {
|
||||
$field->setNext($nextfield->getName());
|
||||
$nextfield->setPrevious($field->getName());
|
||||
}
|
||||
/// Some more attributes
|
||||
$field->setLoaded(true);
|
||||
$field->setChanged(true);
|
||||
/// Add the new field
|
||||
$this->fields[] = $field;
|
||||
/// Reorder the field
|
||||
$this->orderFields($this->fields);
|
||||
/// Recalculate the hash
|
||||
$this->calculateHash(true);
|
||||
/// We have one new field, so the table has changed
|
||||
$this->setChanged(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add one key to the table, allowing to specify the desired order
|
||||
* If it's not specified, then the key is added at the end
|
||||
*/
|
||||
function addKey(&$key, $after=NULL) {
|
||||
|
||||
/// Calculate the previous and next keys
|
||||
$prevkey = NULL;
|
||||
$nextkey = NULL;
|
||||
|
||||
if (!$after) {
|
||||
$allkeys =& $this->getKeys();
|
||||
if (!empty($allkeys)) {
|
||||
end($allkeys);
|
||||
$prevkey =& $allkeys[key($allkeys)];
|
||||
}
|
||||
} else {
|
||||
$prevkey =& $this->getKey($after);
|
||||
}
|
||||
if ($prevkey && $prevkey->getNext()) {
|
||||
$nextkey =& $this->getKey($prevkey->getNext());
|
||||
}
|
||||
|
||||
/// Set current key previous and next attributes
|
||||
if ($prevkey) {
|
||||
$key->setPrevious($prevkey->getName());
|
||||
$prevkey->setNext($key->getName());
|
||||
}
|
||||
if ($nextkey) {
|
||||
$key->setNext($nextkey->getName());
|
||||
$nextkey->setPrevious($key->getName());
|
||||
}
|
||||
/// Some more attributes
|
||||
$key->setLoaded(true);
|
||||
$key->setChanged(true);
|
||||
/// Add the new key
|
||||
$this->keys[] = $key;
|
||||
/// Reorder the keys
|
||||
$this->orderKeys($this->keys);
|
||||
/// Recalculate the hash
|
||||
$this->calculateHash(true);
|
||||
/// We have one new field, so the table has changed
|
||||
$this->setChanged(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add one index to the table, allowing to specify the desired order
|
||||
* If it's not specified, then the index is added at the end
|
||||
*/
|
||||
function addIndex(&$index, $after=NULL) {
|
||||
|
||||
/// Calculate the previous and next indexes
|
||||
$previndex = NULL;
|
||||
$nextindex = NULL;
|
||||
|
||||
if (!$after) {
|
||||
$allindexes =& $this->getIndexes();
|
||||
if (!empty($allindexes)) {
|
||||
end($allindexes);
|
||||
$previndex =& $allindexes[key($allindexes)];
|
||||
}
|
||||
} else {
|
||||
$previndex =& $this->getIndex($after);
|
||||
}
|
||||
if ($previndex && $previndex->getNext()) {
|
||||
$nextindex =& $this->getIndex($previndex->getNext());
|
||||
}
|
||||
|
||||
/// Set current index previous and next attributes
|
||||
if ($previndex) {
|
||||
$index->setPrevious($previndex->getName());
|
||||
$previndex->setNext($index->getName());
|
||||
}
|
||||
if ($nextindex) {
|
||||
$index->setNext($nextindex->getName());
|
||||
$nextindex->setPrevious($index->getName());
|
||||
}
|
||||
|
||||
/// Some more attributes
|
||||
$index->setLoaded(true);
|
||||
$index->setChanged(true);
|
||||
/// Add the new index
|
||||
$this->indexes[] = $index;
|
||||
/// Reorder the indexes
|
||||
$this->orderIndexes($this->indexes);
|
||||
/// Recalculate the hash
|
||||
$this->calculateHash(true);
|
||||
/// We have one new index, so the table has changed
|
||||
$this->setChanged(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return the array of fields in the table
|
||||
*/
|
||||
function &getFields() {
|
||||
return $this->fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return the array of keys in the table
|
||||
*/
|
||||
function &getKeys() {
|
||||
return $this->keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return the array of indexes in the table
|
||||
*/
|
||||
function &getIndexes() {
|
||||
return $this->indexes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one XMLDBField
|
||||
*/
|
||||
function &getField($fieldname) {
|
||||
$i = $this->findFieldInArray($fieldname);
|
||||
if ($i !== NULL) {
|
||||
return $this->fields[$i];
|
||||
}
|
||||
$null = NULL;
|
||||
return $null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position of one field in the array.
|
||||
*/
|
||||
function &findFieldInArray($fieldname) {
|
||||
foreach ($this->fields as $i => $field) {
|
||||
if ($fieldname == $field->getName()) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
$null = NULL;
|
||||
return $null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will reorder the array of fields
|
||||
*/
|
||||
function orderFields() {
|
||||
$result =& $this->orderElements($this->fields);
|
||||
if ($result) {
|
||||
$this->setFields($result);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one XMLDBKey
|
||||
*/
|
||||
function &getKey($keyname) {
|
||||
$i = $this->findKeyInArray($keyname);
|
||||
if ($i !== NULL) {
|
||||
return $this->keys[$i];
|
||||
}
|
||||
$null = NULL;
|
||||
return $null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position of one key in the array.
|
||||
*/
|
||||
function &findKeyInArray($keyname) {
|
||||
foreach ($this->keys as $i => $key) {
|
||||
if ($keyname == $key->getName()) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
$null = NULL;
|
||||
return $null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will reorder the array of keys
|
||||
*/
|
||||
function orderKeys() {
|
||||
$result =& $this->orderElements($this->keys);
|
||||
if ($result) {
|
||||
$this->setKeys($result);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one XMLDBIndex
|
||||
*/
|
||||
function &getIndex($indexname) {
|
||||
$i = $this->findIndexInArray($indexname);
|
||||
if ($i !== NULL) {
|
||||
return $this->indexes[$i];
|
||||
}
|
||||
$null = NULL;
|
||||
return $null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position of one index in the array.
|
||||
*/
|
||||
function &findIndexInArray($indexname) {
|
||||
foreach ($this->indexes as $i => $index) {
|
||||
if ($indexname == $index->getName()) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
$null = NULL;
|
||||
return $null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will reorder the array of indexes
|
||||
*/
|
||||
function orderIndexes() {
|
||||
$result =& $this->orderElements($this->indexes);
|
||||
if ($result) {
|
||||
$this->setIndexes($result);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set the array of fields in the table
|
||||
*/
|
||||
function setFields($fields) {
|
||||
$this->fields = $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set the array of keys in the table
|
||||
*/
|
||||
function setKeys($keys) {
|
||||
$this->keys = $keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set the array of indexes in the table
|
||||
*/
|
||||
function setIndexes($indexes) {
|
||||
$this->indexes = $indexes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete one field from the table
|
||||
*/
|
||||
function deleteField($fieldname) {
|
||||
|
||||
$field =& $this->getField($fieldname);
|
||||
if ($field) {
|
||||
$i = $this->findFieldInArray($fieldname);
|
||||
$prevfield = NULL;
|
||||
$nextfield = NULL;
|
||||
/// Look for prev and next field
|
||||
$prevfield =& $this->getField($field->getPrevious());
|
||||
$nextfield =& $this->getField($field->getNext());
|
||||
/// Change their previous and next attributes
|
||||
if ($prevfield) {
|
||||
$prevfield->setNext($field->getNext());
|
||||
}
|
||||
if ($nextfield) {
|
||||
$nextfield->setPrevious($field->getPrevious());
|
||||
}
|
||||
/// Delete the field
|
||||
unset($this->fields[$i]);
|
||||
/// Reorder the whole structure
|
||||
$this->orderFields($this->fields);
|
||||
/// Recalculate the hash
|
||||
$this->calculateHash(true);
|
||||
/// We have one deleted field, so the table has changed
|
||||
$this->setChanged(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete one key from the table
|
||||
*/
|
||||
function deleteKey($keyname) {
|
||||
|
||||
$key =& $this->getKey($keyname);
|
||||
if ($key) {
|
||||
$i = $this->findKeyInArray($keyname);
|
||||
$prevkey = NULL;
|
||||
$nextkey = NULL;
|
||||
/// Look for prev and next key
|
||||
$prevkey =& $this->getKey($key->getPrevious());
|
||||
$nextkey =& $this->getKey($key->getNext());
|
||||
/// Change their previous and next attributes
|
||||
if ($prevkey) {
|
||||
$prevkey->setNext($key->getNext());
|
||||
}
|
||||
if ($nextkey) {
|
||||
$nextkey->setPrevious($key->getPrevious());
|
||||
}
|
||||
/// Delete the key
|
||||
unset($this->keys[$i]);
|
||||
/// Reorder the Keys
|
||||
$this->orderKeys($this->keys);
|
||||
/// Recalculate the hash
|
||||
$this->calculateHash(true);
|
||||
/// We have one deleted key, so the table has changed
|
||||
$this->setChanged(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete one index from the table
|
||||
*/
|
||||
function deleteIndex($indexname) {
|
||||
|
||||
$index =& $this->getIndex($indexname);
|
||||
if ($index) {
|
||||
$i = $this->findIndexInArray($indexname);
|
||||
$previndex = NULL;
|
||||
$nextindex = NULL;
|
||||
/// Look for prev and next index
|
||||
$previndex =& $this->getIndex($index->getPrevious());
|
||||
$nextindex =& $this->getIndex($index->getNext());
|
||||
/// Change their previous and next attributes
|
||||
if ($previndex) {
|
||||
$previndex->setNext($index->getNext());
|
||||
}
|
||||
if ($nextindex) {
|
||||
$nextindex->setPrevious($index->getPrevious());
|
||||
}
|
||||
/// Delete the index
|
||||
unset($this->indexes[$i]);
|
||||
/// Reorder the indexes
|
||||
$this->orderIndexes($this->indexes);
|
||||
/// Recalculate the hash
|
||||
$this->calculateHash(true);
|
||||
/// We have one deleted index, so the table has changed
|
||||
$this->setChanged(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load data from XML to the table
|
||||
*/
|
||||
function arr2XMLDBTable($xmlarr) {
|
||||
|
||||
$result = true;
|
||||
|
||||
/// Debug the table
|
||||
/// traverse_xmlize($xmlarr); //Debug
|
||||
/// print_object ($GLOBALS['traverse_array']); //Debug
|
||||
/// $GLOBALS['traverse_array']=""; //Debug
|
||||
|
||||
/// Process table attributes (name, comment, previoustable and nexttable)
|
||||
if (isset($xmlarr['@']['NAME'])) {
|
||||
$this->name = trim($xmlarr['@']['NAME']);
|
||||
} else {
|
||||
$this->errormsg = 'Missing NAME attribute';
|
||||
$result = false;
|
||||
}
|
||||
if (isset($xmlarr['@']['COMMENT'])) {
|
||||
$this->comment = trim($xmlarr['@']['COMMENT']);
|
||||
} else {
|
||||
$this->errormsg = 'Missing COMMENT attribute';
|
||||
$result = false;
|
||||
}
|
||||
if (isset($xmlarr['@']['PREVIOUS'])) {
|
||||
$this->previous = trim($xmlarr['@']['PREVIOUS']);
|
||||
}
|
||||
if (isset($xmlarr['@']['NEXT'])) {
|
||||
$this->next = trim($xmlarr['@']['NEXT']);
|
||||
}
|
||||
|
||||
/// Iterate over fields
|
||||
if (isset($xmlarr['#']['FIELDS']['0']['#']['FIELD'])) {
|
||||
foreach ($xmlarr['#']['FIELDS']['0']['#']['FIELD'] as $xmlfield) {
|
||||
if (!$result) { //Skip on error
|
||||
continue;
|
||||
}
|
||||
$name = trim($xmlfield['@']['NAME']);
|
||||
$field = new XMLDBField($name);
|
||||
$field->arr2XMLDBField($xmlfield);
|
||||
$this->fields[] = $field;
|
||||
if (!$field->isLoaded()) {
|
||||
$this->errormsg = 'Problem loading field ' . $name;
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Missing FIELDS section';
|
||||
$result = false;
|
||||
}
|
||||
|
||||
/// Perform some general checks over fields
|
||||
if ($result && $this->fields) {
|
||||
/// Check field names are ok (lowercase, a-z _-)
|
||||
if (!$this->checkNameValues($this->fields)) {
|
||||
$this->errormsg = 'Some FIELDS name values are incorrect';
|
||||
$result = false;
|
||||
}
|
||||
/// Check previous & next are ok (duplicates and existing fields)
|
||||
if ($result && !$this->checkPreviousNextValues($this->fields)) {
|
||||
$this->errormsg = 'Some FIELDS previous/next values are incorrect';
|
||||
$result = false;
|
||||
}
|
||||
/// Order fields
|
||||
if ($result && !$this->orderFields($this->fields)) {
|
||||
$this->errormsg = 'Error ordering the fields';
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterate over keys
|
||||
if (isset($xmlarr['#']['KEYS']['0']['#']['KEY'])) {
|
||||
foreach ($xmlarr['#']['KEYS']['0']['#']['KEY'] as $xmlkey) {
|
||||
if (!$result) { //Skip on error
|
||||
continue;
|
||||
}
|
||||
$name = trim($xmlkey['@']['NAME']);
|
||||
$key = new XMLDBKey($name);
|
||||
$key->arr2XMLDBKey($xmlkey);
|
||||
$this->keys[] = $key;
|
||||
if (!$key->isLoaded()) {
|
||||
$this->errormsg = 'Problem loading key ' . $name;
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->errormsg = 'Missing KEYS section (at least one PK must exist)';
|
||||
$result = false;
|
||||
}
|
||||
|
||||
/// Perform some general checks over keys
|
||||
if ($result && $this->keys) {
|
||||
/// Check keys names are ok (lowercase, a-z _-)
|
||||
if (!$this->checkNameValues($this->keys)) {
|
||||
$this->errormsg = 'Some KEYS name values are incorrect';
|
||||
$result = false;
|
||||
}
|
||||
/// Check previous & next are ok (duplicates and existing keys)
|
||||
if ($result && !$this->checkPreviousNextValues($this->keys)) {
|
||||
$this->errormsg = 'Some KEYS previous/next values are incorrect';
|
||||
$result = false;
|
||||
}
|
||||
/// Order keys
|
||||
if ($result && !$this->orderKeys($this->keys)) {
|
||||
$this->errormsg = 'Error ordering the keys';
|
||||
$result = false;
|
||||
}
|
||||
/// TODO: Only one PK
|
||||
/// TODO: Not keys with repeated fields
|
||||
/// TODO: Check fields and reffieds exist in table
|
||||
}
|
||||
|
||||
/// Iterate over indexes
|
||||
if (isset($xmlarr['#']['INDEXES']['0']['#']['INDEX'])) {
|
||||
foreach ($xmlarr['#']['INDEXES']['0']['#']['INDEX'] as $xmlindex) {
|
||||
if (!$result) { //Skip on error
|
||||
continue;
|
||||
}
|
||||
$name = trim($xmlindex['@']['NAME']);
|
||||
$index = new XMLDBIndex($name);
|
||||
$index->arr2XMLDBIndex($xmlindex);
|
||||
$this->indexes[] = $index;
|
||||
if (!$index->isLoaded()) {
|
||||
$this->errormsg = 'Problem loading index ' . $name;
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform some general checks over indexes
|
||||
if ($result && $this->indexes) {
|
||||
/// Check field names are ok (lowercase, a-z _-)
|
||||
if (!$this->checkNameValues($this->indexes)) {
|
||||
$this->errormsg = 'Some INDEXES name values are incorrect';
|
||||
$result = false;
|
||||
}
|
||||
/// Check previous & next are ok (duplicates and existing INDEXES)
|
||||
if ($result && !$this->checkPreviousNextValues($this->indexes)) {
|
||||
$this->errormsg = 'Some INDEXES previous/next values are incorrect';
|
||||
$result = false;
|
||||
}
|
||||
/// Order indexes
|
||||
if ($result && !$this->orderIndexes($this->indexes)) {
|
||||
$this->errormsg = 'Error ordering the indexes';
|
||||
$result = false;
|
||||
}
|
||||
/// TODO: Not indexes with repeated fields
|
||||
/// TODO: Check fields exist in table
|
||||
}
|
||||
|
||||
/// Set some attributes
|
||||
if ($result) {
|
||||
$this->loaded = true;
|
||||
}
|
||||
$this->calculateHash();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function calculate and set the hash of one XMLDBTable
|
||||
*/
|
||||
function calculateHash($recursive = false) {
|
||||
if (!$this->loaded) {
|
||||
$this->hash = NULL;
|
||||
} else {
|
||||
$key = $this->name . $this->comment;
|
||||
if ($this->fields) {
|
||||
foreach ($this->fields as $fie) {
|
||||
$field =& $this->getField($fie->getName());
|
||||
if ($recursive) {
|
||||
$field->calculateHash($recursive);
|
||||
}
|
||||
$key .= $field->getHash();
|
||||
}
|
||||
}
|
||||
if ($this->keys) {
|
||||
foreach ($this->keys as $ke) {
|
||||
$k =& $this->getKey($ke->getName());
|
||||
if ($recursive) {
|
||||
$k->calculateHash($recursive);
|
||||
}
|
||||
$key .= $k->getHash();
|
||||
}
|
||||
}
|
||||
if ($this->indexes) {
|
||||
foreach ($this->indexes as $in) {
|
||||
$index =& $this->getIndex($in->getName());
|
||||
if ($recursive) {
|
||||
$index->calculateHash($recursive);
|
||||
}
|
||||
$key .= $index->getHash();
|
||||
}
|
||||
}
|
||||
$this->hash = md5($key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will output the XML text for one table
|
||||
*/
|
||||
function xmlOutput() {
|
||||
$o = '';
|
||||
$o.= ' <TABLE NAME="' . $this->name . '"';
|
||||
if ($this->comment) {
|
||||
$o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
|
||||
}
|
||||
if ($this->previous) {
|
||||
$o.= ' PREVIOUS="' . $this->previous . '"';
|
||||
}
|
||||
if ($this->next) {
|
||||
$o.= ' NEXT="' . $this->next . '"';
|
||||
}
|
||||
$o.= '>' . "\n";
|
||||
/// Now the fields
|
||||
if ($this->fields) {
|
||||
$o.= ' <FIELDS>' . "\n";
|
||||
foreach ($this->fields as $field) {
|
||||
$o.= $field->xmlOutput();
|
||||
}
|
||||
$o.= ' </FIELDS>' . "\n";
|
||||
}
|
||||
/// Now the keys
|
||||
if ($this->keys) {
|
||||
$o.= ' <KEYS>' . "\n";
|
||||
foreach ($this->keys as $key) {
|
||||
$o.= $key->xmlOutput();
|
||||
}
|
||||
$o.= ' </KEYS>' . "\n";
|
||||
}
|
||||
/// Now the indexes
|
||||
if ($this->indexes) {
|
||||
$o.= ' <INDEXES>' . "\n";
|
||||
foreach ($this->indexes as $index) {
|
||||
$o.= $index->xmlOutput();
|
||||
}
|
||||
$o.= ' </INDEXES>' . "\n";
|
||||
}
|
||||
$o.= ' </TABLE>' . "\n";
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return all the errors found in one table
|
||||
* looking recursively inside each field/key/index. Returns
|
||||
* an array of errors or false
|
||||
*/
|
||||
function getAllErrors() {
|
||||
|
||||
$errors = array();
|
||||
/// First the table itself
|
||||
if ($this->getError()) {
|
||||
$errors[] = $this->getError();
|
||||
}
|
||||
/// Delegate to fields
|
||||
if ($fields = $this->getFields()) {
|
||||
foreach ($fields as $field) {
|
||||
if ($field->getError()) {
|
||||
$errors[] = $field->getError();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Delegate to keys
|
||||
if ($keys = $this->getKeys()) {
|
||||
foreach ($keys as $key) {
|
||||
if ($key->getError()) {
|
||||
$errors[] = $key->getError();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Delegate to indexes
|
||||
if ($indexes = $this->getIndexes()) {
|
||||
foreach ($indexes as $index) {
|
||||
if ($index->getError()) {
|
||||
$errors[] = $index->getError();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Return decision
|
||||
if (count($errors)) {
|
||||
return $errors;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return the SQL code needed to create the table for the specified DB and
|
||||
* prefix. Just one simple wrapper over generators.
|
||||
*/
|
||||
function getCreateTableSQL ($dbtype, $prefix) {
|
||||
$classname = 'XMLDB' . $dbtype;
|
||||
$generator = new $classname();
|
||||
$generator->setPrefix($prefix);
|
||||
return $generator->getCreateTableSQL($this);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,228 @@
|
||||
<?php // $Id$
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// NOTICE OF COPYRIGHT //
|
||||
// //
|
||||
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
|
||||
// http://moodle.com //
|
||||
// //
|
||||
// Copyright (C) 2001-3001 Martin Dougiamas http://dougiamas.com //
|
||||
// (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details: //
|
||||
// //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// This class represent the base generator class where all the
|
||||
/// needed functions to generate proper SQL are defined.
|
||||
|
||||
/// If fact, this class generate SQL code to be used against MySQL
|
||||
/// so the rest of classes will inherit, by default, the same logic.
|
||||
/// Functions will be overriden as needed to generate correct SQL.
|
||||
|
||||
class XMLDBmysql {
|
||||
|
||||
var $quote_string = '`'; // String used to quote names
|
||||
|
||||
var $primary_keys = true; // Does the constructor build primary keys
|
||||
var $unique_keys = false; // Does the constructor build unique keys
|
||||
var $foreign_keys = false; // Does the constructor build foreign keys
|
||||
|
||||
var $primary_index = false;// Does the constructor need to build one index for primary keys
|
||||
var $unique_index = true; // Does the constructor need to build one index for unique keys
|
||||
var $foreign_index = true; // Does the constructor need to build one index for foreign keys
|
||||
|
||||
var $prefix; // Prefix to be used for all the DB objects
|
||||
|
||||
|
||||
/**
|
||||
* Creates one new XMLDBmysql
|
||||
*/
|
||||
function XMLDBmysql() {
|
||||
global $CFG;
|
||||
$this->prefix = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the prefix
|
||||
*/
|
||||
function setPrefix($prefix) {
|
||||
$this->prefix = $prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
|
||||
*/
|
||||
function getType ($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
|
||||
|
||||
switch ($xmldb_type) {
|
||||
case XMLDB_TYPE_INTEGER: // From http://mysql.com/doc/refman/5.0/en/numeric-types.html!
|
||||
if (empty($xmldb_length)) {
|
||||
$xmldb_length = 10;
|
||||
}
|
||||
if ($xmldb_length > 9) {
|
||||
$dbtype = 'BIGINT';
|
||||
$xmldb_length = 10;
|
||||
} else if ($xmldb_length > 6) {
|
||||
$dbtype = 'INT';
|
||||
} else if ($xmldb_length > 4) {
|
||||
$dbtype = 'MEDIUMINT';
|
||||
} else if ($xmldb_length > 2) {
|
||||
$dbtype = 'SMALLINT';
|
||||
} else {
|
||||
$dbtype = 'TINTINT';
|
||||
}
|
||||
$dbtype .= '(' . $xmldb_length . ')';
|
||||
break;
|
||||
case XMLDB_TYPE_NUMBER:
|
||||
$dbtype = 'DECIMAL';
|
||||
if (!empty($xmldb_length)) {
|
||||
$dbtype .= '(' . $xmldb_length;
|
||||
if (!empty($xmldb_decimals)) {
|
||||
$dbtype .= ',' . $xmldb_decimals;
|
||||
}
|
||||
$dbtype .= ')';
|
||||
}
|
||||
break;
|
||||
case XMLDB_TYPE_FLOAT:
|
||||
$dbtype = 'FLOAT';
|
||||
if (!empty($xmldb_length)) {
|
||||
$dbtype .= '(' . $xmldb_length;
|
||||
if (!empty($xmldb_decimals)) {
|
||||
$dbtype .= ',' . $xmldb_decimals;
|
||||
}
|
||||
$dbtype .= ')';
|
||||
}
|
||||
break;
|
||||
case XMLDB_TYPE_CHAR:
|
||||
$dbtype = 'VARCHAR';
|
||||
if (!empty($xmldb_length)) {
|
||||
$xmldb_length='255';
|
||||
}
|
||||
$dbtype .= '(' . $xmldb_length . ')';
|
||||
break;
|
||||
case XMLDB_TYPE_TEXT:
|
||||
if (empty($xmldb_length)) {
|
||||
$xmldb_length = 'small';
|
||||
}
|
||||
if ($xmldb_length = 'small') {
|
||||
$dbtype = 'TEXT';
|
||||
} else if ($xmldb_length = 'medium') {
|
||||
$dbtype = 'MEDIUMTEXT';
|
||||
} else {
|
||||
$dbtype = 'BIGTEXT';
|
||||
}
|
||||
break;
|
||||
case XMLDB_TYPE_BINARY:
|
||||
if (empty($xmldb_length)) {
|
||||
$xmldb_length = 'small';
|
||||
}
|
||||
if ($xmldb_length = 'small') {
|
||||
$dbtype = 'BLOB';
|
||||
} else if ($xmldb_length = 'medium') {
|
||||
$dbtype = 'MEDIUMBLOB';
|
||||
} else {
|
||||
$dbtype = 'BIGBLOB';
|
||||
}
|
||||
break;
|
||||
case XMLDB_TYPE_DATETIME:
|
||||
$dbtype = 'DATETIME';
|
||||
}
|
||||
return $dbtype;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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->getCreateFieldSQL($xmldb_field) . ',';
|
||||
}
|
||||
/// Table footer, trim the latest comma
|
||||
$table = trim($table,',');
|
||||
$table .= "\n)";
|
||||
if ($xmldb_table->getComment()) {
|
||||
$table .= " COMMENT='" . $xmldb_table->getComment() . "';\n\n";
|
||||
}
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given one correct XMLDBField, returns the complete SQL line to create it
|
||||
*/
|
||||
function getCreateFieldSQL($xmldb_field) {
|
||||
|
||||
/// The name
|
||||
$field = $this->getEncQuoted($xmldb_field->getName());
|
||||
/// The type and length (if the field isn't enum)
|
||||
if (!$xmldb_field->getEnum()) {
|
||||
$field .= ' ' . $this->getType($xmldb_field->getType(), $xmldb_field->getLength(), $xmldb_field->getDecimals());
|
||||
} else {
|
||||
/// If enum, do it with its values
|
||||
$field .= ' enum(' . implode(', ', $xmldb_field->getEnumValues()) . ')';
|
||||
}
|
||||
/// The unsigned
|
||||
if ($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 .= ' auto_increment';
|
||||
}
|
||||
/// 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 ($xmldb_field->getType() == XMLDB_TYPE_CHAR &&
|
||||
$xmldb_field->getNotNull()) {
|
||||
$field .= ' default ' . "''";
|
||||
}
|
||||
}
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given any string, enclose it by the proper quotes
|
||||
*/
|
||||
function getEncQuoted($string) {
|
||||
return $this->quote_string . $string . $this->quote_string;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,62 @@
|
||||
<!ELEMENT FIELD EMPTY >
|
||||
<!ATTLIST FIELD DECIMALS NMTOKEN #IMPLIED >
|
||||
<!ATTLIST FIELD DEFAULT NMTOKEN #IMPLIED >
|
||||
<!ATTLIST FIELD ENUM ( false | true ) #REQUIRED >
|
||||
<!ATTLIST FIELD ENUMVALUES CDATA #IMPLIED >
|
||||
<!ATTLIST FIELD LENGTH NMTOKEN #REQUIRED >
|
||||
<!ATTLIST FIELD NAME NMTOKEN #REQUIRED >
|
||||
<!ATTLIST FIELD NEXT NMTOKEN #IMPLIED >
|
||||
<!ATTLIST FIELD NOTNULL ( false | true ) #REQUIRED >
|
||||
<!ATTLIST FIELD PREVIOUS NMTOKEN #IMPLIED >
|
||||
<!ATTLIST FIELD SEQUENCE ( false | true ) #REQUIRED >
|
||||
<!ATTLIST FIELD TYPE ( binary | char | float | int | number | text ) #REQUIRED >
|
||||
<!ATTLIST FIELD UNSIGNED ( false | true ) #IMPLIED >
|
||||
|
||||
<!ELEMENT FIELDS ( FIELD+ ) >
|
||||
|
||||
<!ELEMENT INDEX EMPTY >
|
||||
<!ATTLIST INDEX COMMENT CDATA #IMPLIED >
|
||||
<!ATTLIST INDEX FIELDS CDATA #REQUIRED >
|
||||
<!ATTLIST INDEX NAME NMTOKEN #REQUIRED >
|
||||
<!ATTLIST INDEX NEXT NMTOKEN #IMPLIED >
|
||||
<!ATTLIST INDEX PREVIOUS NMTOKEN #IMPLIED >
|
||||
<!ATTLIST INDEX UNIQUE ( false | true ) #REQUIRED >
|
||||
|
||||
<!ELEMENT INDEXES ( INDEX+ ) >
|
||||
|
||||
<!ELEMENT KEY EMPTY >
|
||||
<!ATTLIST KEY COMMENT CDATA #IMPLIED >
|
||||
<!ATTLIST KEY FIELDS CDATA #REQUIRED >
|
||||
<!ATTLIST KEY NAME NMTOKEN #REQUIRED >
|
||||
<!ATTLIST KEY NEXT NMTOKEN #IMPLIED >
|
||||
<!ATTLIST KEY PREVIOUS NMTOKEN #IMPLIED >
|
||||
<!ATTLIST KEY TYPE ( primary | unique | foreign ) #REQUIRED >
|
||||
|
||||
<!ELEMENT KEYS ( KEY+ ) >
|
||||
|
||||
<!ELEMENT SENTENCE EMPTY >
|
||||
<!ATTLIST SENTENCE TEXT CDATA #REQUIRED >
|
||||
|
||||
<!ELEMENT SENTENCES ( SENTENCE+ ) >
|
||||
|
||||
<!ELEMENT STATEMENT ( SENTENCES ) >
|
||||
<!ATTLIST STATEMENT COMMENT CDATA #REQUIRED >
|
||||
<!ATTLIST STATEMENT NAME CDATA #REQUIRED >
|
||||
<!ATTLIST STATEMENT TABLE NMTOKEN #REQUIRED >
|
||||
<!ATTLIST STATEMENT TYPE NMTOKEN #REQUIRED >
|
||||
|
||||
<!ELEMENT STATEMENTS ( STATEMENT ) >
|
||||
|
||||
<!ELEMENT TABLE ( FIELDS, KEYS, INDEXES? ) >
|
||||
<!ATTLIST TABLE COMMENT CDATA #REQUIRED >
|
||||
<!ATTLIST TABLE NAME ID #REQUIRED >
|
||||
<!ATTLIST TABLE NEXT NMTOKEN #IMPLIED >
|
||||
<!ATTLIST TABLE PREVIOUS NMTOKEN #IMPLIED >
|
||||
|
||||
<!ELEMENT TABLES ( TABLE+ ) >
|
||||
|
||||
<!ELEMENT XMLDB ( TABLES, STATEMENTS ) >
|
||||
<!ATTLIST XMLDB COMMENT CDATA #REQUIRED >
|
||||
<!ATTLIST XMLDB PATH CDATA #REQUIRED >
|
||||
<!ATTLIST XMLDB VERSION NMTOKEN #REQUIRED >
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:element name="FIELD">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="ENUM" use="required">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="false" />
|
||||
<xs:enumeration value="true" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="LENGTH" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="DECIMALS" type="xs:NMTOKEN" use="optional" />
|
||||
<xs:attribute name="NEXT" type="xs:NMTOKEN" use="optional" />
|
||||
<xs:attribute name="SEQUENCE" use="required">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="false" />
|
||||
<xs:enumeration value="true" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="ENUMVALUES" type="xs:string" use="optional" />
|
||||
<xs:attribute name="DEFAULT" type="xs:NMTOKEN" use="optional" />
|
||||
<xs:attribute name="TYPE" use="required">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="binary" />
|
||||
<xs:enumeration value="char" />
|
||||
<xs:enumeration value="float" />
|
||||
<xs:enumeration value="int" />
|
||||
<xs:enumeration value="number" />
|
||||
<xs:enumeration value="text" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="UNSIGNED" use="optional">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="false" />
|
||||
<xs:enumeration value="true" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="PREVIOUS" type="xs:NMTOKEN" use="optional" />
|
||||
<xs:attribute name="NOTNULL" use="required">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="false" />
|
||||
<xs:enumeration value="true" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="NAME" type="xs:NMTOKEN" use="required" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="FIELDS">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="FIELD" maxOccurs="unbounded" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="INDEX">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="PREVIOUS" type="xs:NMTOKEN" use="optional" />
|
||||
<xs:attribute name="COMMENT" type="xs:string" use="optional" />
|
||||
<xs:attribute name="UNIQUE" use="required">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="false" />
|
||||
<xs:enumeration value="true" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="NAME" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="FIELDS" type="xs:string" use="required" />
|
||||
<xs:attribute name="NEXT" type="xs:NMTOKEN" use="optional" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="INDEXES">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="INDEX" maxOccurs="unbounded" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="KEY">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="PREVIOUS" type="xs:NMTOKEN" use="optional" />
|
||||
<xs:attribute name="COMMENT" type="xs:string" use="optional" />
|
||||
<xs:attribute name="NAME" use="required">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="name" />
|
||||
<xs:enumeration value="plugin_name" />
|
||||
<xs:enumeration value="primary" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="FIELDS" type="xs:string" use="required" />
|
||||
<xs:attribute name="TYPE" use="required">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="primary" />
|
||||
<xs:enumeration value="unique" />
|
||||
<xs:enumeration value="foreign" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="NEXT" type="xs:NMTOKEN" use="optional" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="KEYS">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="KEY" maxOccurs="unbounded" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="SENTENCE">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="TEXT" type="xs:string" use="required" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="SENTENCES">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="SENTENCE" maxOccurs="unbounded" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="STATEMENT">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="SENTENCES" />
|
||||
</xs:sequence>
|
||||
<xs:attribute name="COMMENT" type="xs:string" use="required" />
|
||||
<xs:attribute name="TABLE" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="NAME" type="xs:string" use="required" />
|
||||
<xs:attribute name="TYPE" type="xs:NMTOKEN" use="required" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="STATEMENTS">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="STATEMENT" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="TABLE">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="FIELDS" />
|
||||
<xs:element ref="KEYS" />
|
||||
<xs:element ref="INDEXES" minOccurs="0" />
|
||||
</xs:sequence>
|
||||
<xs:attribute name="PREVIOUS" type="xs:NMTOKEN" use="optional" />
|
||||
<xs:attribute name="COMMENT" type="xs:string" use="required" />
|
||||
<xs:attribute name="NAME" type="xs:ID" use="required" />
|
||||
<xs:attribute name="NEXT" type="xs:NMTOKEN" use="optional" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="TABLES">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="TABLE" maxOccurs="unbounded" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="XMLDB">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="TABLES" />
|
||||
<xs:element ref="STATEMENTS" />
|
||||
</xs:sequence>
|
||||
<xs:attribute name="PATH" type="xs:string" use="required" />
|
||||
<xs:attribute name="COMMENT" type="xs:string" use="required" />
|
||||
<xs:attribute name="VERSION" type="xs:NMTOKEN" use="required" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
</xs:schema>
|
||||
Reference in New Issue
Block a user