tableName = $name; } /** * Adds a field to a table object * * $name is the name of the table to which the field should be added. * $type is an ADODB datadict field type. The following field types * are supported as of ADODB 3.40: * - C: varchar * - X: CLOB (character large object) or largest varchar size * if CLOB is not supported * - C2: Multibyte varchar * - X2: Multibyte CLOB * - B: BLOB (binary large object) * - D: Date (some databases do not support this, and we return a datetime type) * - T: Datetime or Timestamp * - L: Integer field suitable for storing booleans (0 or 1) * - I: Integer (mapped to I4) * - I1: 1-byte integer * - I2: 2-byte integer * - I4: 4-byte integer * - I8: 8-byte integer * - F: Floating point number * - N: Numeric or decimal number * * @param string $name Name of the table to which the field will be added. * @param string $type ADODB datadict field type. * @param string $size Field size * @param array $opts Field options array * @return array Field specifier array */ function addField( $name, $type, $size = NULL, $opts = NULL ) { // Set the field index so we know where we are $this->currentField = $name; // Set the field type (required) $this->fieldSpec[$name]['TYPE'] = $type; // Set the field size (optional) if( isset( $size ) ) { $this->fieldSpec[$name]['SIZE'] = $size; } // Set the field options if( isset( $opts ) ) $this->fieldSpec[$name]['OPTS'] = $opts; // Return array containing field specifier return $this->fieldSpec; } /** * Adds a field option to the current field specifier * * This method adds a field option allowed by the ADOdb datadict * and appends it to the given field. * * @param string $field Field name * @param string $opt ADOdb field option * @param mixed $value Field option value * @return array Field specifier array */ function addFieldOpt( $field, $opt, $value = NULL ) { // Add the option to the field specifier if( $value === NULL ) { // No value, so add only the option $this->fieldSpec[$field]['OPTS'][] = $opt; } else { // Add the option and value $this->fieldSpec[$field]['OPTS'][] = array( "$opt" => "$value" ); } // Return array containing field specifier return $this->fieldSpec; } /** * Adds an option to the table * *This method takes a comma-separated list of table-level options * and appends them to the table object. * * @param string $opt Table option * @return string Option list */ function addTableOpt( $opt ) { $optlist = &$this->tableOpts; $optlist ? $optlist .= ", $opt" : $optlist = $opt; // Return the options list return $optlist; } /** * Generates the SQL that will create the table in the database * * Returns SQL that will create the table represented by the object. * * @param object $dict ADOdb data dictionary * @return array Array containing table creation SQL */ function create( $dict ) { // Loop through the field specifier array, building the associative array for the field options $fldarray = array(); $i = 0; foreach( $this->fieldSpec as $field => $finfo ) { $i++; // Set an empty size if it isn't supplied if( !isset( $finfo['SIZE'] ) ) $finfo['SIZE'] = ''; // Initialize the field array with the type and size $fldarray[$i] = array( $field, $finfo['TYPE'], $finfo['SIZE'] ); // Loop through the options array and add the field options. $opts = $finfo['OPTS']; if( $opts ) { foreach( $finfo['OPTS'] as $opt ) { if( is_array( $opt ) ) { // Option has an argument. $key = key( $opt ); $value = $opt[key( $opt ) ]; $fldarray[$i][$key] = $value; } else { // Option doesn't have arguments array_push( $fldarray[$i], $opt ); } } } } // Build table array $sqlArray = $dict->CreateTableSQL( $this->tableName, $fldarray, $this->tableOpts ); // Return the array containing the SQL to create the table return $sqlArray; } /** * Destructor */ function destroy() { unset( $this ); } } /** * Creates an index object in ADOdb's datadict format * * This class stores information about a database index. As charactaristics * of the index are loaded from the external source, methods and properties * of this class are used to build up the index description in ADOdb's * datadict format. * * @package xmlschema * @access private */ class dbIndex { /** * @var string Index name */ var $indexName; /** * @var string Name of the table this index is attached to */ var $tableName; /** * @var array Indexed fields: Table columns included in this index */ var $fields; /** * Constructor. Initialize the index and table names. * * @param string $name Index name * @param string $table Name of indexed table */ function dbIndex( $name, $table ) { $this->indexName = $name; $this->tableName = $table; } /** * Adds a field to the index * * This method adds the specified column to an index. * * @param string $name Field name * @return string Field list */ function addField( $name ) { $fieldlist = &$this->fields; $fieldlist ? $fieldlist .=" , $name" : $fieldlist = $name; // Return the field list return $fieldlist; } /** * Generates the SQL that will create the index in the database * * Returns SQL that will create the index represented by the object. * * @param object $dict ADOdb data dictionary object * @return array Array containing index creation SQL */ function create( $dict ) { // Build table array $sqlArray = $dict->CreateIndexSQL( $this->indexName, $this->tableName, $this->fields ); // Return the array containing the SQL to create the table return $sqlArray; } /** * Destructor */ function destroy() { unset( $this ); } } /** * Creates the SQL to execute a list of provided SQL queries * * This class compiles a list of SQL queries specified in the external file. * * @package xmlschema * @access private */ class dbQuerySet { /** * @var array List of SQL queries */ var $querySet; /** * @var string String used to build of a query line by line */ var $query; /** * Constructor. Initializes the queries array */ function dbQuerySet() { $this->querySet = array(); $this->query = ''; } /** * Appends a line to a query that is being built line by line * * $param string $data Line of SQL data or NULL to initialize a new query */ function buildQuery( $data = NULL ) { isset( $data ) ? $this->query .= " " . trim( $data ) : $this->query = ''; } /** * Adds a completed query to the query list * * @return string SQL of added query */ function addQuery() { // Push the query onto the query set array $finishedQuery = $this->query; array_push( $this->querySet, $finishedQuery ); // Return the query set array return $finishedQuery; } /** * Creates and returns the current query set * * @return array Query set */ function create() { return $this->querySet; } /** * Destructor */ function destroy() { unset( $this ); } } /** * Loads and parses an XML file, creating an array of "ready-to-run" SQL statements * * This class is used to load and parse the XML file, to create an array of SQL statements * that can be used to build a database, and to build the database using the SQL array. * * @package xmlschema */ class adoSchema { /** * @var array Array containing SQL queries to generate all objects */ var $sqlArray; /** * @var object XML Parser object */ var $xmlParser; /** * @var object ADOdb connection object */ var $dbconn; /** * @var string Database type (platform) */ var $dbType; /** * @var object ADOdb Data Dictionary */ var $dict; /** * @var object Temporary dbTable object * @access private */ var $table; /** * @var object Temporary dbIndex object * @access private */ var $index; /** * @var object Temporary dbQuerySet object * @access private */ var $querySet; /** * @var string Current XML element * @access private */ var $currentElement; /** * @var long Original Magic Quotes Runtime value * @access private */ var $mgq; /** * Constructor. Initializes the xmlschema object * * @param object $dbconn ADOdb connection object */ function adoSchema( $dbconn ) { // Initialize the environment $this->mgq = get_magic_quotes_runtime(); set_magic_quotes_runtime(0); $this->dbconn = &$dbconn; $this->dbType = $dbconn->databaseType; $this->sqlArray = array(); // Create an ADOdb dictionary object $this->dict = NewDataDictionary( $dbconn ); } /** * Loads and parses an XML file * * This method accepts a path to an xmlschema-compliant XML file, * loads it, parses it, and uses it to create the SQL to generate the objects * described by the XML file. * * @param string $file XML file * @return array Array of SQL queries, ready to execute */ function ParseSchema( $file ) { // Create the parser $this->xmlParser = &$xmlParser; $xmlParser = xml_parser_create(); xml_set_object( $xmlParser, &$this ); // Initialize the XML callback functions xml_set_element_handler( $xmlParser, "_xmlcb_startElement", "_xmlcb_endElement" ); xml_set_character_data_handler( $xmlParser, "_xmlcb_cData" ); // Open the file if( !( $fp = fopen( $file, "r" ) ) ) { die( "Unable to open file" ); } // Process the file while( $data = fread( $fp, 4096 ) ) { if( !xml_parse( $xmlParser, $data, feof( $fp ) ) ) { die( sprint( "XML error: %s at line %d", xml_error_string( xml_get_error_code( $xmlParser ) ), xml_get_current_line_number( $xmlParser ) ) ); } } // Return the array of queries return $this->sqlArray; } /** * Loads a schema into the database * * Accepts an array of SQL queries generated by the parser * and executes them. * * @param array $sqlArray Array of SQL statements * @param boolean $continueOnErr Don't fail out if an error is encountered * @return integer 0 if failed, 1 if errors, 2 if successful */ function ExecuteSchema( $sqlArray, $continueOnErr = TRUE ) { $err = $this->dict->ExecuteSQLArray( $sqlArray, $continueOnErr ); // Return the success code return $err; } /** * XML Callback to process start elements * * @access private */ function _xmlcb_startElement( $parser, $name, $attrs ) { $dbType = $this->dbType; if( isset( $this->table ) ) $table = &$this->table; if( isset( $this->index ) ) $index = &$this->index; if( isset( $this->querySet ) ) $querySet = &$this->querySet; $this->currentElement = $name; // Process the element. Ignore unimportant elements. if( in_array( trim( $name ), array( "SCHEMA", "DESCR", "COL", "CONSTRAINT" ) ) ) { return FALSE; } switch( $name ) { case "TABLE": // Table element if( $this->supportedPlatform( $attrs['PLATFORM'] ) ) { $this->table = new dbTable( $attrs['NAME'] ); } else { unset( $this->table ); } break; case "FIELD": // Table field if( isset( $this->table ) ) { $fieldName = $attrs['NAME']; $fieldType = $attrs['TYPE']; isset( $attrs['SIZE'] ) ? $fieldSize = $attrs['SIZE'] : $fieldSize = NULL; isset( $attrs['OPTS'] ) ? $fieldOpts = $attrs['OPTS'] : $fieldOpts = NULL; $this->table->addField( $fieldName, $fieldType, $fieldSize, $fieldOpts ); } break; case "KEY": // Table field option if( isset( $this->table ) ) { $this->table->addFieldOpt( $this->table->currentField, 'KEY' ); } break; case "NOTNULL": // Table field option if( isset( $this->table ) ) { $this->table->addFieldOpt( $this->table->currentField, 'NOTNULL' ); } break; case "AUTOINCREMENT": // Table field option if( isset( $this->table ) ) { $this->table->addFieldOpt( $this->table->currentField, 'AUTOINCREMENT' ); } break; case "DEFAULT": // Table field option if( isset( $this->table ) ) { $this->table->addFieldOpt( $this->table->currentField, 'DEFAULT', $attrs['VALUE'] ); } break; case "INDEX": // Table index if( $this->supportedPlatform( $attrs['PLATFORM'] ) ) { $this->index = new dbIndex( $attrs['NAME'], $attrs['TABLE'] ); } else { if( isset( $this->index ) ) unset( $this->index ); } break; case "SQL": // Freeform SQL queryset if( $this->supportedPlatform( $attrs['PLATFORM'] ) ) { $this->querySet = new dbQuerySet( $attrs ); } else { if( isset( $this->querySet ) ) unset( $this->querySet ); } break; case "QUERY": // Queryset SQL query if( isset( $this->querySet ) ) { // Ignore this query set if a platform is specified and it's different than the // current connection platform. if( $this->supportedPlatform( $attrs['PLATFORM'] ) ) { $this->querySet->buildQuery(); } else { if( isset( $this->querySet->query ) ) unset( $this->querySet->query ); } } break; default: print "OPENING ELEMENT '$name'
\n"; } } /** * XML Callback to process cDATA elements * * @access private */ function _xmlcb_cData( $parser, $data ) { $element = &$this->currentElement; if( trim( $data ) == "" ) return; // Process the data depending on the element switch( $element ) { case "COL": // Index column if( isset( $this->index ) ) $this->index->addField( $data ); break; case "DESCR": // Description element // Display the description information if( isset( $this->table ) ) { $name = "({$this->table->tableName}): "; } elseif( isset( $this->index ) ) { $name = "({$this->index->indexName}): "; } else { $name = ""; } print "
  • $name $data\n"; break; case "QUERY": // Query SQL data if( isset( $this->querySet ) and isset( $this->querySet->query ) ) $this->querySet->buildQuery( $data ); break; case "CONSTRAINT": // Table constraint if( isset( $this->table ) ) $this->table->addTableOpt( $data ); break; default: print "\n"; } } /** * XML Callback to process end elements * * @access private */ function _xmlcb_endElement( $parser, $name ) { // Process the element. Ignore unimportant elements. if( in_array( trim( $name ), array( "SCHEMA", "DESCR", "KEY", "AUTOINCREMENT", "FIELD", "DEFAULT", "NOTNULL", "CONSTRAINT", "COL" ) ) ) { return FALSE; } switch( trim( $name ) ) { case "TABLE": // Table element if( isset( $this->table ) ) { $tableSQL = $this->table->create( $this->dict ); array_push( $this->sqlArray, $tableSQL[0] ); $this->table->destroy(); } break; case "INDEX": // Index element if( isset( $this->index ) ) { $indexSQL = $this->index->create( $this->dict ); array_push( $this->sqlArray, $indexSQL[0] ); $this->index->destroy(); } break; case "QUERY": // Queryset element if( isset( $this->querySet ) and isset( $this->querySet->query ) ) $this->querySet->addQuery(); break; case "SQL": // Query SQL element if( isset( $this->querySet ) ) { $querySQL = $this->querySet->create(); $this->sqlArray = array_merge( $this->sqlArray, $querySQL );; $this->querySet->destroy(); } break; default: print "
  • CLOSING $name\n"; } } /** * Checks if element references a specific platform * * Returns TRUE is no platform is specified or if we are currently * using the specified platform. * * @param string $platform Requested platform * @return boolean TRUE if platform check succeeds * * @access private */ function supportedPlatform( $platform = NULL ) { $dbType = $this->dbType; $regex = "/^(\w*\|)*" . $dbType . "(\|\w*)*$/"; if( !isset( $platform ) or preg_match( $regex, $platform ) ) { return TRUE; } else { return FALSE; } } /** * Destructor */ function Destroy() { xml_parser_free( $this->xmlParser ); set_magic_quotes_runtime( $this->mgq ); unset( $this ); } } ?>