Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/adodb/adodb-xmlschema03.inc.php
Go to the documentation of this file.
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(&$xmls) {
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(isset($this->currentPlatform)) {
00508                         $this->opts[$this->parent->db->databaseType] = $opt;
00509                 }
00510                 return $this->opts;
00511         }
00512 
00513         
00520         function create( &$xmls ) {
00521                 $sql = array();
00522                 
00523                 // drop any existing indexes
00524                 if( is_array( $legacy_indexes = $xmls->dict->MetaIndexes( $this->name ) ) ) {
00525                         foreach( $legacy_indexes as $index => $index_details ) {
00526                                 $sql[] = $xmls->dict->DropIndexSQL( $index, $this->name );
00527                         }
00528                 }
00529                 
00530                 // remove fields to be dropped from table object
00531                 foreach( $this->drop_field as $field ) {
00532                         unset( $this->fields[$field] );
00533                 }
00534                 
00535                 // if table exists
00536                 if( is_array( $legacy_fields = $xmls->dict->MetaColumns( $this->name ) ) ) {
00537                         // drop table
00538                         if( $this->drop_table ) {
00539                                 $sql[] = $xmls->dict->DropTableSQL( $this->name );
00540                                 
00541                                 return $sql;
00542                         }
00543                         
00544                         // drop any existing fields not in schema
00545                         foreach( $legacy_fields as $field_id => $field ) {
00546                                 if( !isset( $this->fields[$field_id] ) ) {
00547                                         $sql[] = $xmls->dict->DropColumnSQL( $this->name, $field->name );
00548                                 }
00549                         }
00550                 // if table doesn't exist
00551                 } else {
00552                         if( $this->drop_table ) {
00553                                 return $sql;
00554                         }
00555                         
00556                         $legacy_fields = array();
00557                 }
00558                 
00559                 // Loop through the field specifier array, building the associative array for the field options
00560                 $fldarray = array();
00561                 
00562                 foreach( $this->fields as $field_id => $finfo ) {
00563                         // Set an empty size if it isn't supplied
00564                         if( !isset( $finfo['SIZE'] ) ) {
00565                                 $finfo['SIZE'] = '';
00566                         }
00567                         
00568                         // Initialize the field array with the type and size
00569                         $fldarray[$field_id] = array(
00570                                 'NAME' => $finfo['NAME'],
00571                                 'TYPE' => $finfo['TYPE'],
00572                                 'SIZE' => $finfo['SIZE']
00573                         );
00574                         
00575                         // Loop through the options array and add the field options. 
00576                         if( isset( $finfo['OPTS'] ) ) {
00577                                 foreach( $finfo['OPTS'] as $opt ) {
00578                                         // Option has an argument.
00579                                         if( is_array( $opt ) ) {
00580                                                 $key = key( $opt );
00581                                                 $value = $opt[key( $opt )];
00582                                                 @$fldarray[$field_id][$key] .= $value;
00583                                         // Option doesn't have arguments
00584                                         } else {
00585                                                 $fldarray[$field_id][$opt] = $opt;
00586                                         }
00587                                 }
00588                         }
00589                 }
00590                 
00591                 if( empty( $legacy_fields ) ) {
00592                         // Create the new table
00593                         $sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts );
00594                         logMsg( end( $sql ), 'Generated CreateTableSQL' );
00595                 } else {
00596                         // Upgrade an existing table
00597                         logMsg( "Upgrading {$this->name} using '{$xmls->upgrade}'" );
00598                         switch( $xmls->upgrade ) {
00599                                 // Use ChangeTableSQL
00600                                 case 'ALTER':
00601                                         logMsg( 'Generated ChangeTableSQL (ALTERing table)' );
00602                                         $sql[] = $xmls->dict->ChangeTableSQL( $this->name, $fldarray, $this->opts );
00603                                         break;
00604                                 case 'REPLACE':
00605                                         logMsg( 'Doing upgrade REPLACE (testing)' );
00606                                         $sql[] = $xmls->dict->DropTableSQL( $this->name );
00607                                         $sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts );
00608                                         break;
00609                                 // ignore table
00610                                 default:
00611                                         return array();
00612                         }
00613                 }
00614                 
00615                 foreach( $this->indexes as $index ) {
00616                         $sql[] = $index->create( $xmls );
00617                 }
00618                 
00619                 if( isset( $this->data ) ) {
00620                         $sql[] = $this->data->create( $xmls );
00621                 }
00622                 
00623                 return $sql;
00624         }
00625         
00629         function drop() {
00630                 if( isset( $this->current_field ) ) {
00631                         // Drop the current field
00632                         logMsg( "Dropping field '{$this->current_field}' from table '{$this->name}'" );
00633                         // $this->drop_field[$this->current_field] = $xmls->dict->DropColumnSQL( $this->name, $this->current_field );
00634                         $this->drop_field[$this->current_field] = $this->current_field;
00635                 } else {
00636                         // Drop the current table
00637                         logMsg( "Dropping table '{$this->name}'" );
00638                         // $this->drop_table = $xmls->dict->DropTableSQL( $this->name );
00639                         $this->drop_table = TRUE;
00640                 }
00641         }
00642 }
00643 
00655 class dbIndex extends dbObject {
00656         
00660         var $name;
00661         
00665         var $opts = array();
00666         
00670         var $columns = array();
00671         
00676         var $drop = FALSE;
00677         
00686         function dbIndex( &$parent, $attributes = NULL ) {
00687                 $this->parent = $parent;
00688                 
00689                 $this->name = $this->prefix ($attributes['NAME']);
00690         }
00691         
00700         function _tag_open( &$parser, $tag, $attributes ) {
00701                 $this->currentElement = strtoupper( $tag );
00702                 
00703                 switch( $this->currentElement ) {
00704                         case 'DROP':
00705                                 $this->drop();
00706                                 break;
00707                         case 'CLUSTERED':
00708                         case 'BITMAP':
00709                         case 'UNIQUE':
00710                         case 'FULLTEXT':
00711                         case 'HASH':
00712                                 // Add index Option
00713                                 $this->addIndexOpt( $this->currentElement );
00714                                 break;
00715                         default:
00716                                 // print_r( array( $tag, $attributes ) );
00717                 }
00718         }
00719         
00727         function _tag_cdata( &$parser, $cdata ) {
00728                 switch( $this->currentElement ) {
00729                         // Index field name
00730                         case 'COL':
00731                                 $this->addField( $cdata );
00732                                 break;
00733                         default:
00734                                 
00735                 }
00736         }
00737         
00743         function _tag_close( &$parser, $tag ) {
00744                 $this->currentElement = '';
00745                 
00746                 switch( strtoupper( $tag ) ) {
00747                         case 'INDEX':
00748                                 xml_set_object( $parser, $this->parent );
00749                                 break;
00750                 }
00751         }
00752         
00759         function addField( $name ) {
00760                 $this->columns[$this->FieldID( $name )] = $name;
00761                 
00762                 // Return the field list
00763                 return $this->columns;
00764         }
00765         
00772         function addIndexOpt( $opt ) {
00773                 $this->opts[] = $opt;
00774                 
00775                 // Return the options list
00776                 return $this->opts;
00777         }
00778         
00785         function create( &$xmls ) {
00786                 if( $this->drop ) {
00787                         return NULL;
00788                 }
00789                 
00790                 // eliminate any columns that aren't in the table
00791                 foreach( $this->columns as $id => $col ) {
00792                         if( !isset( $this->parent->fields[$id] ) ) {
00793                                 unset( $this->columns[$id] );
00794                         }
00795                 }
00796                 
00797                 return $xmls->dict->CreateIndexSQL( $this->name, $this->parent->name, $this->columns, $this->opts );
00798         }
00799         
00803         function drop() {
00804                 $this->drop = TRUE;
00805         }
00806 }
00807 
00817 class dbData extends dbObject {
00818         
00819         var $data = array();
00820         
00821         var $row;
00822         
00831         function dbData( &$parent, $attributes = NULL ) {
00832                 $this->parent = $parent;
00833         }
00834         
00843         function _tag_open( &$parser, $tag, $attributes ) {
00844                 $this->currentElement = strtoupper( $tag );
00845                 
00846                 switch( $this->currentElement ) {
00847                         case 'ROW':
00848                                 $this->row = count( $this->data );
00849                                 $this->data[$this->row] = array();
00850                                 break;
00851                         case 'F':
00852                                 $this->addField($attributes);
00853                         default:
00854                                 // print_r( array( $tag, $attributes ) );
00855                 }
00856         }
00857         
00865         function _tag_cdata( &$parser, $cdata ) {
00866                 switch( $this->currentElement ) {
00867                         // Index field name
00868                         case 'F':
00869                                 $this->addData( $cdata );
00870                                 break;
00871                         default:
00872                                 
00873                 }
00874         }
00875         
00881         function _tag_close( &$parser, $tag ) {
00882                 $this->currentElement = '';
00883                 
00884                 switch( strtoupper( $tag ) ) {
00885                         case 'DATA':
00886                                 xml_set_object( $parser, $this->parent );
00887                                 break;
00888                 }
00889         }
00890         
00897         function addField( $attributes ) {
00898                 // check we're in a valid row
00899                 if( !isset( $this->row ) || !isset( $this->data[$this->row] ) ) {
00900                         return;
00901                 }
00902                 
00903                 // Set the field index so we know where we are
00904                 if( isset( $attributes['NAME'] ) ) {
00905                         $this->current_field = $this->FieldID( $attributes['NAME'] );
00906                 } else {
00907                         $this->current_field = count( $this->data[$this->row] );
00908                 }
00909                 
00910                 // initialise data
00911                 if( !isset( $this->data[$this->row][$this->current_field] ) ) {
00912                         $this->data[$this->row][$this->current_field] = '';
00913                 }
00914         }
00915         
00922         function addData( $cdata ) {
00923                 // check we're in a valid field
00924                 if ( isset( $this->data[$this->row][$this->current_field] ) ) {
00925                         // add data to field
00926                         $this->data[$this->row][$this->current_field] .= $cdata;
00927                 }
00928         }
00929         
00936         function create( &$xmls ) {
00937                 $table = $xmls->dict->TableName($this->parent->name);
00938                 $table_field_count = count($this->parent->fields);
00939                 $tables = $xmls->db->MetaTables(); 
00940                 $sql = array();
00941                 
00942                 $ukeys = $xmls->db->MetaPrimaryKeys( $table );
00943                 if( !empty( $this->parent->indexes ) and !empty( $ukeys ) ) {
00944                         foreach( $this->parent->indexes as $indexObj ) {
00945                                 if( !in_array( $indexObj->name, $ukeys ) ) $ukeys[] = $indexObj->name;
00946                         }
00947                 }
00948                 
00949                 // eliminate any columns that aren't in the table
00950                 foreach( $this->data as $row ) {
00951                         $table_fields = $this->parent->fields;
00952                         $fields = array();
00953                         $rawfields = array(); // Need to keep some of the unprocessed data on hand.
00954                         
00955                         foreach( $row as $field_id => $field_data ) {
00956                                 if( !array_key_exists( $field_id, $table_fields ) ) {
00957                                         if( is_numeric( $field_id ) ) {
00958                                                 $field_id = reset( array_keys( $table_fields ) );
00959                                         } else {
00960                                                 continue;
00961                                         }
00962                                 }
00963                                 
00964                                 $name = $table_fields[$field_id]['NAME'];
00965                                 
00966                                 switch( $table_fields[$field_id]['TYPE'] ) {
00967                                         case 'I':
00968                                         case 'I1':
00969                                         case 'I2':
00970                                         case 'I4':
00971                                         case 'I8':
00972                                                 $fields[$name] = intval($field_data);
00973                                                 break;
00974                                         case 'C':
00975                                         case 'C2':
00976                                         case 'X':
00977                                         case 'X2':
00978                                         default:
00979                                                 $fields[$name] = $xmls->db->qstr( $field_data );
00980                                                 $rawfields[$name] = $field_data;
00981                                 }
00982                                 
00983                                 unset($table_fields[$field_id]);
00984                                 
00985                         }
00986                         
00987                         // check that at least 1 column is specified
00988                         if( empty( $fields ) ) {
00989                                 continue;
00990                         }
00991                         
00992                         // check that no required columns are missing
00993                         if( count( $fields ) < $table_field_count ) {
00994                                 foreach( $table_fields as $field ) {
00995                                         if( isset( $field['OPTS'] ) and ( in_array( 'NOTNULL', $field['OPTS'] ) || in_array( 'KEY', $field['OPTS'] ) ) && !in_array( 'AUTOINCREMENT', $field['OPTS'] ) ) {
00996                                                         continue(2);
00997                                                 }
00998                                 }
00999                         }
01000                         
01001                         // The rest of this method deals with updating existing data records.
01002                         
01003                         if( !in_array( $table, $tables ) or ( $mode = $xmls->existingData() ) == XMLS_MODE_INSERT ) {
01004                                 // Table doesn't yet exist, so it's safe to insert.
01005                                 logMsg( "$table doesn't exist, inserting or mode is INSERT" );
01006                         $sql[] = 'INSERT INTO '. $table .' ('. implode( ',', array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')';
01007                                 continue;
01008                 }
01009                 
01010                         // Prepare to test for potential violations. Get primary keys and unique indexes
01011                         $mfields = array_merge( $fields, $rawfields );
01012                         $keyFields = array_intersect( $ukeys, array_keys( $mfields ) );
01013                         
01014                         if( empty( $ukeys ) or count( $keyFields ) == 0 ) {
01015                                 // No unique keys in schema, so safe to insert
01016                                 logMsg( "Either schema or data has no unique keys, so safe to insert" );
01017                                 $sql[] = 'INSERT INTO '. $table .' ('. implode( ',', array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')';
01018                                 continue;
01019                         }
01020                         
01021                         // Select record containing matching unique keys.
01022                         $where = '';
01023                         foreach( $ukeys as $key ) {
01024                                 if( isset( $mfields[$key] ) and $mfields[$key] ) {
01025                                         if( $where ) $where .= ' AND ';
01026                                         $where .= $key . ' = ' . $xmls->db->qstr( $mfields[$key] );
01027                                 }
01028                         }
01029                         $records = $xmls->db->Execute( 'SELECT * FROM ' . $table . ' WHERE ' . $where );
01030                         switch( $records->RecordCount() ) {
01031                                 case 0:
01032                                         // No matching record, so safe to insert.
01033                                         logMsg( "No matching records. Inserting new row with unique data" );
01034                                         $sql[] = $xmls->db->GetInsertSQL( $records, $mfields );
01035                                         break;
01036                                 case 1:
01037                                         // Exactly one matching record, so we can update if the mode permits.
01038                                         logMsg( "One matching record..." );
01039                                         if( $mode == XMLS_MODE_UPDATE ) {
01040                                                 logMsg( "...Updating existing row from unique data" );
01041                                                 $sql[] = $xmls->db->GetUpdateSQL( $records, $mfields );
01042                                         }
01043                                         break;
01044                                 default:
01045                                         // More than one matching record; the result is ambiguous, so we must ignore the row.
01046                                         logMsg( "More than one matching record. Ignoring row." );
01047                         }
01048                 }
01049                 return $sql;
01050         }
01051 }
01052 
01059 class dbQuerySet extends dbObject {
01060         
01064         var $queries = array();
01065         
01069         var $query;
01070         
01074         var $prefixKey = '';
01075         
01079         var $prefixMethod = 'AUTO';
01080         
01087         function dbQuerySet( &$parent, $attributes = NULL ) {
01088                 $this->parent = $parent;
01089                         
01090                 // Overrides the manual prefix key
01091                 if( isset( $attributes['KEY'] ) ) {
01092                         $this->prefixKey = $attributes['KEY'];
01093                 }
01094                 
01095                 $prefixMethod = isset( $attributes['PREFIXMETHOD'] ) ? strtoupper( trim( $attributes['PREFIXMETHOD'] ) ) : '';
01096                 
01097                 // Enables or disables automatic prefix prepending
01098                 switch( $prefixMethod ) {
01099                         case 'AUTO':
01100                                 $this->prefixMethod = 'AUTO';
01101                                 break;
01102                         case 'MANUAL':
01103                                 $this->prefixMethod = 'MANUAL';
01104                                 break;
01105                         case 'NONE':
01106                                 $this->prefixMethod = 'NONE';
01107                                 break;
01108                 }
01109         }
01110         
01117         function _tag_open( &$parser, $tag, $attributes ) {
01118                 $this->currentElement = strtoupper( $tag );
01119                 
01120                 switch( $this->currentElement ) {
01121                         case 'QUERY':
01122                                 // Create a new query in a SQL queryset.
01123                                 // Ignore this query set if a platform is specified and it's different than the 
01124                                 // current connection platform.
01125                                 if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
01126                                         $this->newQuery();
01127                                 } else {
01128                                         $this->discardQuery();
01129                                 }
01130                                 break;
01131                         default:
01132                                 // print_r( array( $tag, $attributes ) );
01133                 }
01134         }
01135         
01139         function _tag_cdata( &$parser, $cdata ) {
01140                 switch( $this->currentElement ) {
01141                         // Line of queryset SQL data
01142                         case 'QUERY':
01143                                 $this->buildQuery( $cdata );
01144                                 break;
01145                         default:
01146                                 
01147                 }
01148         }
01149         
01155         function _tag_close( &$parser, $tag ) {
01156                 $this->currentElement = '';
01157                 
01158                 switch( strtoupper( $tag ) ) {
01159                         case 'QUERY':
01160                                 // Add the finished query to the open query set.
01161                                 $this->addQuery();
01162                                 break;
01163                         case 'SQL':
01164                                 $this->parent->addSQL( $this->create( $this->parent ) );
01165                                 xml_set_object( $parser, $this->parent );
01166                                 $this->destroy();
01167                                 break;
01168                         default:
01169                                 
01170                 }
01171         }
01172         
01178         function newQuery() {
01179                 $this->query = '';
01180                 
01181                 return TRUE;
01182         }
01183         
01189         function discardQuery() {
01190                 unset( $this->query );
01191                 
01192                 return TRUE;
01193         }
01194         
01201         function buildQuery( $sql = NULL ) {
01202                 if( !isset( $this->query ) OR empty( $sql ) ) {
01203                         return FALSE;
01204                 }
01205                 
01206                 $this->query .= $sql;
01207                 
01208                 return $this->query;
01209         }
01210         
01216         function addQuery() {
01217                 if( !isset( $this->query ) ) {
01218                         return FALSE;
01219                 }
01220                 
01221                 $this->queries[] = $return = trim($this->query);
01222                 
01223                 unset( $this->query );
01224                 
01225                 return $return;
01226         }
01227         
01234         function create( &$xmls ) {
01235                 foreach( $this->queries as $id => $query ) {
01236                         switch( $this->prefixMethod ) {
01237                                 case 'AUTO':
01238                                         // Enable auto prefix replacement
01239                                         
01240                                         // Process object prefix.
01241                                         // Evaluate SQL statements to prepend prefix to objects
01242                                         $query = $this->prefixQuery( '/^\s*((?is)INSERT\s+(INTO\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
01243                                         $query = $this->prefixQuery( '/^\s*((?is)UPDATE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
01244                                         $query = $this->prefixQuery( '/^\s*((?is)DELETE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
01245                                         
01246                                         // SELECT statements aren't working yet
01247                                         #$data = preg_replace( '/(?ias)(^\s*SELECT\s+.*\s+FROM)\s+(\W\s*,?\s*)+((?i)\s+WHERE.*$)/', "\1 $prefix\2 \3", $data );
01248                                         
01249                                 case 'MANUAL':
01250                                         // If prefixKey is set and has a value then we use it to override the default constant XMLS_PREFIX.
01251                                         // If prefixKey is not set, we use the default constant XMLS_PREFIX
01252                                         if( isset( $this->prefixKey ) AND( $this->prefixKey !== '' ) ) {
01253                                                 // Enable prefix override
01254                                                 $query = str_replace( $this->prefixKey, $xmls->objectPrefix, $query );
01255                                         } else {
01256                                                 // Use default replacement
01257                                                 $query = str_replace( XMLS_PREFIX , $xmls->objectPrefix, $query );
01258                                         }
01259                         }
01260                         
01261                         $this->queries[$id] = trim( $query );
01262                 }
01263                 
01264                 // Return the query set array
01265                 return $this->queries;
01266         }
01267         
01276         function prefixQuery( $regex, $query, $prefix = NULL ) {
01277                 if( !isset( $prefix ) ) {
01278                         return $query;
01279                 }
01280                 
01281                 if( preg_match( $regex, $query, $match ) ) {
01282                         $preamble = $match[1];
01283                         $postamble = $match[5];
01284                         $objectList = explode( ',', $match[3] );
01285                         // $prefix = $prefix . '_';
01286                         
01287                         $prefixedList = '';
01288                         
01289                         foreach( $objectList as $object ) {
01290                                 if( $prefixedList !== '' ) {
01291                                         $prefixedList .= ', ';
01292                                 }
01293                                 
01294                                 $prefixedList .= $prefix . trim( $object );
01295                         }
01296                         
01297                         $query = $preamble . ' ' . $prefixedList . ' ' . $postamble;
01298                 }
01299                 
01300                 return $query;
01301         }
01302 }
01303 
01317 class adoSchema {
01318         
01323         var $sqlArray;
01324         
01329         var $db;
01330         
01335         var $dict;
01336         
01341         var $currentElement = '';
01342         
01347         var $upgrade = '';
01348         
01353         var $objectPrefix = '';
01354         
01359         var $mgq;
01360         
01365         var $debug;
01366         
01371         var $versionRegex = '/<schema.*?( version="([^"]*)")?.*?>/';
01372         
01377         var $schemaVersion;
01378         
01382         var $success;
01383         
01387         var $executeInline;
01388         
01392         var $continueOnError;
01393         
01397         var $existingData;
01398         
01408         function adoSchema( $db ) {
01409                 // Initialize the environment
01410                 $this->mgq = get_magic_quotes_runtime();
01411                 #set_magic_quotes_runtime(0);
01412                 ini_set("magic_quotes_runtime", 0);
01413                 
01414                 $this->db = $db;
01415                 $this->debug = $this->db->debug;
01416                 $this->dict = NewDataDictionary( $this->db );
01417                 $this->sqlArray = array();
01418                 $this->schemaVersion = XMLS_SCHEMA_VERSION;
01419                 $this->executeInline( XMLS_EXECUTE_INLINE );
01420                 $this->continueOnError( XMLS_CONTINUE_ON_ERROR );
01421                 $this->existingData( XMLS_EXISTING_DATA );
01422                 $this->setUpgradeMethod();
01423         }
01424         
01441         function SetUpgradeMethod( $method = '' ) {
01442                 if( !is_string( $method ) ) {
01443                         return FALSE;
01444                 }
01445                 
01446                 $method = strtoupper( $method );
01447                 
01448                 // Handle the upgrade methods
01449                 switch( $method ) {
01450                         case 'ALTER':
01451                                 $this->upgrade = $method;
01452                                 break;
01453                         case 'REPLACE':
01454                                 $this->upgrade = $method;
01455                                 break;
01456                         case 'BEST':
01457                                 $this->upgrade = 'ALTER';
01458                                 break;
01459                         case 'NONE':
01460                                 $this->upgrade = 'NONE';
01461                                 break;
01462                         default:
01463                                 // Use default if no legitimate method is passed.
01464                                 $this->upgrade = XMLS_DEFAULT_UPGRADE_METHOD;
01465                 }
01466                 
01467                 return $this->upgrade;
01468         }
01469         
01489         function ExistingData( $mode = NULL ) {
01490                 if( is_int( $mode ) ) {
01491                         switch( $mode ) {
01492                                 case XMLS_MODE_UPDATE:
01493                                         $mode = XMLS_MODE_UPDATE;
01494                                         break;
01495                                 case XMLS_MODE_IGNORE:
01496                                         $mode = XMLS_MODE_IGNORE;
01497                                         break;
01498                                 case XMLS_MODE_INSERT:
01499                                         $mode = XMLS_MODE_INSERT;
01500                                         break;
01501                                 default:
01502                                         $mode = XMLS_EXISTING_DATA;
01503                                         break;
01504                         }
01505                         $this->existingData = $mode;
01506                 }
01507                 
01508                 return $this->existingData;
01509         }
01510         
01524         function ExecuteInline( $mode = NULL ) {
01525                 if( is_bool( $mode ) ) {
01526                         $this->executeInline = $mode;
01527                 }
01528                 
01529                 return $this->executeInline;
01530         }
01531         
01545         function ContinueOnError( $mode = NULL ) {
01546                 if( is_bool( $mode ) ) {
01547                         $this->continueOnError = $mode;
01548                 }
01549                 
01550                 return $this->continueOnError;
01551         }
01552         
01566         function ParseSchema( $filename, $returnSchema = FALSE ) {
01567                 return $this->ParseSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema );
01568         }
01569         
01591         function ParseSchemaFile( $filename, $returnSchema = FALSE ) {
01592                 // Open the file
01593                 if( !($fp = fopen( $filename, 'r' )) ) {
01594                         logMsg( 'Unable to open file' );
01595                         return FALSE;
01596                 }
01597                 
01598                 // do version detection here
01599                 if( $this->SchemaFileVersion( $filename ) != $this->schemaVersion ) {
01600                         logMsg( 'Invalid Schema Version' );
01601                         return FALSE;
01602                 }
01603                 
01604                 if( $returnSchema ) {
01605                         $xmlstring = '';
01606                         while( $data = fread( $fp, 4096 ) ) {
01607                                 $xmlstring .= $data . "\n";
01608                         }
01609                         return $xmlstring;
01610                 }
01611                 
01612                 $this->success = 2;
01613                 
01614                 $xmlParser = $this->create_parser();
01615                 
01616                 // Process the file
01617                 while( $data = fread( $fp, 4096 ) ) {
01618                         if( !xml_parse( $xmlParser, $data, feof( $fp ) ) ) {
01619                                 die( sprintf(
01620                                         "XML error: %s at line %d",
01621                                         xml_error_string( xml_get_error_code( $xmlParser) ),
01622                                         xml_get_current_line_number( $xmlParser)
01623                                 ) );
01624                         }
01625                 }
01626                 
01627                 xml_parser_free( $xmlParser );
01628                 
01629                 return $this->sqlArray;
01630         }
01631         
01643         function ParseSchemaString( $xmlstring, $returnSchema = FALSE ) {
01644                 if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
01645                         logMsg( 'Empty or Invalid Schema' );
01646                         return FALSE;
01647                 }
01648                 
01649                 // do version detection here
01650                 if( $this->SchemaStringVersion( $xmlstring ) != $this->schemaVersion ) {
01651                         logMsg( 'Invalid Schema Version' );
01652                         return FALSE;
01653                 }
01654                 
01655                 if( $returnSchema ) {
01656                         return $xmlstring;
01657                 }
01658                 
01659                 $this->success = 2;
01660                 
01661                 $xmlParser = $this->create_parser();
01662                 
01663                 if( !xml_parse( $xmlParser, $xmlstring, TRUE ) ) {
01664                         die( sprintf(
01665                                 "XML error: %s at line %d",
01666                                 xml_error_string( xml_get_error_code( $xmlParser) ),
01667                                 xml_get_current_line_number( $xmlParser)
01668                         ) );
01669                 }
01670                 
01671                 xml_parser_free( $xmlParser );
01672                 
01673                 return $this->sqlArray;
01674         }
01675         
01687         function RemoveSchema( $filename, $returnSchema = FALSE ) {
01688                 return $this->RemoveSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema );
01689         }
01690         
01702         function RemoveSchemaString( $schema, $returnSchema = FALSE ) {
01703                 
01704                 // grab current version
01705                 if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
01706                         return FALSE;
01707                 }
01708                 
01709                 return $this->ParseSchemaString( $this->TransformSchema( $schema, 'remove-' . $version), $returnSchema );
01710         }
01711         
01725         function ExecuteSchema( $sqlArray = NULL, $continueOnErr =  NULL ) {
01726                 if( !is_bool( $continueOnErr ) ) {
01727                         $continueOnErr = $this->ContinueOnError();
01728                 }
01729                 
01730                 if( !isset( $sqlArray ) ) {
01731                         $sqlArray = $this->sqlArray;
01732                 }
01733                 
01734                 if( !is_array( $sqlArray ) ) {
01735                         $this->success = 0;
01736                 } else {
01737                         $this->success = $this->dict->ExecuteSQLArray( $sqlArray, $continueOnErr );
01738                 }
01739                 
01740                 return $this->success;
01741         }
01742         
01752         function PrintSQL( $format = 'NONE' ) {
01753                 $sqlArray = null;
01754                 return $this->getSQL( $format, $sqlArray );
01755         }
01756         
01766         function SaveSQL( $filename = './schema.sql' ) {
01767                 
01768                 if( !isset( $sqlArray ) ) {
01769                         $sqlArray = $this->sqlArray;
01770                 }
01771                 if( !isset( $sqlArray ) ) {
01772                         return FALSE;
01773                 }
01774                 
01775                 $fp = fopen( $filename, "w" );
01776                 
01777                 foreach( $sqlArray as $key => $query ) {
01778                         fwrite( $fp, $query . ";\n" );
01779                 }
01780                 fclose( $fp );
01781         }
01782         
01790         function create_parser() {
01791                 // Create the parser
01792                 $xmlParser = xml_parser_create();
01793                 xml_set_object( $xmlParser, $this );
01794                 
01795                 // Initialize the XML callback functions
01796                 xml_set_element_handler( $xmlParser, '_tag_open', '_tag_close' );
01797                 xml_set_character_data_handler( $xmlParser, '_tag_cdata' );
01798                 
01799                 return $xmlParser;
01800         }
01801         
01807         function _tag_open( &$parser, $tag, $attributes ) {
01808                 switch( strtoupper( $tag ) ) {
01809                         case 'TABLE':
01810                                 if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
01811                                 $this->obj = new dbTable( $this, $attributes );
01812                                 xml_set_object( $parser, $this->obj );
01813                                 }
01814                                 break;
01815                         case 'SQL':
01816                                 if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
01817                                         $this->obj = new dbQuerySet( $this, $attributes );
01818                                         xml_set_object( $parser, $this->obj );
01819                                 }
01820                                 break;
01821                         default:
01822                                 // print_r( array( $tag, $attributes ) );
01823                 }
01824                 
01825         }
01826         
01832         function _tag_cdata( &$parser, $cdata ) {
01833         }
01834         
01841         function _tag_close( &$parser, $tag ) {
01842                 
01843         }
01844         
01861         function ConvertSchemaString( $schema, $newVersion = NULL, $newFile = NULL ) {
01862                 
01863                 // grab current version
01864                 if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
01865                         return FALSE;
01866                 }
01867                 
01868                 if( !isset ($newVersion) ) {
01869                         $newVersion = $this->schemaVersion;
01870                 }
01871                 
01872                 if( $version == $newVersion ) {
01873                         $result = $schema;
01874                 } else {
01875                         $result = $this->TransformSchema( $schema, 'convert-' . $version . '-' . $newVersion);
01876                 }
01877                 
01878                 if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) {
01879                         fwrite( $fp, $result );
01880                         fclose( $fp );
01881                 }
01882                 
01883                 return $result;
01884         }
01885 
01886         /*
01887         // compat for pre-4.3 - jlim
01888         function _file_get_contents($path)
01889         {
01890                 if (function_exists('file_get_contents')) return file_get_contents($path);
01891                 return join('',file($path));
01892         }*/
01893         
01910         function ConvertSchemaFile( $filename, $newVersion = NULL, $newFile = NULL ) {
01911                 
01912                 // grab current version
01913                 if( !( $version = $this->SchemaFileVersion( $filename ) ) ) {
01914                         return FALSE;
01915                 }
01916                 
01917                 if( !isset ($newVersion) ) {
01918                         $newVersion = $this->schemaVersion;
01919                 }
01920                 
01921                 if( $version == $newVersion ) {
01922                         $result = _file_get_contents( $filename );
01923                         
01924                         // remove unicode BOM if present
01925                         if( substr( $result, 0, 3 ) == sprintf( '%c%c%c', 239, 187, 191 ) ) {
01926                                 $result = substr( $result, 3 );
01927                         }
01928                 } else {
01929                         $result = $this->TransformSchema( $filename, 'convert-' . $version . '-' . $newVersion, 'file' );
01930                 }
01931                 
01932                 if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) {
01933                         fwrite( $fp, $result );
01934                         fclose( $fp );
01935                 }
01936                 
01937                 return $result;
01938         }
01939         
01940         function TransformSchema( $schema, $xsl, $schematype='string' )
01941         {
01942                 // Fail if XSLT extension is not available
01943                 if( ! function_exists( 'xslt_create' ) ) {
01944                         return FALSE;
01945                 }
01946                 
01947                 $xsl_file = dirname( __FILE__ ) . '/xsl/' . $xsl . '.xsl';
01948                 
01949                 // look for xsl
01950                 if( !is_readable( $xsl_file ) ) {
01951                         return FALSE;
01952                 }
01953                 
01954                 switch( $schematype )
01955                 {
01956                         case 'file':
01957                                 if( !is_readable( $schema ) ) {
01958                                         return FALSE;
01959                                 }
01960                                 
01961                                 $schema = _file_get_contents( $schema );
01962                                 break;
01963                         case 'string':
01964                         default:
01965                                 if( !is_string( $schema ) ) {
01966                                         return FALSE;
01967                                 }
01968                 }
01969                 
01970                 $arguments = array (
01971                         '/_xml' => $schema,
01972                         '/_xsl' => _file_get_contents( $xsl_file )
01973                 );
01974                 
01975                 // create an XSLT processor
01976                 $xh = xslt_create ();
01977                 
01978                 // set error handler
01979                 xslt_set_error_handler ($xh, array (&$this, 'xslt_error_handler'));
01980                 
01981                 // process the schema
01982                 $result = xslt_process ($xh, 'arg:/_xml', 'arg:/_xsl', NULL, $arguments); 
01983                 
01984                 xslt_free ($xh);
01985                 
01986                 return $result;
01987         }
01988         
01999         function xslt_error_handler( $parser, $errno, $level, $fields ) {
02000                 if( is_array( $fields ) ) {
02001                         $msg = array(
02002                                 'Message Type' => ucfirst( $fields['msgtype'] ),
02003                                 'Message Code' => $fields['code'],
02004                                 'Message' => $fields['msg'],
02005                                 'Error Number' => $errno,
02006                                 'Level' => $level
02007                         );
02008                         
02009                         switch( $fields['URI'] ) {
02010                                 case 'arg:/_xml':
02011                                         $msg['Input'] = 'XML';
02012                                         break;
02013                                 case 'arg:/_xsl':
02014                                         $msg['Input'] = 'XSL';
02015                                         break;
02016                                 default:
02017                                         $msg['Input'] = $fields['URI'];
02018                         }
02019                         
02020                         $msg['Line'] = $fields['line'];
02021                 } else {
02022                         $msg = array(
02023                                 'Message Type' => 'Error',
02024                                 'Error Number' => $errno,
02025                                 'Level' => $level,
02026                                 'Fields' => var_export( $fields, TRUE )
02027                         );
02028                 }
02029                 
02030                 $error_details = $msg['Message Type'] . ' in XSLT Transformation' . "\n"
02031                                            . '<table>' . "\n";
02032                 
02033                 foreach( $msg as $label => $details ) {
02034                         $error_details .= '<tr><td><b>' . $label . ': </b></td><td>' . htmlentities( $details ) . '</td></tr>' . "\n";
02035                 }
02036                 
02037                 $error_details .= '</table>';
02038                 
02039                 trigger_error( $error_details, E_USER_ERROR );
02040         }
02041         
02051         function SchemaFileVersion( $filename ) {
02052                 // Open the file
02053                 if( !($fp = fopen( $filename, 'r' )) ) {
02054                         // die( 'Unable to open file' );
02055                         return FALSE;
02056                 }
02057                 
02058                 // Process the file
02059                 while( $data = fread( $fp, 4096 ) ) {
02060                         if( preg_match( $this->versionRegex, $data, $matches ) ) {
02061                                 return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION;
02062                         }
02063                 }
02064                 
02065                 return FALSE;
02066         }
02067         
02077         function SchemaStringVersion( $xmlstring ) {
02078                 if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
02079                         return FALSE;
02080                 }
02081                 
02082                 if( preg_match( $this->versionRegex, $xmlstring, $matches ) ) {
02083                         return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION;
02084                 }
02085                 
02086                 return FALSE;
02087         }
02088         
02102         function ExtractSchema( $data = FALSE, $indent = '  ', $prefix = '' , $stripprefix=false) {
02103                 $old_mode = $this->db->SetFetchMode( ADODB_FETCH_NUM );
02104                 
02105                 $schema = '<?xml version="1.0"?>' . "\n"
02106                                 . '<schema version="' . $this->schemaVersion . '">' . "\n";
02107                 
02108                 if( is_array( $tables = $this->db->MetaTables( 'TABLES' , ($prefix) ? $prefix.'%' : '') ) ) {
02109                         foreach( $tables as $table ) {
02110                                 if ($stripprefix) $table = str_replace(str_replace('\\_', '_', $pfx ), '', $table);
02111                                 $schema .= $indent . '<table name="' . htmlentities( $table ) . '">' . "\n";
02112                                 
02113                                 // grab details from database
02114                                 $rs = $this->db->Execute( 'SELECT * FROM ' . $table . ' WHERE -1' );
02115                                 $fields = $this->db->MetaColumns( $table );
02116                                 $indexes = $this->db->MetaIndexes( $table );
02117                                 
02118                                 if( is_array( $fields ) ) {
02119                                         foreach( $fields as $details ) {
02120                                                 $extra = '';
02121                                                 $content = array();
02122                                                 
02123                                                 if( isset($details->max_length) && $details->max_length > 0 ) {
02124                                                         $extra .= ' size="' . $details->max_length . '"';
02125                                                 }
02126                                                 
02127                                                 if( isset($details->primary_key) && $details->primary_key ) {
02128                                                         $content[] = '<KEY/>';
02129                                                 } elseif( isset($details->not_null) && $details->not_null ) {
02130                                                         $content[] = '<NOTNULL/>';
02131                                                 }
02132                                                 
02133                                                 if( isset($details->has_default) && $details->has_default ) {
02134                                                         $content[] = '<DEFAULT value="' . htmlentities( $details->default_value ) . '"/>';
02135                                                 }
02136                                                 
02137                                                 if( isset($details->auto_increment) && $details->auto_increment ) {
02138                                                         $content[] = '<AUTOINCREMENT/>';
02139                                                 }
02140                                                 
02141                                                 if( isset($details->unsigned) && $details->unsigned ) {
02142                                                         $content[] = '<UNSIGNED/>';
02143                                                 }
02144                                                 
02145                                                 // this stops the creation of 'R' columns,
02146                                                 // AUTOINCREMENT is used to create auto columns
02147                                                 $details->primary_key = 0;
02148                                                 $type = $rs->MetaType( $details );
02149                                                 
02150                                                 $schema .= str_repeat( $indent, 2 ) . '<field name="' . htmlentities( $details->name ) . '" type="' . $type . '"' . $extra;
02151                                                 
02152                                                 if( !empty( $content ) ) {
02153                                                         $schema .= ">\n" . str_repeat( $indent, 3 )
02154                                                                          . implode( "\n" . str_repeat( $indent, 3 ), $content ) . "\n"
02155                                                                          . str_repeat( $indent, 2 ) . '</field>' . "\n";
02156                                                 } else {
02157                                                         $schema .= "/>\n";
02158                                                 }
02159                                         }
02160                                 }
02161                                 
02162                                 if( is_array( $indexes ) ) {
02163                                         foreach( $indexes as $index => $details ) {
02164                                                 $schema .= str_repeat( $indent, 2 ) . '<index name="' . $index . '">' . "\n";
02165                                                 
02166                                                 if( $details['unique'] ) {
02167                                                         $schema .= str_repeat( $indent, 3 ) . '<UNIQUE/>' . "\n";
02168                                                 }
02169                                                 
02170                                                 foreach( $details['columns'] as $column ) {
02171                                                         $schema .= str_repeat( $indent, 3 ) . '<col>' . htmlentities( $column ) . '</col>' . "\n";
02172                                                 }
02173                                                 
02174                                                 $schema .= str_repeat( $indent, 2 ) . '</index>' . "\n";
02175                                         }
02176                                 }
02177                                 
02178                                 if( $data ) {
02179                                         $rs = $this->db->Execute( 'SELECT * FROM ' . $table );
02180                                         
02181                                         if( is_object( $rs ) && !$rs->EOF ) {
02182                                                 $schema .= str_repeat( $indent, 2 ) . "<data>\n";
02183                                                 
02184                                                 while( $row = $rs->FetchRow() ) {
02185                                                         foreach( $row as $key => $val ) {
02186                                                                 if ( $val != htmlentities( $val ) ) {
02187                                                                         $row[$key] = '<![CDATA[' . $val . ']]>';
02188                                                                 }
02189                                                         }
02190                                                         
02191                                                         $schema .= str_repeat( $indent, 3 ) . '<row><f>' . implode( '</f><f>', $row ) . "</f></row>\n";
02192                                                 }
02193                                                 
02194                                                 $schema .= str_repeat( $indent, 2 ) . "</data>\n";
02195                                         }
02196                                 }
02197                                 
02198                                 $schema .= $indent . "</table>\n";
02199                         }
02200                 }
02201                 
02202                 $this->db->SetFetchMode( $old_mode );
02203                 
02204                 $schema .= '</schema>';
02205                 return $schema;
02206         }
02207         
02218         function SetPrefix( $prefix = '', $underscore = TRUE ) {
02219                 switch( TRUE ) {
02220                         // clear prefix
02221                         case empty( $prefix ):
02222                                 logMsg( 'Cleared prefix' );
02223                                 $this->objectPrefix = '';
02224                                 return TRUE;
02225                         // prefix too long
02226                         case strlen( $prefix ) > XMLS_PREFIX_MAXLEN:
02227                         // prefix contains invalid characters
02228                         case !preg_match( '/^[a-z][a-z0-9_]+$/i', $prefix ):
02229                                 logMsg( 'Invalid prefix: ' . $prefix );
02230                                 return FALSE;
02231                 }
02232                 
02233                 if( $underscore AND substr( $prefix, -1 ) != '_' ) {
02234                         $prefix .= '_';
02235                 }
02236                 
02237                 // prefix valid
02238                 logMsg( 'Set prefix: ' . $prefix );
02239                 $this->objectPrefix = $prefix;
02240                 return TRUE;
02241         }
02242         
02251         function prefix( $name = '' ) {
02252                 // if prefix is set
02253                 if( !empty( $this->objectPrefix ) ) {
02254                         // Prepend the object prefix to the table name
02255                         // prepend after quote if used
02256                         return preg_replace( '/^(`?)(.+)$/', '$1' . $this->objectPrefix . '$2', $name );
02257                 }
02258                 
02259                 // No prefix set. Use name provided.
02260                 return $name;
02261         }
02262         
02271         function supportedPlatform( $platform = NULL ) {
02272                 if( !empty( $platform ) ) {
02273                         $regex = '/(^|\|)' . $this->db->databaseType . '(\||$)/i';
02274                 
02275                         if( preg_match( '/^- /', $platform ) ) {
02276                                 if (preg_match ( $regex, substr( $platform, 2 ) ) ) {
02277                                         logMsg( 'Platform ' . $platform . ' is NOT supported' );
02278                                         return FALSE;
02279                                 }
02280                 } else {
02281                                 if( !preg_match ( $regex, $platform ) ) {
02282                                         logMsg( 'Platform ' . $platform . ' is NOT supported' );
02283                         return FALSE;
02284                 }
02285         }
02286                 }
02287                 
02288                 logMsg( 'Platform ' . $platform . ' is supported' );
02289                 return TRUE;
02290         }
02291         
02297         function clearSQL() {
02298                 $this->sqlArray = array();
02299         }
02300         
02309         function addSQL( $sql = NULL ) {
02310                 if( is_array( $sql ) ) {
02311                         foreach( $sql as $line ) {
02312                                 $this->addSQL( $line );
02313                         }
02314                         
02315                         return TRUE;
02316                 }
02317                 
02318                 if( is_string( $sql ) ) {
02319                         $this->sqlArray[] = $sql;
02320                         
02321                         // if executeInline is enabled, and either no errors have occurred or continueOnError is enabled, execute SQL.
02322                         if( $this->ExecuteInline() && ( $this->success == 2 || $this->ContinueOnError() ) ) {
02323                                 $saved = $this->db->debug;
02324                                 $this->db->debug = $this->debug;
02325                                 $ok = $this->db->Execute( $sql );
02326                                 $this->db->debug = $saved;
02327                                 
02328                                 if( !$ok ) {
02329                                         if( $this->debug ) {
02330                                                 ADOConnection::outp( $this->db->ErrorMsg() );
02331                                         }
02332                                         
02333                                         $this->success = 1;
02334                                 }
02335                         }
02336                         
02337                         return TRUE;
02338                 }
02339                 
02340                 return FALSE;
02341         }
02342         
02351         function getSQL( $format = NULL, $sqlArray = NULL ) {
02352                 if( !is_array( $sqlArray ) ) {
02353                         $sqlArray = $this->sqlArray;
02354                 }
02355                 
02356                 if( !is_array( $sqlArray ) ) {
02357                         return FALSE;
02358                 }
02359                 
02360                 switch( strtolower( $format ) ) {
02361                         case 'string':
02362                         case 'text':
02363                                 return !empty( $sqlArray ) ? implode( ";\n\n", $sqlArray ) . ';' : '';
02364                         case'html':
02365                                 return !empty( $sqlArray ) ? nl2br( htmlentities( implode( ";\n\n", $sqlArray ) . ';' ) ) : '';
02366                 }
02367                 
02368                 return $this->sqlArray;
02369         }
02370         
02377         function Destroy() {
02378                 ini_set("magic_quotes_runtime", $this->mgq );
02379                 #set_magic_quotes_runtime( $this->mgq );
02380                 unset( $this );
02381         }
02382 }
02383 
02389 function logMsg( $msg, $title = NULL, $force = FALSE ) {
02390         if( XMLS_DEBUG or $force ) {
02391                 echo '<pre>';
02392                 
02393                 if( isset( $title ) ) {
02394                         echo '<h3>' . htmlentities( $title ) . '</h3>';
02395                 }
02396                 
02397                 if( @is_object( $this ) ) {
02398                         echo '[' . get_class( $this ) . '] ';
02399                 }
02400                 
02401                 print_r( $msg );
02402                 
02403                 echo '</pre>';
02404         }
02405 }
02406 ?>
 All Data Structures Namespaces Files Functions Variables Enumerations