"TYPO3 4.0.1: typo3_src-4.0.1/typo3/sysext/adodb/adodb/adodb-xmlschema03.inc.php Source File", "datetime" => "Sat Dec 2 19:22:24 2006", "date" => "2 Dec 2006", "doxygenversion" => "1.4.6", "projectname" => "TYPO3 4.0.1", "projectnumber" => "4.0.1" ); get_header($doxygen_vars); ?>

adodb-xmlschema03.inc.php

00001 <?php
00002 // Copyright (c) 2004-2005 ars Cognita Inc., all rights reserved
00003 /* ******************************************************************************
00004     Released under both BSD license and Lesser GPL library license. 
00005         Whenever there is any discrepancy between the two licenses, 
00006         the BSD license will take precedence. 
00007 *******************************************************************************/
00021 function _file_get_contents($file) 
00022 {
00023         if (function_exists('file_get_contents')) return file_get_contents($file);
00024         
00025         $f = fopen($file,'r');
00026         if (!$f) return '';
00027         $t = '';
00028         
00029         while ($s = fread($f,100000)) $t .= $s;
00030         fclose($f);
00031         return $t;
00032 }
00033 
00034 
00038 if( !defined( 'XMLS_DEBUG' ) ) {
00039         define( 'XMLS_DEBUG', FALSE );
00040 }
00041 
00045 if( !defined( 'XMLS_PREFIX' ) ) {
00046         define( 'XMLS_PREFIX', '%%P' );
00047 }
00048 
00052 if( !defined( 'XMLS_PREFIX_MAXLEN' ) ) {
00053         define( 'XMLS_PREFIX_MAXLEN', 10 );
00054 }
00055 
00059 if( !defined( 'XMLS_EXECUTE_INLINE' ) ) {
00060         define( 'XMLS_EXECUTE_INLINE', FALSE );
00061 }
00062 
00066 if( !defined( 'XMLS_CONTINUE_ON_ERROR' ) ) {
00067         define( 'XMLS_CONTINUE_ON_ERROR', FALSE );
00068 }
00069 
00073 if( !defined( 'XMLS_SCHEMA_VERSION' ) ) {
00074         define( 'XMLS_SCHEMA_VERSION', '0.3' );
00075 }
00076 
00080 if( !defined( 'XMLS_DEFAULT_SCHEMA_VERSION' ) ) {
00081         define( 'XMLS_DEFAULT_SCHEMA_VERSION', '0.1' );
00082 }
00083 
00089 if( !defined( 'XMLS_MODE_INSERT' ) ) {
00090         define( 'XMLS_MODE_INSERT', 0 );
00091 }
00092 if( !defined( 'XMLS_MODE_UPDATE' ) ) {
00093         define( 'XMLS_MODE_UPDATE', 1 );
00094 }
00095 if( !defined( 'XMLS_MODE_IGNORE' ) ) {
00096         define( 'XMLS_MODE_IGNORE', 2 );
00097 }
00098 if( !defined( 'XMLS_EXISTING_DATA' ) ) {
00099         define( 'XMLS_EXISTING_DATA', XMLS_MODE_INSERT );
00100 }
00101 
00105 if( !defined( 'XMLS_DEFAULT_UPGRADE_METHOD' ) ) {
00106         define( 'XMLS_DEFAULT_UPGRADE_METHOD', 'ALTER' );
00107 }
00108 
00112 if( !defined( '_ADODB_LAYER' ) ) {
00113         require( 'adodb.inc.php' );
00114         require( 'adodb-datadict.inc.php' );
00115 }
00116 
00124 class dbObject {
00125         
00129         var $parent;
00130         
00134         var $currentElement;
00135         
00139         function dbObject( &$parent, $attributes = NULL ) {
00140                 $this->parent =& $parent;
00141         }
00142         
00148         function _tag_open( &$parser, $tag, $attributes ) {
00149                 
00150         }
00151         
00157         function _tag_cdata( &$parser, $cdata ) {
00158                 
00159         }
00160         
00166         function _tag_close( &$parser, $tag ) {
00167                 
00168         }
00169         
00170         function create() {
00171                 return array();
00172         }
00173         
00177         function destroy() {
00178                 unset( $this );
00179         }
00180         
00188         function supportedPlatform( $platform = NULL ) {
00189                 return is_object( $this->parent ) ? $this->parent->supportedPlatform( $platform ) : TRUE;
00190         }
00191         
00198         function prefix( $name = '' ) {
00199                 return is_object( $this->parent ) ? $this->parent->prefix( $name ) : $name;
00200         }
00201         
00208         function FieldID( $field ) {
00209                 return strtoupper( preg_replace( '/^`(.+)`$/', '$1', $field ) );
00210         }
00211 }
00212 
00224 class dbTable extends dbObject {
00225         
00229         var $name;
00230         
00234         var $fields = array();
00235         
00239         var $indexes = array();
00240         
00244         var $opts = array();
00245         
00249         var $current_field;
00250         
00255         var $drop_table;
00256         
00261         var $drop_field = array();
00262         
00267         var $currentPlatform = true;
00268         
00269         
00276         function dbTable( &$parent, $attributes = NULL ) {
00277                 $this->parent =& $parent;
00278                 $this->name = $this->prefix($attributes['NAME']);
00279         }
00280         
00287         function _tag_open( &$parser, $tag, $attributes ) {
00288                 $this->currentElement = strtoupper( $tag );
00289                 
00290                 switch( $this->currentElement ) {
00291                         case 'INDEX':
00292                                 if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
00293                                         xml_set_object( $parser, $this->addIndex( $attributes ) );
00294                                 }
00295                                 break;
00296                         case 'DATA':
00297                                 if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
00298                                         xml_set_object( $parser, $this->addData( $attributes ) );
00299                                 }
00300                                 break;
00301                         case 'DROP':
00302                                 $this->drop();
00303                                 break;
00304                         case 'FIELD':
00305                                 // Add a field
00306                                 $fieldName = $attributes['NAME'];
00307                                 $fieldType = $attributes['TYPE'];
00308                                 $fieldSize = isset( $attributes['SIZE'] ) ? $attributes['SIZE'] : NULL;
00309                                 $fieldOpts = !empty( $attributes['OPTS'] ) ? $attributes['OPTS'] : NULL;
00310                                 
00311                                 $this->addField( $fieldName, $fieldType, $fieldSize, $fieldOpts );
00312                                 break;
00313                         case 'KEY':
00314                         case 'NOTNULL':
00315                         case 'AUTOINCREMENT':
00316                         case 'DEFDATE':
00317                         case 'DEFTIMESTAMP':
00318                         case 'UNSIGNED':
00319                                 // Add a field option
00320                                 $this->addFieldOpt( $this->current_field, $this->currentElement );
00321                                 break;
00322                         case 'DEFAULT':
00323                                 // Add a field option to the table object
00324                                 
00325                                 // Work around ADOdb datadict issue that misinterprets empty strings.
00326                                 if( $attributes['VALUE'] == '' ) {
00327                                         $attributes['VALUE'] = " '' ";
00328                                 }
00329                                 
00330                                 $this->addFieldOpt( $this->current_field, $this->currentElement, $attributes['VALUE'] );
00331                                 break;
00332                         case 'OPT':
00333                         case 'CONSTRAINT':
00334                                 // Accept platform-specific options
00335                                 $this->currentPlatform = ( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) );
00336                                 break;
00337                         default:
00338                                 // print_r( array( $tag, $attributes ) );
00339                 }
00340         }
00341         
00347         function _tag_cdata( &$parser, $cdata ) {
00348                 switch( $this->currentElement ) {
00349                         // Table/field constraint
00350                         case 'CONSTRAINT':
00351                                 if( isset( $this->current_field ) ) {
00352                                         $this->addFieldOpt( $this->current_field, $this->currentElement, $cdata );
00353                                 } else {
00354                                         $this->addTableOpt( $cdata );
00355                                 }
00356                                 break;
00357                         // Table/field option
00358                         case 'OPT':
00359                                 if( isset( $this->current_field ) ) {
00360                                         $this->addFieldOpt( $this->current_field, $cdata );
00361                                 } else {
00362                                 $this->addTableOpt( $cdata );
00363                                 }
00364                                 break;
00365                         default:
00366                                 
00367                 }
00368         }
00369         
00375         function _tag_close( &$parser, $tag ) {
00376                 $this->currentElement = '';
00377                 
00378                 switch( strtoupper( $tag ) ) {
00379                         case 'TABLE':
00380                                 $this->parent->addSQL( $this->create( $this->parent ) );
00381                                 xml_set_object( $parser, $this->parent );
00382                                 $this->destroy();
00383                                 break;
00384                         case 'FIELD':
00385                                 unset($this->current_field);
00386                                 break;
00387                         case 'OPT':
00388                         case 'CONSTRAINT':
00389                                 $this->currentPlatform = true;
00390                                 break;
00391                         default:
00392 
00393                 }
00394         }
00395         
00402         function &addIndex( $attributes ) {
00403                 $name = strtoupper( $attributes['NAME'] );
00404                 $this->indexes[$name] =& new dbIndex( $this, $attributes );
00405                 return $this->indexes[$name];
00406         }
00407         
00414         function &addData( $attributes ) {
00415                 if( !isset( $this->data ) ) {
00416                         $this->data =& new dbData( $this, $attributes );
00417                 }
00418                 return $this->data;
00419         }
00420         
00450         function addField( $name, $type, $size = NULL, $opts = NULL ) {
00451                 $field_id = $this->FieldID( $name );
00452                 
00453                 // Set the field index so we know where we are
00454                 $this->current_field = $field_id;
00455                 
00456                 // Set the field name (required)
00457                 $this->fields[$field_id]['NAME'] = $name;
00458                 
00459                 // Set the field type (required)
00460                 $this->fields[$field_id]['TYPE'] = $type;
00461                 
00462                 // Set the field size (optional)
00463                 if( isset( $size ) ) {
00464                         $this->fields[$field_id]['SIZE'] = $size;
00465                 }
00466                 
00467                 // Set the field options
00468                 if( isset( $opts ) ) {
00469                         $this->fields[$field_id]['OPTS'] = array($opts);
00470                 } else {
00471                         $this->fields[$field_id]['OPTS'] = array();
00472                 }
00473         }
00474         
00486         function addFieldOpt( $field, $opt, $value = NULL ) {
00487                 if( $this->currentPlatform ) {
00488                 if( !isset( $value ) ) {
00489                         $this->fields[$this->FieldID( $field )]['OPTS'][] = $opt;
00490                 // Add the option and value
00491                 } else {
00492                         $this->fields[$this->FieldID( $field )]['OPTS'][] = array( $opt => $value );
00493                 }
00494         }
00495         }
00496         
00506         function addTableOpt( $opt ) {
00507                 if( $this->currentPlatform ) {
00508                 $this->opts[] = $opt;
00509                 }
00510                 return $this->opts;
00511         }
00512         
00519         function create( &$xmls ) {
00520                 $sql = array();
00521                 
00522                 // drop any existing indexes
00523                 if( is_array( $legacy_indexes = $xmls->dict->MetaIndexes( $this->name ) ) ) {
00524                         foreach( $legacy_indexes as $index => $index_details ) {
00525                                 $sql[] = $xmls->dict->DropIndexSQL( $index, $this->name );
00526                         }
00527                 }
00528                 
00529                 // remove fields to be dropped from table object
00530                 foreach( $this->drop_field as $field ) {
00531                         unset( $this->fields[$field] );
00532                 }
00533                 
00534                 // if table exists
00535                 if( is_array( $legacy_fields = $xmls->dict->MetaColumns( $this->name ) ) ) {
00536                         // drop table
00537                         if( $this->drop_table ) {
00538                                 $sql[] = $xmls->dict->DropTableSQL( $this->name );
00539                                 
00540                                 return $sql;
00541                         }
00542                         
00543                         // drop any existing fields not in schema
00544                         foreach( $legacy_fields as $field_id => $field ) {
00545                                 if( !isset( $this->fields[$field_id] ) ) {
00546                                         $sql[] = $xmls->dict->DropColumnSQL( $this->name, $field->name );
00547                                 }
00548                         }
00549                 // if table doesn't exist
00550                 } else {
00551                         if( $this->drop_table ) {
00552                                 return $sql;
00553                         }
00554                         
00555                         $legacy_fields = array();
00556                 }
00557                 
00558                 // Loop through the field specifier array, building the associative array for the field options
00559                 $fldarray = array();
00560                 
00561                 foreach( $this->fields as $field_id => $finfo ) {
00562                         // Set an empty size if it isn't supplied
00563                         if( !isset( $finfo['SIZE'] ) ) {
00564                                 $finfo['SIZE'] = '';
00565                         }
00566                         
00567                         // Initialize the field array with the type and size
00568                         $fldarray[$field_id] = array(
00569                                 'NAME' => $finfo['NAME'],
00570                                 'TYPE' => $finfo['TYPE'],
00571                                 'SIZE' => $finfo['SIZE']
00572                         );
00573                         
00574                         // Loop through the options array and add the field options. 
00575                         if( isset( $finfo['OPTS'] ) ) {
00576                                 foreach( $finfo['OPTS'] as $opt ) {
00577                                         // Option has an argument.
00578                                         if( is_array( $opt ) ) {
00579                                                 $key = key( $opt );
00580                                                 $value = $opt[key( $opt )];
00581                                                 @$fldarray[$field_id][$key] .= $value;
00582                                         // Option doesn't have arguments
00583                                         } else {
00584                                                 $fldarray[$field_id][$opt] = $opt;
00585                                         }
00586                                 }
00587                         }
00588                 }
00589                 
00590                 if( empty( $legacy_fields ) ) {
00591                         // Create the new table
00592                         $sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts );
00593                         logMsg( end( $sql ), 'Generated CreateTableSQL' );
00594                 } else {
00595                         // Upgrade an existing table
00596                         logMsg( "Upgrading {$this->name} using '{$xmls->upgrade}'" );
00597                         switch( $xmls->upgrade ) {
00598                                 // Use ChangeTableSQL
00599                                 case 'ALTER':
00600                                         logMsg( 'Generated ChangeTableSQL (ALTERing table)' );
00601                                         $sql[] = $xmls->dict->ChangeTableSQL( $this->name, $fldarray, $this->opts );
00602                                         break;
00603                                 case 'REPLACE':
00604                                         logMsg( 'Doing upgrade REPLACE (testing)' );
00605                                         $sql[] = $xmls->dict->DropTableSQL( $this->name );
00606                                         $sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts );
00607                                         break;
00608                                 // ignore table
00609                                 default:
00610                                         return array();
00611                         }
00612                 }
00613                 
00614                 foreach( $this->indexes as $index ) {
00615                         $sql[] = $index->create( $xmls );
00616                 }
00617                 
00618                 if( isset( $this->data ) ) {
00619                         $sql[] = $this->data->create( $xmls );
00620                 }
00621                 
00622                 return $sql;
00623         }
00624         
00628         function drop() {
00629                 if( isset( $this->current_field ) ) {
00630                         // Drop the current field
00631                         logMsg( "Dropping field '{$this->current_field}' from table '{$this->name}'" );
00632                         // $this->drop_field[$this->current_field] = $xmls->dict->DropColumnSQL( $this->name, $this->current_field );
00633                         $this->drop_field[$this->current_field] = $this->current_field;
00634                 } else {
00635                         // Drop the current table
00636                         logMsg( "Dropping table '{$this->name}'" );
00637                         // $this->drop_table = $xmls->dict->DropTableSQL( $this->name );
00638                         $this->drop_table = TRUE;
00639                 }
00640         }
00641 }
00642 
00654 class dbIndex extends dbObject {
00655         
00659         var $name;
00660         
00664         var $opts = array();
00665         
00669         var $columns = array();
00670         
00675         var $drop = FALSE;
00676         
00685         function dbIndex( &$parent, $attributes = NULL ) {
00686                 $this->parent =& $parent;
00687                 
00688                 $this->name = $this->prefix ($attributes['NAME']);
00689         }
00690         
00699         function _tag_open( &$parser, $tag, $attributes ) {
00700                 $this->currentElement = strtoupper( $tag );
00701                 
00702                 switch( $this->currentElement ) {
00703                         case 'DROP':
00704                                 $this->drop();
00705                                 break;
00706                         case 'CLUSTERED':
00707                         case 'BITMAP':
00708                         case 'UNIQUE':
00709                         case 'FULLTEXT':
00710                         case 'HASH':
00711                                 // Add index Option
00712                                 $this->addIndexOpt( $this->currentElement );
00713                                 break;
00714                         default:
00715                                 // print_r( array( $tag, $attributes ) );
00716                 }
00717         }
00718         
00726         function _tag_cdata( &$parser, $cdata ) {
00727                 switch( $this->currentElement ) {
00728                         // Index field name
00729                         case 'COL':
00730                                 $this->addField( $cdata );
00731                                 break;
00732                         default:
00733                                 
00734                 }
00735         }
00736         
00742         function _tag_close( &$parser, $tag ) {
00743                 $this->currentElement = '';
00744                 
00745                 switch( strtoupper( $tag ) ) {
00746                         case 'INDEX':
00747                                 xml_set_object( $parser, $this->parent );
00748                                 break;
00749                 }
00750         }
00751         
00758         function addField( $name ) {
00759                 $this->columns[$this->FieldID( $name )] = $name;
00760                 
00761                 // Return the field list
00762                 return $this->columns;
00763         }
00764         
00771         function addIndexOpt( $opt ) {
00772                 $this->opts[] = $opt;
00773                 
00774                 // Return the options list
00775                 return $this->opts;
00776         }
00777         
00784         function create( &$xmls ) {
00785                 if( $this->drop ) {
00786                         return NULL;
00787                 }
00788                 
00789                 // eliminate any columns that aren't in the table
00790                 foreach( $this->columns as $id => $col ) {
00791                         if( !isset( $this->parent->fields[$id] ) ) {
00792                                 unset( $this->columns[$id] );
00793                         }
00794                 }
00795                 
00796                 return $xmls->dict->CreateIndexSQL( $this->name, $this->parent->name, $this->columns, $this->opts );
00797         }
00798         
00802         function drop() {
00803                 $this->drop = TRUE;
00804         }
00805 }
00806 
00816 class dbData extends dbObject {
00817         
00818         var $data = array();
00819         
00820         var $row;
00821         
00830         function dbData( &$parent, $attributes = NULL ) {
00831                 $this->parent =& $parent;
00832         }
00833         
00842         function _tag_open( &$parser, $tag, $attributes ) {
00843                 $this->currentElement = strtoupper( $tag );
00844                 
00845                 switch( $this->currentElement ) {
00846                         case 'ROW':
00847                                 $this->row = count( $this->data );
00848                                 $this->data[$this->row] = array();
00849                                 break;
00850                         case 'F':
00851                                 $this->addField($attributes);
00852                         default:
00853                                 // print_r( array( $tag, $attributes ) );
00854                 }
00855         }
00856         
00864         function _tag_cdata( &$parser, $cdata ) {
00865                 switch( $this->currentElement ) {
00866                         // Index field name
00867                         case 'F':
00868                                 $this->addData( $cdata );
00869                                 break;
00870                         default:
00871                                 
00872                 }
00873         }
00874         
00880         function _tag_close( &$parser, $tag ) {
00881                 $this->currentElement = '';
00882                 
00883                 switch( strtoupper( $tag ) ) {
00884                         case 'DATA':
00885                                 xml_set_object( $parser, $this->parent );
00886                                 break;
00887                 }
00888         }
00889         
00896         function addField( $attributes ) {
00897                 // check we're in a valid row
00898                 if( !isset( $this->row ) || !isset( $this->data[$this->row] ) ) {
00899                         return;
00900                 }
00901                 
00902                 // Set the field index so we know where we are
00903                 if( isset( $attributes['NAME'] ) ) {
00904                         $this->current_field = $this->FieldID( $attributes['NAME'] );
00905                 } else {
00906                         $this->current_field = count( $this->data[$this->row] );
00907                 }
00908                 
00909                 // initialise data
00910                 if( !isset( $this->data[$this->row][$this->current_field] ) ) {
00911                         $this->data[$this->row][$this->current_field] = '';
00912                 }
00913         }
00914         
00921         function addData( $cdata ) {
00922                 // check we're in a valid field
00923                 if ( isset( $this->data[$this->row][$this->current_field] ) ) {
00924                         // add data to field
00925                         $this->data[$this->row][$this->current_field] .= $cdata;
00926                 }
00927         }
00928         
00935         function create( &$xmls ) {
00936                 $table = $xmls->dict->TableName($this->parent->name);
00937                 $table_field_count = count($this->parent->fields);
00938                 $tables = $xmls->db->MetaTables(); 
00939                 $sql = array();
00940                 
00941                 $ukeys = $xmls->db->MetaPrimaryKeys( $table );
00942                 if( !empty( $this->parent->indexes ) and !empty( $ukeys ) ) {
00943                         foreach( $this->parent->indexes as $indexObj ) {
00944                                 if( !in_array( $indexObj->name, $ukeys ) ) $ukeys[] = $indexObj->name;
00945                         }
00946                 }
00947                 
00948                 // eliminate any columns that aren't in the table
00949                 foreach( $this->data as $row ) {
00950                         $table_fields = $this->parent->fields;
00951                         $fields = array();
00952                         $rawfields = array(); // Need to keep some of the unprocessed data on hand.
00953                         
00954                         foreach( $row as $field_id => $field_data ) {
00955                                 if( !array_key_exists( $field_id, $table_fields ) ) {
00956                                         if( is_numeric( $field_id ) ) {
00957                                                 $field_id = reset( array_keys( $table_fields ) );
00958                                         } else {
00959                                                 continue;
00960                                         }
00961                                 }
00962                                 
00963                                 $name = $table_fields[$field_id]['NAME'];
00964                                 
00965                                 switch( $table_fields[$field_id]['TYPE'] ) {
00966                                         case 'I':
00967                                         case 'I1':
00968                                         case 'I2':
00969                                         case 'I4':
00970                                         case 'I8':
00971                                                 $fields[$name] = intval($field_data);
00972                                                 break;
00973                                         case 'C':
00974                                         case 'C2':
00975                                         case 'X':
00976                                         case 'X2':
00977                                         default:
00978                                                 $fields[$name] = $xmls->db->qstr( $field_data );
00979                                                 $rawfields[$name] = $field_data;
00980                                 }
00981                                 
00982                                 unset($table_fields[$field_id]);
00983                                 
00984                         }
00985                         
00986                         // check that at least 1 column is specified
00987                         if( empty( $fields ) ) {
00988                                 continue;
00989                         }
00990                         
00991                         // check that no required columns are missing
00992                         if( count( $fields ) < $table_field_count ) {
00993                                 foreach( $table_fields as $field ) {
00994                                         if( isset( $field['OPTS'] ) and ( in_array( 'NOTNULL', $field['OPTS'] ) || in_array( 'KEY', $field['OPTS'] ) ) && !in_array( 'AUTOINCREMENT', $field['OPTS'] ) ) {
00995                                                         continue(2);
00996                                                 }
00997                                 }
00998                         }
00999                         
01000                         // The rest of this method deals with updating existing data records.
01001                         
01002                         if( !in_array( $table, $tables ) or ( $mode = $xmls->existingData() ) == XMLS_MODE_INSERT ) {
01003                                 // Table doesn't yet exist, so it's safe to insert.
01004                                 logMsg( "$table doesn't exist, inserting or mode is INSERT" );
01005                         $sql[] = 'INSERT INTO '. $table .' ('. implode( ',', array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')';
01006                                 continue;
01007                 }
01008                 
01009                         // Prepare to test for potential violations. Get primary keys and unique indexes
01010                         $mfields = array_merge( $fields, $rawfields );
01011                         $keyFields = array_intersect( $ukeys, array_keys( $mfields ) );
01012                         
01013                         if( empty( $ukeys ) or count( $keyFields ) == 0 ) {
01014                                 // No unique keys in schema, so safe to insert
01015                                 logMsg( "Either schema or data has no unique keys, so safe to insert" );
01016                                 $sql[] = 'INSERT INTO '. $table .' ('. implode( ',', array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')';
01017                                 continue;
01018                         }
01019                         
01020                         // Select record containing matching unique keys.
01021                         $where = '';
01022                         foreach( $ukeys as $key ) {
01023                                 if( isset( $mfields[$key] ) and $mfields[$key] ) {
01024                                         if( $where ) $where .= ' AND ';
01025                                         $where .= $key . ' = ' . $xmls->db->qstr( $mfields[$key] );
01026                                 }
01027                         }
01028                         $records = $xmls->db->Execute( 'SELECT * FROM ' . $table . ' WHERE ' . $where );
01029                         switch( $records->RecordCount() ) {
01030                                 case 0:
01031                                         // No matching record, so safe to insert.
01032                                         logMsg( "No matching records. Inserting new row with unique data" );
01033                                         $sql[] = $xmls->db->GetInsertSQL( $records, $mfields );
01034                                         break;
01035                                 case 1:
01036                                         // Exactly one matching record, so we can update if the mode permits.
01037                                         logMsg( "One matching record..." );
01038                                         if( $mode == XMLS_MODE_UPDATE ) {
01039                                                 logMsg( "...Updating existing row from unique data" );
01040                                                 $sql[] = $xmls->db->GetUpdateSQL( $records, $mfields );
01041                                         }
01042                                         break;
01043                                 default:
01044                                         // More than one matching record; the result is ambiguous, so we must ignore the row.
01045                                         logMsg( "More than one matching record. Ignoring row." );
01046                         }
01047                 }
01048                 return $sql;
01049         }
01050 }
01051 
01058 class dbQuerySet extends dbObject {
01059         
01063         var $queries = array();
01064         
01068         var $query;
01069         
01073         var $prefixKey = '';
01074         
01078         var $prefixMethod = 'AUTO';
01079         
01086         function dbQuerySet( &$parent, $attributes = NULL ) {
01087                 $this->parent =& $parent;
01088                         
01089                 // Overrides the manual prefix key
01090                 if( isset( $attributes['KEY'] ) ) {
01091                         $this->prefixKey = $attributes['KEY'];
01092                 }
01093                 
01094                 $prefixMethod = isset( $attributes['PREFIXMETHOD'] ) ? strtoupper( trim( $attributes['PREFIXMETHOD'] ) ) : '';
01095                 
01096                 // Enables or disables automatic prefix prepending
01097                 switch( $prefixMethod ) {
01098                         case 'AUTO':
01099                                 $this->prefixMethod = 'AUTO';
01100                                 break;
01101                         case 'MANUAL':
01102                                 $this->prefixMethod = 'MANUAL';
01103                                 break;
01104                         case 'NONE':
01105                                 $this->prefixMethod = 'NONE';
01106                                 break;
01107                 }
01108         }
01109         
01116         function _tag_open( &$parser, $tag, $attributes ) {
01117                 $this->currentElement = strtoupper( $tag );
01118                 
01119                 switch( $this->currentElement ) {
01120                         case 'QUERY':
01121                                 // Create a new query in a SQL queryset.
01122                                 // Ignore this query set if a platform is specified and it's different than the 
01123                                 // current connection platform.
01124                                 if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
01125                                         $this->newQuery();
01126                                 } else {
01127                                         $this->discardQuery();
01128                                 }
01129                                 break;
01130                         default:
01131                                 // print_r( array( $tag, $attributes ) );
01132                 }
01133         }
01134         
01138         function _tag_cdata( &$parser, $cdata ) {
01139                 switch( $this->currentElement ) {
01140                         // Line of queryset SQL data
01141                         case 'QUERY':
01142                                 $this->buildQuery( $cdata );
01143                                 break;
01144                         default:
01145                                 
01146                 }
01147         }
01148         
01154         function _tag_close( &$parser, $tag ) {
01155                 $this->currentElement = '';
01156                 
01157                 switch( strtoupper( $tag ) ) {
01158                         case 'QUERY':
01159                                 // Add the finished query to the open query set.
01160                                 $this->addQuery();
01161                                 break;
01162                         case 'SQL':
01163                                 $this->parent->addSQL( $this->create( $this->parent ) );
01164                                 xml_set_object( $parser, $this->parent );
01165                                 $this->destroy();
01166                                 break;
01167                         default:
01168                                 
01169                 }
01170         }
01171         
01177         function newQuery() {
01178                 $this->query = '';
01179                 
01180                 return TRUE;
01181         }
01182         
01188         function discardQuery() {
01189                 unset( $this->query );
01190                 
01191                 return TRUE;
01192         }
01193         
01200         function buildQuery( $sql = NULL ) {
01201                 if( !isset( $this->query ) OR empty( $sql ) ) {
01202                         return FALSE;
01203                 }
01204                 
01205                 $this->query .= $sql;
01206                 
01207                 return $this->query;
01208         }
01209         
01215         function addQuery() {
01216                 if( !isset( $this->query ) ) {
01217                         return FALSE;
01218                 }
01219                 
01220                 $this->queries[] = $return = trim($this->query);
01221                 
01222                 unset( $this->query );
01223                 
01224                 return $return;
01225         }
01226         
01233         function create( &$xmls ) {
01234                 foreach( $this->queries as $id => $query ) {
01235                         switch( $this->prefixMethod ) {
01236                                 case 'AUTO':
01237                                         // Enable auto prefix replacement
01238                                         
01239                                         // Process object prefix.
01240                                         // Evaluate SQL statements to prepend prefix to objects
01241                                         $query = $this->prefixQuery( '/^\s*((?is)INSERT\s+(INTO\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
01242                                         $query = $this->prefixQuery( '/^\s*((?is)UPDATE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
01243                                         $query = $this->prefixQuery( '/^\s*((?is)DELETE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
01244                                         
01245                                         // SELECT statements aren't working yet
01246                                         #$data = preg_replace( '/(?ias)(^\s*SELECT\s+.*\s+FROM)\s+(\W\s*,?\s*)+((?i)\s+WHERE.*$)/', "\1 $prefix\2 \3", $data );
01247                                         
01248                                 case 'MANUAL':
01249                                         // If prefixKey is set and has a value then we use it to override the default constant XMLS_PREFIX.
01250                                         // If prefixKey is not set, we use the default constant XMLS_PREFIX
01251                                         if( isset( $this->prefixKey ) AND( $this->prefixKey !== '' ) ) {
01252                                                 // Enable prefix override
01253                                                 $query = str_replace( $this->prefixKey, $xmls->objectPrefix, $query );
01254                                         } else {
01255                                                 // Use default replacement
01256                                                 $query = str_replace( XMLS_PREFIX , $xmls->objectPrefix, $query );
01257                                         }
01258                         }
01259                         
01260                         $this->queries[$id] = trim( $query );
01261                 }
01262                 
01263                 // Return the query set array
01264                 return $this->queries;
01265         }
01266         
01275         function prefixQuery( $regex, $query, $prefix = NULL ) {
01276                 if( !isset( $prefix ) ) {
01277                         return $query;
01278                 }
01279                 
01280                 if( preg_match( $regex, $query, $match ) ) {
01281                         $preamble = $match[1];
01282                         $postamble = $match[5];
01283                         $objectList = explode( ',', $match[3] );
01284                         // $prefix = $prefix . '_';
01285                         
01286                         $prefixedList = '';
01287                         
01288                         foreach( $objectList as $object ) {
01289                                 if( $prefixedList !== '' ) {
01290                                         $prefixedList .= ', ';
01291                                 }
01292                                 
01293                                 $prefixedList .= $prefix . trim( $object );
01294                         }
01295                         
01296                         $query = $preamble . ' ' . $prefixedList . ' ' . $postamble;
01297                 }
01298                 
01299                 return $query;
01300         }
01301 }
01302 
01316 class adoSchema {
01317         
01322         var $sqlArray;
01323         
01328         var $db;
01329         
01334         var $dict;
01335         
01340         var $currentElement = '';
01341         
01346         var $upgrade = '';
01347         
01352         var $objectPrefix = '';
01353         
01358         var $mgq;
01359         
01364         var $debug;
01365         
01370         var $versionRegex = '/<schema.*?( version="([^"]*)")?.*?>/';
01371         
01376         var $schemaVersion;
01377         
01381         var $success;
01382         
01386         var $executeInline;
01387         
01391         var $continueOnError;
01392         
01396         var $existingData;
01397         
01407         function adoSchema( &$db ) {
01408                 // Initialize the environment
01409                 $this->mgq = get_magic_quotes_runtime();
01410                 set_magic_quotes_runtime(0);
01411                 
01412                 $this->db =& $db;
01413                 $this->debug = $this->db->debug;
01414                 $this->dict = NewDataDictionary( $this->db );
01415                 $this->sqlArray = array();
01416                 $this->schemaVersion = XMLS_SCHEMA_VERSION;
01417                 $this->executeInline( XMLS_EXECUTE_INLINE );
01418                 $this->continueOnError( XMLS_CONTINUE_ON_ERROR );
01419                 $this->existingData( XMLS_EXISTING_DATA );
01420                 $this->setUpgradeMethod();
01421         }
01422         
01439         function SetUpgradeMethod( $method = '' ) {
01440                 if( !is_string( $method ) ) {
01441                         return FALSE;
01442                 }
01443                 
01444                 $method = strtoupper( $method );
01445                 
01446                 // Handle the upgrade methods
01447                 switch( $method ) {
01448                         case 'ALTER':
01449                                 $this->upgrade = $method;
01450                                 break;
01451                         case 'REPLACE':
01452                                 $this->upgrade = $method;
01453                                 break;
01454                         case 'BEST':
01455                                 $this->upgrade = 'ALTER';
01456                                 break;
01457                         case 'NONE':
01458                                 $this->upgrade = 'NONE';
01459                                 break;
01460                         default:
01461                                 // Use default if no legitimate method is passed.
01462                                 $this->upgrade = XMLS_DEFAULT_UPGRADE_METHOD;
01463                 }
01464                 
01465                 return $this->upgrade;
01466         }
01467         
01487         function ExistingData( $mode = NULL ) {
01488                 if( is_int( $mode ) ) {
01489                         switch( $mode ) {
01490                                 case XMLS_MODE_UPDATE:
01491                                         $mode = XMLS_MODE_UPDATE;
01492                                         break;
01493                                 case XMLS_MODE_IGNORE:
01494                                         $mode = XMLS_MODE_IGNORE;
01495                                         break;
01496                                 case XMLS_MODE_INSERT:
01497                                         $mode = XMLS_MODE_INSERT;
01498                                         break;
01499                                 default:
01500                                         $mode = XMLS_EXISITNG_DATA;
01501                                         break;
01502                         }
01503                         $this->existingData = $mode;
01504                 }
01505                 
01506                 return $this->existingData;
01507         }
01508         
01522         function ExecuteInline( $mode = NULL ) {
01523                 if( is_bool( $mode ) ) {
01524                         $this->executeInline = $mode;
01525                 }
01526                 
01527                 return $this->executeInline;
01528         }
01529         
01543         function ContinueOnError( $mode = NULL ) {
01544                 if( is_bool( $mode ) ) {
01545                         $this->continueOnError = $mode;
01546                 }
01547                 
01548                 return $this->continueOnError;
01549         }
01550         
01564         function ParseSchema( $filename, $returnSchema = FALSE ) {
01565                 return $this->ParseSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema );
01566         }
01567         
01589         function ParseSchemaFile( $filename, $returnSchema = FALSE ) {
01590                 // Open the file
01591                 if( !($fp = fopen( $filename, 'r' )) ) {
01592                         logMsg( 'Unable to open file' );
01593                         return FALSE;
01594                 }
01595                 
01596                 // do version detection here
01597                 if( $this->SchemaFileVersion( $filename ) != $this->schemaVersion ) {
01598                         logMsg( 'Invalid Schema Version' );
01599                         return FALSE;
01600                 }
01601                 
01602                 if( $returnSchema ) {
01603                         $xmlstring = '';
01604                         while( $data = fread( $fp, 4096 ) ) {
01605                                 $xmlstring .= $data . "\n";
01606                         }
01607                         return $xmlstring;
01608                 }
01609                 
01610                 $this->success = 2;
01611                 
01612                 $xmlParser = $this->create_parser();
01613                 
01614                 // Process the file
01615                 while( $data = fread( $fp, 4096 ) ) {
01616                         if( !xml_parse( $xmlParser, $data, feof( $fp ) ) ) {
01617                                 die( sprintf(
01618                                         "XML error: %s at line %d",
01619                                         xml_error_string( xml_get_error_code( $xmlParser) ),
01620                                         xml_get_current_line_number( $xmlParser)
01621                                 ) );
01622                         }
01623                 }
01624                 
01625                 xml_parser_free( $xmlParser );
01626                 
01627                 return $this->sqlArray;
01628         }
01629         
01641         function ParseSchemaString( $xmlstring, $returnSchema = FALSE ) {
01642                 if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
01643                         logMsg( 'Empty or Invalid Schema' );
01644                         return FALSE;
01645                 }
01646                 
01647                 // do version detection here
01648                 if( $this->SchemaStringVersion( $xmlstring ) != $this->schemaVersion ) {
01649                         logMsg( 'Invalid Schema Version' );
01650                         return FALSE;
01651                 }
01652                 
01653                 if( $returnSchema ) {
01654                         return $xmlstring;
01655                 }
01656                 
01657                 $this->success = 2;
01658                 
01659                 $xmlParser = $this->create_parser();
01660                 
01661                 if( !xml_parse( $xmlParser, $xmlstring, TRUE ) ) {
01662                         die( sprintf(
01663                                 "XML error: %s at line %d",
01664                                 xml_error_string( xml_get_error_code( $xmlParser) ),
01665                                 xml_get_current_line_number( $xmlParser)
01666                         ) );
01667                 }
01668                 
01669                 xml_parser_free( $xmlParser );
01670                 
01671                 return $this->sqlArray;
01672         }
01673         
01685         function RemoveSchema( $filename, $returnSchema = FALSE ) {
01686                 return $this->RemoveSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema );
01687         }
01688         
01700         function RemoveSchemaString( $schema, $returnSchema = FALSE ) {
01701                 
01702                 // grab current version
01703                 if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
01704                         return FALSE;
01705                 }
01706                 
01707                 return $this->ParseSchemaString( $this->TransformSchema( $schema, 'remove-' . $version), $returnSchema );
01708         }
01709         
01723         function ExecuteSchema( $sqlArray = NULL, $continueOnErr =  NULL ) {
01724                 if( !is_bool( $continueOnErr ) ) {
01725                         $continueOnErr = $this->ContinueOnError();
01726                 }
01727                 
01728                 if( !isset( $sqlArray ) ) {
01729                         $sqlArray = $this->sqlArray;
01730                 }
01731                 
01732                 if( !is_array( $sqlArray ) ) {
01733                         $this->success = 0;
01734                 } else {
01735                         $this->success = $this->dict->ExecuteSQLArray( $sqlArray, $continueOnErr );
01736                 }
01737                 
01738                 return $this->success;
01739         }
01740         
01750         function PrintSQL( $format = 'NONE' ) {
01751                 $sqlArray = null;
01752                 return $this->getSQL( $format, $sqlArray );
01753         }
01754         
01764         function SaveSQL( $filename = './schema.sql' ) {
01765                 
01766                 if( !isset( $sqlArray ) ) {
01767                         $sqlArray = $this->sqlArray;
01768                 }
01769                 if( !isset( $sqlArray ) ) {
01770                         return FALSE;
01771                 }
01772                 
01773                 $fp = fopen( $filename, "w" );
01774                 
01775                 foreach( $sqlArray as $key => $query ) {
01776                         fwrite( $fp, $query . ";\n" );
01777                 }
01778                 fclose( $fp );
01779         }
01780         
01788         function &create_parser() {
01789                 // Create the parser
01790                 $xmlParser = xml_parser_create();
01791                 xml_set_object( $xmlParser, $this );
01792                 
01793                 // Initialize the XML callback functions
01794                 xml_set_element_handler( $xmlParser, '_tag_open', '_tag_close' );
01795                 xml_set_character_data_handler( $xmlParser, '_tag_cdata' );
01796                 
01797                 return $xmlParser;
01798         }
01799         
01805         function _tag_open( &$parser, $tag, $attributes ) {
01806                 switch( strtoupper( $tag ) ) {
01807                         case 'TABLE':
01808                                 if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
01809                                 $this->obj = new dbTable( $this, $attributes );
01810                                 xml_set_object( $parser, $this->obj );
01811                                 }
01812                                 break;
01813                         case 'SQL':
01814                                 if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
01815                                         $this->obj = new dbQuerySet( $this, $attributes );
01816                                         xml_set_object( $parser, $this->obj );
01817                                 }
01818                                 break;
01819                         default:
01820                                 // print_r( array( $tag, $attributes ) );
01821                 }
01822                 
01823         }
01824         
01830         function _tag_cdata( &$parser, $cdata ) {
01831         }
01832         
01839         function _tag_close( &$parser, $tag ) {
01840                 
01841         }
01842         
01859         function ConvertSchemaString( $schema, $newVersion = NULL, $newFile = NULL ) {
01860                 
01861                 // grab current version
01862                 if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
01863                         return FALSE;
01864                 }
01865                 
01866                 if( !isset ($newVersion) ) {
01867                         $newVersion = $this->schemaVersion;
01868                 }
01869                 
01870                 if( $version == $newVersion ) {
01871                         $result = $schema;
01872                 } else {
01873                         $result = $this->TransformSchema( $schema, 'convert-' . $version . '-' . $newVersion);
01874                 }
01875                 
01876                 if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) {
01877                         fwrite( $fp, $result );
01878                         fclose( $fp );
01879                 }
01880                 
01881                 return $result;
01882         }
01883 
01884         /*
01885         // compat for pre-4.3 - jlim
01886         function _file_get_contents($path)
01887         {
01888                 if (function_exists('file_get_contents')) return file_get_contents($path);
01889                 return join('',file($path));
01890         }*/
01891         
01908         function ConvertSchemaFile( $filename, $newVersion = NULL, $newFile = NULL ) {
01909                 
01910                 // grab current version
01911                 if( !( $version = $this->SchemaFileVersion( $filename ) ) ) {
01912                         return FALSE;
01913                 }
01914                 
01915                 if( !isset ($newVersion) ) {
01916                         $newVersion = $this->schemaVersion;
01917                 }
01918                 
01919                 if( $version == $newVersion ) {
01920                         $result = _file_get_contents( $filename );
01921                         
01922                         // remove unicode BOM if present
01923                         if( substr( $result, 0, 3 ) == sprintf( '%c%c%c', 239, 187, 191 ) ) {
01924                                 $result = substr( $result, 3 );
01925                         }
01926                 } else {
01927                         $result = $this->TransformSchema( $filename, 'convert-' . $version . '-' . $newVersion, 'file' );
01928                 }
01929                 
01930                 if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) {
01931                         fwrite( $fp, $result );
01932                         fclose( $fp );
01933                 }
01934                 
01935                 return $result;
01936         }
01937         
01938         function TransformSchema( $schema, $xsl, $schematype='string' )
01939         {
01940                 // Fail if XSLT extension is not available
01941                 if( ! function_exists( 'xslt_create' ) ) {
01942                         return FALSE;
01943                 }
01944                 
01945                 $xsl_file = dirname( __FILE__ ) . '/xsl/' . $xsl . '.xsl';
01946                 
01947                 // look for xsl
01948                 if( !is_readable( $xsl_file ) ) {
01949                         return FALSE;
01950                 }
01951                 
01952                 switch( $schematype )
01953                 {
01954                         case 'file':
01955                                 if( !is_readable( $schema ) ) {
01956                                         return FALSE;
01957                                 }
01958                                 
01959                                 $schema = _file_get_contents( $schema );
01960                                 break;
01961                         case 'string':
01962                         default:
01963                                 if( !is_string( $schema ) ) {
01964                                         return FALSE;
01965                                 }
01966                 }
01967                 
01968                 $arguments = array (
01969                         '/_xml' => $schema,
01970                         '/_xsl' => _file_get_contents( $xsl_file )
01971                 );
01972                 
01973                 // create an XSLT processor
01974                 $xh = xslt_create ();
01975                 
01976                 // set error handler
01977                 xslt_set_error_handler ($xh, array (&$this, 'xslt_error_handler'));
01978                 
01979                 // process the schema
01980                 $result = xslt_process ($xh, 'arg:/_xml', 'arg:/_xsl', NULL, $arguments); 
01981                 
01982                 xslt_free ($xh);
01983                 
01984                 return $result;
01985         }
01986         
01997         function xslt_error_handler( $parser, $errno, $level, $fields ) {
01998                 if( is_array( $fields ) ) {
01999                         $msg = array(
02000                                 'Message Type' => ucfirst( $fields['msgtype'] ),
02001                                 'Message Code' => $fields['code'],
02002                                 'Message' => $fields['msg'],
02003                                 'Error Number' => $errno,
02004                                 'Level' => $level
02005                         );
02006                         
02007                         switch( $fields['URI'] ) {
02008                                 case 'arg:/_xml':
02009                                         $msg['Input'] = 'XML';
02010                                         break;
02011                                 case 'arg:/_xsl':
02012                                         $msg['Input'] = 'XSL';
02013                                         break;
02014                                 default:
02015                                         $msg['Input'] = $fields['URI'];
02016                         }
02017                         
02018                         $msg['Line'] = $fields['line'];
02019                 } else {
02020                         $msg = array(
02021                                 'Message Type' => 'Error',
02022                                 'Error Number' => $errno,
02023                                 'Level' => $level,
02024                                 'Fields' => var_export( $fields, TRUE )
02025                         );
02026                 }
02027                 
02028                 $error_details = $msg['Message Type'] . ' in XSLT Transformation' . "\n"
02029                                            . '<table>' . "\n";
02030                 
02031                 foreach( $msg as $label => $details ) {
02032                         $error_details .= '<tr><td><b>' . $label . ': </b></td><td>' . htmlentities( $details ) . '</td></tr>' . "\n";
02033                 }
02034                 
02035                 $error_details .= '</table>';
02036                 
02037                 trigger_error( $error_details, E_USER_ERROR );
02038         }
02039         
02049         function SchemaFileVersion( $filename ) {
02050                 // Open the file
02051                 if( !($fp = fopen( $filename, 'r' )) ) {
02052                         // die( 'Unable to open file' );
02053                         return FALSE;
02054                 }
02055                 
02056                 // Process the file
02057                 while( $data = fread( $fp, 4096 ) ) {
02058                         if( preg_match( $this->versionRegex, $data, $matches ) ) {
02059                                 return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION;
02060                         }
02061                 }
02062                 
02063                 return FALSE;
02064         }
02065         
02075         function SchemaStringVersion( $xmlstring ) {
02076                 if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
02077                         return FALSE;
02078                 }
02079                 
02080                 if( preg_match( $this->versionRegex, $xmlstring, $matches ) ) {
02081                         return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION;
02082                 }
02083                 
02084                 return FALSE;
02085         }
02086         
02097         function ExtractSchema( $data = FALSE, $indent = '  ' ) {
02098                 $old_mode = $this->db->SetFetchMode( ADODB_FETCH_NUM );
02099                 
02100                 $schema = '<?xml version="1.0"?>' . "\n"
02101                                 . '<schema version="' . $this->schemaVersion . '">' . "\n";
02102                 
02103                 if( is_array( $tables = $this->db->MetaTables( 'TABLES' ) ) ) {
02104                         foreach( $tables as $table ) {
02105                                 $schema .= $indent . '<table name="' . htmlentities( $table ) . '">' . "\n";
02106                                 
02107                                 // grab details from database
02108                                 $rs = $this->db->Execute( 'SELECT * FROM ' . $table . ' WHERE -1' );
02109                                 $fields = $this->db->MetaColumns( $table );
02110                                 $indexes = $this->db->MetaIndexes( $table );
02111                                 
02112                                 if( is_array( $fields ) ) {
02113                                         foreach( $fields as $details ) {
02114                                                 $extra = '';
02115                                                 $content = array();
02116                                                 
02117                                                 if( isset($details->max_length) && $details->max_length > 0 ) {
02118                                                         $extra .= ' size="' . $details->max_length . '"';
02119                                                 }
02120                                                 
02121                                                 if( isset($details->primary_key) && $details->primary_key ) {
02122                                                         $content[] = '<KEY/>';
02123                                                 } elseif( isset($details->not_null) && $details->not_null ) {
02124                                                         $content[] = '<NOTNULL/>';
02125                                                 }
02126                                                 
02127                                                 if( isset($details->has_default) && $details->has_default ) {
02128                                                         $content[] = '<DEFAULT value="' . htmlentities( $details->default_value ) . '"/>';
02129                                                 }
02130                                                 
02131                                                 if( isset($details->auto_increment) && $details->auto_increment ) {
02132                                                         $content[] = '<AUTOINCREMENT/>';
02133                                                 }
02134                                                 
02135                                                 if( isset($details->unsigned) && $details->unsigned ) {
02136                                                         $content[] = '<UNSIGNED/>';
02137                                                 }
02138                                                 
02139                                                 // this stops the creation of 'R' columns,
02140                                                 // AUTOINCREMENT is used to create auto columns
02141                                                 $details->primary_key = 0;
02142                                                 $type = $rs->MetaType( $details );
02143                                                 
02144                                                 $schema .= str_repeat( $indent, 2 ) . '<field name="' . htmlentities( $details->name ) . '" type="' . $type . '"' . $extra;
02145                                                 
02146                                                 if( !empty( $content ) ) {
02147                                                         $schema .= ">\n" . str_repeat( $indent, 3 )
02148                                                                          . implode( "\n" . str_repeat( $indent, 3 ), $content ) . "\n"
02149                                                                          . str_repeat( $indent, 2 ) . '</field>' . "\n";
02150                                                 } else {
02151                                                         $schema .= "/>\n";
02152                                                 }
02153                                         }
02154                                 }
02155                                 
02156                                 if( is_array( $indexes ) ) {
02157                                         foreach( $indexes as $index => $details ) {
02158                                                 $schema .= str_repeat( $indent, 2 ) . '<index name="' . $index . '">' . "\n";
02159                                                 
02160                                                 if( $details['unique'] ) {
02161                                                         $schema .= str_repeat( $indent, 3 ) . '<UNIQUE/>' . "\n";
02162                                                 }
02163                                                 
02164                                                 foreach( $details['columns'] as $column ) {
02165                                                         $schema .= str_repeat( $indent, 3 ) . '<col>' . htmlentities( $column ) . '</col>' . "\n";
02166                                                 }
02167                                                 
02168                                                 $schema .= str_repeat( $indent, 2 ) . '</index>' . "\n";
02169                                         }
02170                                 }
02171                                 
02172                                 if( $data ) {
02173                                         $rs = $this->db->Execute( 'SELECT * FROM ' . $table );
02174                                         
02175                                         if( is_object( $rs ) && !$rs->EOF ) {
02176                                                 $schema .= str_repeat( $indent, 2 ) . "<data>\n";
02177                                                 
02178                                                 while( $row = $rs->FetchRow() ) {
02179                                                         foreach( $row as $key => $val ) {
02180                                                                 if ( $val != htmlentities( $val ) ) {
02181                                                                         $row[$key] = '<![CDATA[' . $val . ']]>';
02182                                                                 }
02183                                                         }
02184                                                         
02185                                                         $schema .= str_repeat( $indent, 3 ) . '<row><f>' . implode( '</f><f>', $row ) . "</f></row>\n";
02186                                                 }
02187                                                 
02188                                                 $schema .= str_repeat( $indent, 2 ) . "</data>\n";
02189                                         }
02190                                 }
02191                                 
02192                                 $schema .= $indent . "</table>\n";
02193                         }
02194                 }
02195                 
02196                 $this->db->SetFetchMode( $old_mode );
02197                 
02198                 $schema .= '</schema>';
02199                 return $schema;
02200         }
02201         
02212         function SetPrefix( $prefix = '', $underscore = TRUE ) {
02213                 switch( TRUE ) {
02214                         // clear prefix
02215                         case empty( $prefix ):
02216                                 logMsg( 'Cleared prefix' );
02217                                 $this->objectPrefix = '';
02218                                 return TRUE;
02219                         // prefix too long
02220                         case strlen( $prefix ) > XMLS_PREFIX_MAXLEN:
02221                         // prefix contains invalid characters
02222                         case !preg_match( '/^[a-z][a-z0-9_]+$/i', $prefix ):
02223                                 logMsg( 'Invalid prefix: ' . $prefix );
02224                                 return FALSE;
02225                 }
02226                 
02227                 if( $underscore AND substr( $prefix, -1 ) != '_' ) {
02228                         $prefix .= '_';
02229                 }
02230                 
02231                 // prefix valid
02232                 logMsg( 'Set prefix: ' . $prefix );
02233                 $this->objectPrefix = $prefix;
02234                 return TRUE;
02235         }
02236         
02245         function prefix( $name = '' ) {
02246                 // if prefix is set
02247                 if( !empty( $this->objectPrefix ) ) {
02248                         // Prepend the object prefix to the table name
02249                         // prepend after quote if used
02250                         return preg_replace( '/^(`?)(.+)$/', '$1' . $this->objectPrefix . '$2', $name );
02251                 }
02252                 
02253                 // No prefix set. Use name provided.
02254                 return $name;
02255         }
02256         
02265         function supportedPlatform( $platform = NULL ) {
02266                 if( !empty( $platform ) ) {
02267                         $regex = '/(^|\|)' . $this->db->databaseType . '(\||$)/i';
02268                 
02269                         if( preg_match( '/^- /', $platform ) ) {
02270                                 if (preg_match ( $regex, substr( $platform, 2 ) ) ) {
02271                                         logMsg( 'Platform ' . $platform . ' is NOT supported' );
02272                                         return FALSE;
02273                                 }
02274                 } else {
02275                                 if( !preg_match ( $regex, $platform ) ) {
02276                                         logMsg( 'Platform ' . $platform . ' is NOT supported' );
02277                         return FALSE;
02278                 }
02279         }
02280                 }
02281                 
02282                 logMsg( 'Platform ' . $platform . ' is supported' );
02283                 return TRUE;
02284         }
02285         
02291         function clearSQL() {
02292                 $this->sqlArray = array();
02293         }
02294         
02303         function addSQL( $sql = NULL ) {
02304                 if( is_array( $sql ) ) {
02305                         foreach( $sql as $line ) {
02306                                 $this->addSQL( $line );
02307                         }
02308                         
02309                         return TRUE;
02310                 }
02311                 
02312                 if( is_string( $sql ) ) {
02313                         $this->sqlArray[] = $sql;
02314                         
02315                         // if executeInline is enabled, and either no errors have occurred or continueOnError is enabled, execute SQL.
02316                         if( $this->ExecuteInline() && ( $this->success == 2 || $this->ContinueOnError() ) ) {
02317                                 $saved = $this->db->debug;
02318                                 $this->db->debug = $this->debug;
02319                                 $ok = $this->db->Execute( $sql );
02320                                 $this->db->debug = $saved;
02321                                 
02322                                 if( !$ok ) {
02323                                         if( $this->debug ) {
02324                                                 ADOConnection::outp( $this->db->ErrorMsg() );
02325                                         }
02326                                         
02327                                         $this->success = 1;
02328                                 }
02329                         }
02330                         
02331                         return TRUE;
02332                 }
02333                 
02334                 return FALSE;
02335         }
02336         
02345         function getSQL( $format = NULL, $sqlArray = NULL ) {
02346                 if( !is_array( $sqlArray ) ) {
02347                         $sqlArray = $this->sqlArray;
02348                 }
02349                 
02350                 if( !is_array( $sqlArray ) ) {
02351                         return FALSE;
02352                 }
02353                 
02354                 switch( strtolower( $format ) ) {
02355                         case 'string':
02356                         case 'text':
02357                                 return !empty( $sqlArray ) ? implode( ";\n\n", $sqlArray ) . ';' : '';
02358                         case'html':
02359                                 return !empty( $sqlArray ) ? nl2br( htmlentities( implode( ";\n\n", $sqlArray ) . ';' ) ) : '';
02360                 }
02361                 
02362                 return $this->sqlArray;
02363         }
02364         
02371         function Destroy() {
02372                 set_magic_quotes_runtime( $this->mgq );
02373                 unset( $this );
02374         }
02375 }
02376 
02382 function logMsg( $msg, $title = NULL, $force = FALSE ) {
02383         if( XMLS_DEBUG or $force ) {
02384                 echo '<pre>';
02385                 
02386                 if( isset( $title ) ) {
02387                         echo '<h3>' . htmlentities( $title ) . '</h3>';
02388                 }
02389                 
02390                 if( @is_object( $this ) ) {
02391                         echo '[' . get_class( $this ) . '] ';
02392                 }
02393                 
02394                 print_r( $msg );
02395                 
02396                 echo '</pre>';
02397         }
02398 }
02399 ?>