[ Index ]

PHP Cross Reference of BackPress

title

Body

[close]

/includes/ -> class.bp-sql-schema-parser.php (source)

   1  <?php
   2  /**
   3   * Parses SQL schema statements for comparison to real table structures
   4   *
   5   * @package BackPress
   6   **/
   7  class BP_SQL_Schema_Parser
   8  {
   9      /**
  10       * Builds a column definition as used in CREATE TABLE statements from
  11       * an array such as those returned by DESCRIBE `foo` statements
  12       */
  13  	function get_column_definition( $column_data )
  14      {
  15          if ( !is_array( $column_data ) ) {
  16              return $column_data;
  17          }
  18  
  19          $null = '';
  20          if ( $column_data['Null'] != 'YES' ) {
  21              $null = 'NOT NULL';
  22          }
  23  
  24          $default = '';
  25  
  26          // Defaults aren't allowed at all on certain column types
  27          if ( !in_array(
  28              strtolower( $column_data['Type'] ),
  29              array( 'tinytext', 'text', 'mediumtext', 'longtext', 'blob', 'mediumblob', 'longblob' )
  30          ) ) {
  31              if ( $column_data['Null'] == 'YES' && $column_data['Default'] === null ) {
  32                  $default = 'default NULL';
  33              } elseif ( preg_match( '@^\d+$@', $column_data['Default'] ) ) {
  34                  $default = 'default ' . $column_data['Default'];
  35              } elseif ( is_string( $column_data['Default'] ) || is_float( $column_data['Default'] ) ) {
  36                  $default = 'default \'' . $column_data['Default'] . '\'';
  37              }
  38          }
  39  
  40          $column_definition = '`' . $column_data['Field'] . '` ' . $column_data['Type'] . ' ' . $null . ' ' . $column_data['Extra'] . ' ' . $default;
  41          return preg_replace( '@\s+@', ' ', trim( $column_definition ) );
  42      }
  43  
  44      /**
  45       * Builds an index definition as used in CREATE TABLE statements from
  46       * an array similar to those returned by SHOW INDEX FROM `foo` statements
  47       */
  48  	function get_index_definition( $index_data )
  49      {
  50          if ( !is_array( $index_data ) ) {
  51              return $index_data;
  52          }
  53  
  54          if ( !count( $index_data ) ) {
  55              return $index_data;
  56          }
  57  
  58          $_name = '`' . $index_data[0]['Key_name'] . '`';
  59  
  60          if ( $index_data[0]['Index_type'] == 'BTREE' && $index_data[0]['Key_name'] == 'PRIMARY' ) {
  61              $_type = 'PRIMARY KEY';
  62              $_name = '';
  63          } elseif ( $index_data[0]['Index_type'] == 'BTREE' && !$index_data[0]['Non_unique'] ) {
  64              $_type = 'UNIQUE KEY';
  65          } elseif ( $index_data[0]['Index_type'] == 'FULLTEXT' ) {
  66              $_type = 'FULLTEXT KEY';
  67          } else {
  68              $_type = 'KEY';
  69          }
  70  
  71          $_columns = array();
  72          foreach ( $index_data as $_index ) {
  73              if ( $_index['Sub_part'] ) {
  74                  $_columns[] = '`' . $_index['Column_name'] . '`(' . $_index['Sub_part'] . ')';
  75              } else {
  76                  $_columns[] = '`' . $_index['Column_name'] . '`';
  77              }
  78          }
  79          $_columns = join( ', ', $_columns );
  80  
  81          $index_definition = $_type . ' ' . $_name . ' (' . $_columns . ')';
  82          return preg_replace( '@\s+@', ' ', $index_definition );
  83      }
  84  
  85      /**
  86       * Returns a table structure from a raw sql query of the form "CREATE TABLE foo" etc.
  87       * The resulting array contains the original query, the columns as would be returned by DESCRIBE `foo`
  88       * and the indices as would be returned by SHOW INDEX FROM `foo` on a real table
  89       */
  90  	function describe_table( $query )
  91      {
  92          // Retrieve the table structure from the query
  93          if ( !preg_match( '@^CREATE\s+TABLE(\s+IF\s+NOT\s+EXISTS)?\s+`?([^\s|`]+)`?\s+\((.*)\)\s*([^\)|;]*)\s*;?@ims', $query, $_matches ) ) {
  94              return $query;
  95          }
  96  
  97          $_if_not_exists = $_matches[1];
  98  
  99          // Tidy up the table name
 100          $_table_name = trim( $_matches[2] );
 101  
 102          // Tidy up the table columns/indices
 103          $_columns_indices = trim( $_matches[3], " \t\n\r\0\x0B," );
 104          // Split by commas not followed by a closing parenthesis ")", using fancy lookaheads
 105          $_columns_indices = preg_split( '@,(?!(?:[^\(]+\)))$@ms', $_columns_indices );
 106          $_columns_indices = array_map( 'trim', $_columns_indices );
 107  
 108          // Tidy the table attributes
 109          $_attributes = preg_replace( '@\s+@', ' ', trim( $_matches[4] ) );
 110          unset( $_matches );
 111  
 112          // Initialise some temporary arrays
 113          $_columns = array();
 114          $_indices = array();
 115  
 116          // Loop over the columns/indices
 117          foreach ( $_columns_indices as $_column_index ) {
 118              if ( preg_match( '@^(PRIMARY\s+KEY|UNIQUE\s+(?:KEY|INDEX)|FULLTEXT\s+(?:KEY|INDEX)|KEY|INDEX)\s+(?:`?(\w+)`?\s+)*\((.+?)\)$@im', $_column_index, $_matches ) ) {
 119                  // It's an index
 120  
 121                  // Tidy the type
 122                  $_index_type = strtoupper( preg_replace( '@\s+@', ' ', trim( $_matches[1] ) ) );
 123                  $_index_type = str_replace( 'INDEX', 'KEY', $_index_type );
 124                  // Set the index name
 125                  $_index_name = ( 'PRIMARY KEY' == $_matches[1] ) ? 'PRIMARY' : $_matches[2];
 126                  // Split into columns
 127                  $_index_columns = array_map( 'trim', explode( ',', $_matches[3] ) );
 128  
 129                  foreach ( $_index_columns as $_index_columns_index => $_index_column ) {
 130                      preg_match( '@`?(\w+)`?(?:\s*\(\s*(\d+)\s*\))?@i', $_index_column, $_matches_column );
 131  
 132                      $_indices[$_index_name][] = array(
 133                          'Table'        => $_table_name,
 134                          'Non_unique'   => ( 'UNIQUE KEY' == $_index_type || 'PRIMARY' == $_index_name ) ? '0' : '1',
 135                          'Key_name'     => $_index_name,
 136                          'Seq_in_index' => (string) ( $_index_columns_index + 1 ),
 137                          'Column_name'  => $_matches_column[1],
 138                          'Sub_part'     => ( isset( $_matches_column[2] ) && $_matches_column[2] ) ? $_matches_column[2] : null,
 139                          'Index_type'   => ( 'FULLTEXT KEY' == $_index_type ) ? 'FULLTEXT' : 'BTREE'
 140                      );
 141                  }
 142                  unset( $_index_type, $_index_name, $_index_columns, $_index_columns_index, $_index_column, $_matches_column );
 143  
 144              } elseif ( preg_match( "@^`?(\w+)`?\s+(?:(\w+)(?:\s*\(\s*(\d+)\s*\))?(?:\s+(unsigned)){0,1})(?:\s+(NOT\s+NULL))?(?:\s+(auto_increment))?(?:\s+(default)\s+(?:(NULL|'[^']*'|\d+)))?@im", $_column_index, $_matches ) ) {
 145                  // It's a column
 146  
 147                  // Tidy the NOT NULL
 148                  $_matches[5] = isset( $_matches[5] ) ? strtoupper( preg_replace( '@\s+@', ' ', trim( $_matches[5] ) ) ) : '';
 149  
 150                  $_columns[$_matches[1]] = array(
 151                      'Field'   => $_matches[1],
 152                      'Type'    => ( isset( $_matches[3] ) && is_numeric( $_matches[3] ) ) ? $_matches[2] . '(' . $_matches[3] . ')' . ( ( isset( $_matches[4] ) && strtolower( $_matches[4] ) == 'unsigned' ) ? ' unsigned' : '' ) : $_matches[2],
 153                      'Null'    => ( 'NOT NULL' == strtoupper( $_matches[5] ) ) ? 'NO' : 'YES',
 154                      'Default' => ( isset( $_matches[7] ) && 'default' == strtolower( $_matches[7] ) && 'NULL' !== strtoupper( $_matches[8] ) ) ? trim( $_matches[8], "'" ) : null,
 155                      'Extra'   => ( isset( $_matches[6] ) && 'auto_increment' == strtolower( $_matches[6] ) ) ? 'auto_increment' : ''
 156                  );
 157              }
 158          }
 159          unset( $_matches, $_columns_indices, $_column_index );
 160  
 161          // Tidy up the original query
 162          $_tidy_query = 'CREATE TABLE';
 163          if ( $_if_not_exists ) {
 164              $_tidy_query .= ' IF NOT EXISTS';
 165          }
 166          $_tidy_query .= ' `' . $_table_name . '` (' . "\n";
 167          foreach ( $_columns as $_column ) {
 168              $_tidy_query .= "\t" . BP_SQL_Schema_Parser::get_column_definition( $_column ) . ",\n";
 169          }
 170          unset( $_column );
 171          foreach ( $_indices as $_index ) {
 172              $_tidy_query .= "\t" . BP_SQL_Schema_Parser::get_index_definition( $_index ) . ",\n";
 173          }
 174          $_tidy_query = substr( $_tidy_query, 0, -2 ) . "\n" . ') ' . $_attributes . ';';
 175  
 176          // Add to the query array using the table name as the index
 177          $description = array(
 178              'query_original' => $query,
 179              'query_tidy' => $_tidy_query,
 180              'columns' => $_columns,
 181              'indices' => $_indices
 182          );
 183          unset( $_table_name, $_columns, $_indices, $_tidy_query );
 184  
 185          return $description;
 186      }
 187  
 188      /**
 189       * Helper function to flatten arrays
 190       */
 191  	function _flatten_array( $array, $cut_branch = 0, $keep_child_array_keys = true )
 192      {
 193          if ( !is_array( $array ) ) {
 194              return $array;
 195          }
 196  
 197          if ( empty( $array ) ) {
 198              return null;
 199          }
 200  
 201          $temp = array();
 202          foreach ( $array as $k => $v ) {
 203              if ( $cut_branch && $k == $cut_branch )
 204                  continue;
 205              if ( is_array( $v ) ) {
 206                  if ( $keep_child_array_keys ) {
 207                      $temp[$k] = true;
 208                  }
 209                  $temp += BP_SQL_Schema_Parser::_flatten_array( $v, $cut_branch, $keep_child_array_keys );
 210              } else {
 211                  $temp[$k] = $v;
 212              }
 213          }
 214          return $temp;
 215      }
 216  
 217      /**
 218       * Splits grouped SQL statements into queries within a highly structured array
 219       * Only supports CREATE TABLE, INSERT and UPDATE
 220       */
 221  	function parse( $sql )
 222      {
 223          // Only accept strings or arrays
 224          if ( is_string( $sql ) ) {
 225              // Just pop strings into an array to start with
 226              $queries = array( $sql );
 227          } elseif ( is_array( $sql ) ) {
 228              // Flatten the array
 229              $queries = BP_SQL_Schema_Parser::_flatten_array( $sql, 0, false );
 230              // Remove empty nodes
 231              $queries = array_filter( $queries );
 232          } else {
 233              return false;
 234          }
 235  
 236          // Clean up the queries
 237          $_clean_queries = array();
 238          foreach ( $queries as $_query ) {
 239              // Trim space and semi-colons
 240              $_query = trim( $_query, "; \t\n\r\0\x0B" );
 241              // If it exists and isn't a number
 242              if ( $_query && !is_numeric( $_query ) ) {
 243                  // Is it more than one query?
 244                  if ( strpos( ';', $_query ) !== false ) {
 245                      // Explode by semi-colon
 246                      foreach ( explode( ';', $_query ) as $_part ) {
 247                          $_part = trim( $_part );
 248                          if ( $_part && !is_numeric( $_part ) ) {
 249                              // Pull out any commented code
 250                              // Can't properly deal with /*!4321 FOO `bar` */ version specific inclusion, just includes it regardless of version
 251                              $_part = preg_replace( '@/\*![0-9]*([^\*]*)\*/@', '$1', $_part );
 252                              $_part = preg_replace( '@/\*[^\*]*\*/@', '', $_part );
 253                              $_part = preg_replace( '@[\-\-|#].*$@m', '', $_part );
 254                              $_clean_queries[] = trim( $_part ) . ';';
 255                          }
 256                      }
 257                      unset( $_part );
 258                  } else {
 259                      $_clean_queries[] = $_query . ';';
 260                  }
 261              }
 262          }
 263          unset( $_query );
 264          if ( !count( $_clean_queries ) ) {
 265              return false;
 266          }
 267          $queries = $_clean_queries;
 268          unset( $_clean_queries );
 269  
 270          $_queries = array();
 271          foreach ( $queries as $_query ) {
 272              // Only process table creation, inserts and updates, capture the table/database name while we are at it
 273              if ( !preg_match( '@^(CREATE\s+TABLE(?:\s+IF\s+NOT\s+EXISTS)?|INSERT\s+INTO|UPDATE)\s+`?([^\s|`]+)`?@im', $_query, $_matches ) ) {
 274                  continue;
 275              }
 276  
 277              // Tidy up the type so we can switch it
 278              $_type = strtoupper( preg_replace( '@\s+@', ' ', trim( $_matches[1] ) ) );
 279              $_table_name = trim( $_matches[2] );
 280              unset( $_matches );
 281  
 282              switch ( $_type ) {
 283                  case 'CREATE TABLE':
 284                  case 'CREATE TABLE IF NOT EXISTS':
 285                      $_description = BP_SQL_Schema_Parser::describe_table( $_query );
 286                      if ( is_array( $_description ) ) {
 287                          $_queries['tables'][$_table_name] = $_description;
 288                      }
 289                      break;
 290  
 291                  case 'INSERT INTO':
 292                      // Just add the query as is for now
 293                      $_queries['insert'][$_table_name][] = $_query;
 294                      break;
 295  
 296                  case 'UPDATE':
 297                      // Just add the query as is for now
 298                      $_queries['update'][$_table_name][] = $_query;
 299                      break;
 300              }
 301              unset( $_type, $_table_name );
 302          }
 303          unset( $_query );
 304  
 305          if ( !count( $_queries ) ) {
 306              return false;
 307          }
 308          return $_queries;
 309      }
 310  
 311      /**
 312       * Evaluates the difference between a given set of SQL queries and real database structure
 313       */
 314  	function delta( $db_object, $queries, $ignore = false, $execute = true )
 315      {
 316          if ( !$db_object || !is_object( $db_object ) || !( is_a( $db_object, 'BPDB' ) || is_a( $db_object, 'BPDB_Multi' ) || is_a( $db_object, 'BPDB_Hyper' ) ) ) {
 317              return __( 'Passed variable is not a BackPress database object.' );
 318          }
 319  
 320          if ( !$_queries = BP_SQL_Schema_Parser::parse( $queries ) ) {
 321              return __( 'No schema available.' );
 322          }
 323  
 324          // Set up default elements to ignore
 325          $ignore_defaults = array(
 326              'tables'  => array(), // Just a list of tablenames, including prefix. Does not affect INSERT and UPDATE queries.
 327              'columns' => array(), // Arrays of column names, keyed with the table names, including prefix.
 328              'indices' => array()  // Arrays of index names, keyed with the table names, including prefix.
 329          );
 330  
 331          // Add the elements to ignore that were passed to the function
 332          if ( !$ignore || !is_array( $ignore ) ) {
 333              $ignore = $ignore_defaults;
 334          } else {
 335              if ( isset( $ignore['tables'] ) && is_array( $ignore['tables'] ) ) {
 336                  $ignore['tables'] = array_merge( $ignore_defaults['tables'], $ignore['tables'] );
 337              }
 338              if ( isset( $ignore['columns'] ) && is_array( $ignore['columns'] ) ) {
 339                  $ignore['columns'] = array_merge( $ignore_defaults['columns'], $ignore['columns'] );
 340              }
 341              if ( isset( $ignore['indices'] ) && is_array( $ignore['indices'] ) ) {
 342                  $ignore['indices'] = array_merge( $ignore_defaults['indices'], $ignore['indices'] );
 343              }
 344          }
 345  
 346          // Build an array of $db_object registered tables and their database identifiers
 347          $_tables = $db_object->tables;
 348          $db_object_tables = array();
 349          foreach ( $_tables as $_table_id => $_table_name ) {
 350              if ( is_array( $_table_name ) && isset( $db_object->db_servers['dbh_' . $_table_name[0]] ) ) {
 351                  $db_object_tables[$db_object->$_table_id] = 'dbh_' . $_table_name[0];
 352              } else {
 353                  $db_object_tables[$db_object->$_table_id] = 'dbh_global';
 354              }
 355          }
 356          unset( $_tables, $_table_id, $_table_name );
 357  
 358          $alterations = array();
 359  
 360          // Loop through table queries
 361          if ( isset( $_queries['tables'] ) ) {
 362              foreach ( $_queries['tables'] as $_new_table_name => $_new_table_data ) {
 363                  if ( in_array( $_new_table_name, $ignore['tables'] ) ) {
 364                      continue;
 365                  }
 366  
 367                  // See if the table is custom and registered in $db_object under a custom database
 368                  if (
 369                      isset( $db_object_tables[$_new_table_name] ) &&
 370                      $db_object_tables[$_new_table_name] != 'dbh_global' &&
 371                      isset( $db_object->db_servers[$db_object_tables[$_new_table_name]]['ds'] )
 372                  ) {
 373                      // Force the database connection
 374                      $_dbhname = $db_object->db_servers[$db_object_tables[$_new_table_name]]['ds'];
 375                      $db_object->_force_dbhname = $_dbhname;
 376                  } else {
 377                      $_dbhname = 'dbh_global';
 378                  }
 379  
 380                  // Fetch the existing table column structure from the database
 381                  $db_object->suppress_errors();
 382                  if ( !$_existing_table_columns = $db_object->get_results( 'DESCRIBE `' . $_new_table_name . '`;', ARRAY_A ) ) {
 383                      $db_object->suppress_errors( false );
 384                      // The table doesn't exist, add it and then continue to the next table
 385                      $alterations[$_dbhname][$_new_table_name][] = array(
 386                          'action' => 'create_table',
 387                          'message' => __( 'Creating table' ),
 388                          'query' => $_new_table_data['query_tidy']
 389                      );
 390                      continue;
 391                  }
 392                  $db_object->suppress_errors( false );
 393  
 394                  // Add an index to the existing columns array
 395                  $__existing_table_columns = array();
 396                  foreach ( $_existing_table_columns as $_existing_table_column ) {
 397                      // Remove 'Key' from returned column structure
 398                      unset( $_existing_table_column['Key'] );
 399                      $__existing_table_columns[$_existing_table_column['Field']] = $_existing_table_column;
 400                  }
 401                  $_existing_table_columns = $__existing_table_columns;
 402                  unset( $__existing_table_columns );
 403  
 404                  // Loop over the columns in this table and look for differences
 405                  foreach ( $_new_table_data['columns'] as $_new_column_name => $_new_column_data ) {
 406                      if ( isset( $ignore['columns'][$_new_table_name] ) && in_array( $_new_column_name, $ignore['columns'][$_new_table_name] ) ) {
 407                          continue;
 408                      }
 409  
 410                      if ( !in_array( $_new_column_data, $_existing_table_columns ) ) {
 411                          // There is a difference
 412                          if ( !isset( $_existing_table_columns[$_new_column_name] ) ) {
 413                              // The column doesn't exist, so add it
 414                              $alterations[$_dbhname][$_new_table_name][] = array(
 415                                  'action' => 'add_column',
 416                                  'message' => sprintf( __( 'Adding column: %s' ), $_new_column_name ),
 417                                  'column' => $_new_column_name,
 418                                  'query' => 'ALTER TABLE `' . $_new_table_name . '` ADD COLUMN ' . BP_SQL_Schema_Parser::get_column_definition( $_new_column_data ) . ';'
 419                              );
 420                              continue;
 421                          }
 422  
 423                          // Adjust defaults on columns that allow defaults
 424                          if (
 425                              ! is_null( $_new_column_data['Default'] ) && // Possibly should use DROP DEFAULT here
 426                              $_new_column_data['Default'] !== $_existing_table_columns[$_new_column_name]['Default'] &&
 427                              !in_array(
 428                                  strtolower( $_new_column_data['Type'] ),
 429                                  array( 'tinytext', 'text', 'mediumtext', 'longtext', 'blob', 'mediumblob', 'longblob' )
 430                              )
 431                          ) {
 432                              // Change the default value for the column
 433                              $alterations[$_dbhname][$_new_table_name][] = array(
 434                                  'action' => 'set_default',
 435                                  'message' => sprintf( __( 'Setting default on column: %s' ), $_new_column_name ),
 436                                  'column' => $_new_column_name,
 437                                  'query' => 'ALTER TABLE `' . $_new_table_name . '` ALTER COLUMN `' . $_new_column_name . '` SET DEFAULT \'' . $_new_column_data['Default'] . '\';'
 438                              );
 439                              // Don't continue, overwrite this if the next conditional is met
 440                          }
 441  
 442                          // TODO Improve handling of scenarios like http://dev.mysql.com/doc/refman/5.0/en/silent-column-changes.html
 443                          // The db picks different column data types from the schema and we can't make it change it's mind ;)
 444                          // e.g. varchar(32) and char(32)
 445                          if (
 446                              $_new_column_data['Type'] !== $_existing_table_columns[$_new_column_name]['Type'] ||
 447                              ( 'YES' === $_new_column_data['Null'] xor 'YES' === $_existing_table_columns[$_new_column_name]['Null'] ) ||
 448                              $_new_column_data['Extra'] !== $_existing_table_columns[$_new_column_name]['Extra']
 449                          ) {
 450                              // Change the structure for the column
 451                              $alterations[$_dbhname][$_new_table_name][] = array(
 452                                  'action' => 'change_column',
 453                                  'message' => sprintf( __( 'Changing column: %s' ), $_new_column_name ),
 454                                  'column' => $_new_column_name,
 455                                  'query' => 'ALTER TABLE `' . $_new_table_name . '` CHANGE COLUMN `' . $_new_column_name . '` ' . BP_SQL_Schema_Parser::get_column_definition( $_new_column_data ) . ';'
 456                              );
 457                          }
 458                      }
 459                  }
 460                  unset( $_existing_table_columns, $_new_column_name, $_new_column_data );
 461  
 462                  // Fetch the table index structure from the database
 463                  if ( !$_existing_table_indices = $db_object->get_results( 'SHOW INDEX FROM `' . $_new_table_name . '`;', ARRAY_A ) ) {
 464                      continue;
 465                  }
 466  
 467                  // Add an index to the existing columns array and organise by index name
 468                  $__existing_table_indices = array();
 469                  foreach ( $_existing_table_indices as $_existing_table_index ) {
 470                      // Remove unused parts from returned index structure
 471                      unset(
 472                          $_existing_table_index['Collation'],
 473                          $_existing_table_index['Cardinality'],
 474                          $_existing_table_index['Packed'],
 475                          $_existing_table_index['Null'],
 476                          $_existing_table_index['Comment'],
 477                          $_existing_table_index['Index_comment']
 478                      );
 479                      $__existing_table_indices[$_existing_table_index['Key_name']][] = $_existing_table_index;
 480                  }
 481                  $_existing_table_indices = $__existing_table_indices;
 482                  unset( $__existing_table_indices );
 483  
 484                  // Loop over the indices in this table and look for differences
 485                  foreach ( $_new_table_data['indices'] as $_new_index_name => $_new_index_data ) {
 486                      if ( isset( $ignore['indices'][$_new_table_name] ) && in_array( $_new_index_name, $ignore['indices'][$_new_table_name] ) ) {
 487                          continue;
 488                      }
 489  
 490                      if ( !in_array( $_new_index_data, $_existing_table_indices ) ) {
 491                          // There is a difference
 492                          if ( !isset( $_existing_table_indices[$_new_index_name] ) ) {
 493                              // The index doesn't exist, so add it
 494                              $alterations[$_dbhname][$_new_table_name][] = array(
 495                                  'action' => 'add_index',
 496                                  'message' => sprintf( __( 'Adding index: %s' ), $_new_index_name ),
 497                                  'index' => $_new_index_name,
 498                                  'query' => 'ALTER TABLE `' . $_new_table_name . '` ADD ' . BP_SQL_Schema_Parser::get_index_definition( $_new_index_data ) . ';'
 499                              );
 500                              continue;
 501                          }
 502  
 503                          if ( $_new_index_data !== $_existing_table_indices[$_new_index_name] ) {
 504                              // The index is incorrect, so drop it and add the new one
 505                              if ( $_new_index_name == 'PRIMARY' ) {
 506                                  $_drop_index_name = 'PRIMARY KEY';
 507                              } else {
 508                                  $_drop_index_name = 'INDEX `' . $_new_index_name . '`';
 509                              }
 510                              $alterations[$_dbhname][$_new_table_name][] = array(
 511                                  'action' => 'drop_index',
 512                                  'message' => sprintf( __( 'Dropping index: %s' ), $_new_index_name ),
 513                                  'index' => $_new_index_name,
 514                                  'query' => 'ALTER TABLE `' . $_new_table_name . '` DROP ' . $_drop_index_name . ';'
 515                              );
 516                              unset( $_drop_index_name );
 517                              $alterations[$_dbhname][$_new_table_name][] = array(
 518                                  'action' => 'add_index',
 519                                  'message' => sprintf( __( 'Adding index: %s' ), $_new_index_name ),
 520                                  'index' => $_new_index_name,
 521                                  'query' => 'ALTER TABLE `' . $_new_table_name . '` ADD ' . BP_SQL_Schema_Parser::get_index_definition( $_new_index_data ) . ';'
 522                              );
 523                          }
 524                      }
 525                  }
 526                  unset( $_new_index_name, $_new_index_data );
 527  
 528                  // Go back to the default database connection
 529                  $db_object->_force_dbhname = false;
 530              }
 531              unset( $_new_table_name, $_new_table_data, $_dbhname );
 532          }
 533  
 534          // Now deal with the sundry INSERT and UPDATE statements (if any)
 535          if ( isset( $_queries['insert'] ) && is_array( $_queries['insert'] ) && count( $_queries['insert'] ) ) {
 536              foreach ( $_queries['insert'] as $_table_name => $_inserts ) {
 537                  foreach ( $_inserts as $_insert ) {
 538                      $alterations['dbh_global'][$_table_name][] = array(
 539                          'action' => 'insert',
 540                          'message' => __( 'Inserting data' ),
 541                          'query' => $_insert
 542                      );
 543                  }
 544                  unset( $_insert );
 545              }
 546              unset( $_table_name, $_inserts );
 547          }
 548          if ( isset( $_queries['update'] ) && is_array( $_queries['update'] ) && count( $_queries['update'] ) ) {
 549              foreach ( $_queries['update'] as $_table_name => $_updates ) {
 550                  foreach ( $_updates as $_update ) {
 551                      $alterations['dbh_global'][$_table_name][] = array(
 552                          'action' => 'update',
 553                          'message' => __( 'Updating data' ),
 554                          'query' => $_update
 555                      );
 556                  }
 557                  unset( $_update );
 558              }
 559              unset( $_table_name, $_updates );
 560          }
 561  
 562          // Initialise an array to hold the output messages
 563          $messages = array();
 564          $errors = array();
 565  
 566          foreach ( $alterations as $_dbhname => $_tables ) {
 567              // Force the database connection (this was already checked to be valid in the previous loop)
 568              $db_object->_force_dbhname = $_dbhname;
 569  
 570              // Note the database in the return messages
 571              $messages[] = '>>> ' . sprintf( __( 'Modifying database: %s (%s)' ), $db_object->db_servers[$_dbhname]['name'], $db_object->db_servers[$_dbhname]['host'] );
 572  
 573              foreach ( $_tables as $_table_name => $_alterations ) {
 574                  // Note the table in the return messages
 575                  $messages[] = '>>>>>> ' . sprintf( __( 'Table: %s' ), $_table_name );
 576  
 577                  foreach ( $_alterations as $_alteration ) {
 578                      // If there is no query, then skip
 579                      if ( !$_alteration['query'] ) {
 580                          continue;
 581                      }
 582  
 583                      // Note the action in the return messages
 584                      $messages[] = '>>>>>>>>> ' . $_alteration['message'];
 585  
 586                      if ( !$execute ) {
 587                          $messages[] = '>>>>>>>>>>>> ' . __( 'Skipped' );
 588                          continue;
 589                      }
 590  
 591                      // Run the query
 592                      $_result = $db_object->query( $_alteration['query'] );
 593                      $_result_error = $db_object->get_error();
 594  
 595                      if ( $_result_error ) {
 596                          // There was an error
 597                          $_result =& $_result_error;
 598                          unset( $_result_error );
 599                          $messages[] = '>>>>>>>>>>>> ' . __( 'SQL ERROR! See the error log for more detail' );
 600                          $errors[] = __( 'SQL ERROR!' );
 601                          $errors[] = '>>> ' . sprintf( __( 'Database: %s (%s)' ), $db_object->db_servers[$_dbhname]['name'], $db_object->db_servers[$_dbhname]['host'] );
 602                          $errors[] = '>>>>>> ' . $_result->error_data['db_query']['query'];
 603                          $errors[] = '>>>>>> ' . $_result->error_data['db_query']['error'];
 604                      } else {
 605                          $messages[] = '>>>>>>>>>>>> ' . __( 'Done' );
 606                      }
 607                      unset( $_result );
 608                  }
 609                  unset( $_alteration );
 610              }
 611              unset( $_table_name, $_alterations );
 612          }
 613          unset( $_dbhname, $_tables );
 614  
 615          // Reset the database connection
 616          $db_object->_force_dbhname = false;
 617  
 618          return array( 'messages' => $messages, 'errors' => $errors );
 619      }
 620  } // END class BP_SQL_Schema_Parser


Generated: Thu Dec 26 01:01:01 2024 Cross-referenced by PHPXref 0.7.1