|
Moodle
2.2.1
http://www.collinsharper.com
|
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 ?>