WordPress.org

Make WordPress Core

Ticket #40357: upgrade.php.diff

File upgrade.php.diff, 9.2 KB (added by stuporglue, 3 years ago)

The patch that implements the changes outlined in this ticket.

  • wp-admin/includes/upgrade.php

     
    22282228                // Separate field lines into an array.
    22292229                $flds = explode("\n", $qryline);
    22302230
     2231                // An array to hold the index parts, for later comparison to existing indexes.
     2232                $new_indices_ary = array();
     2233
    22312234                // For every field line specified in the query.
    22322235                foreach ( $flds as $fld ) {
    22332236                        $fld = trim( $fld, " \t\n\r\0\x0B," ); // Default trim characters, plus ','.
     
    22912294                                        // Escape the index name with backticks. An index for a primary key has no name.
    22922295                                        $index_name = ( 'PRIMARY KEY' === $index_type ) ? '' : '`' . strtolower( $index_matches['index_name'] ) . '`';
    22932296
     2297                                        // Save the index name for use in the $new_indices_ary array.
     2298                                        $new_indices_ary_key = empty( $index_name ) ? 'primary' : strtolower( $index_matches['index_name'] );
     2299
    22942300                                        // Parse the columns. Multiple columns are separated by a comma.
    22952301                                        $index_columns = $index_columns_without_subparts = array_map( 'trim', explode( ',', $index_matches['index_columns'] ) );
    22962302
     
    23292335                                                if ( isset( $index_column_matches['sub_part'] ) ) {
    23302336                                                        $index_column .= '(' . $index_column_matches['sub_part'] . ')';
    23312337                                                }
     2338
     2339                                                $new_indices_ary[$new_indices_ary_key]['columns'][] = array('fieldname' => $index_column_matches['column_name'], 'subpart' => ( empty( $index_column_matches['sub_part']) ? null : $index_column_matches['sub_part'] ));
    23322340                                        }
    23332341
    23342342                                        // Build the normalized index definition and add it to the list of indices.
    23352343                                        $indices[] = "{$index_type} {$index_name} (" . implode( ',', $index_columns ) . ")";
    23362344                                        $indices_without_subparts[] = "{$index_type} {$index_name} (" . implode( ',', $index_columns_without_subparts ) . ")";
    23372345
     2346                                        // Set the unique and index_type values.
     2347                                        $new_indices_ary[$new_indices_ary_key]['unique'] = (false !== strpos($index_type,'PRIMARY') || false !== strpos($index_type,'UNIQUE') ) ? true : false;
     2348
     2349                                        // SHOW INDEX FROM returns BTREE, FULLTEXT, HASH or RTREE. SPATIAL and FULLTEXT should be specified, and MySQL uses BTREE unless HASH is specified explicitly.
     2350                                        if ( 'FULLTEXT KEY' === $index_type ) {
     2351                                                $new_indices_ary[$new_indices_ary_key]['index_type'] = 'FULLTEXT';
     2352                                        } else if ( 'SPATIAL' === $index_type ) {
     2353                                                $new_indices_ary[$new_indices_ary_key]['index_type'] = 'RTREE';
     2354                                        } else if ( false !== stripos( $fld, 'USING HASH' ) ) {
     2355                                                $new_indices_ary[$new_indices_ary_key]['index_type'] = 'HASH';
     2356                                        } else {
     2357                                                $new_indices_ary[$new_indices_ary_key]['index_type'] = 'BTREE';
     2358                                        }
     2359
    23382360                                        // Destroy no longer needed variables.
    23392361                                        unset( $index_column, $index_column_matches, $index_matches, $index_type, $index_name, $index_columns, $index_columns_without_subparts );
    23402362
     
    23602382                                $fieldtype = $matches[1];
    23612383                                $fieldtype_lowercased = strtolower( $fieldtype );
    23622384
     2385                                /**
     2386                                 * If the new AUTO_INCREMENT settings don't match the existing ones, change the column.
     2387                                 *
     2388                                 * Note: We need to do this first, because adding AI to an existing column will break things
     2389                                 */
     2390                                $old_has_ai = 'auto_increment' === $tablefield->Extra;
     2391                                $new_has_ai = !(false === strpos( strtolower( $cfields[ $tablefield_field_lowercased ] ), 'auto_increment' ));
     2392                                if ( $old_has_ai !== $new_has_ai  ) {
     2393                                        $iqueries[] = "ALTER TABLE {$table} CHANGE COLUMN `{$tablefield->Field}` " . $cfields[ $tablefield_field_lowercased ];
     2394                                        $use_or_not = 'auto_increment' === $tablefield->Extra  ? 'not use' : 'use';
     2395                                        $for_update[] = "Set column {$tablefield->Field} to {$use_or_not} AUTO_INCREMENT";
     2396                                } 
     2397                               
    23632398                                // Is actual field type different from the field type in query?
    2364                                 if ($tablefield->Type != $fieldtype) {
     2399                                else if ($tablefield->Type != $fieldtype) {
    23652400                                        $do_change = true;
    23662401                                        if ( in_array( $fieldtype_lowercased, $text_fields ) && in_array( $tablefield_type_lowercased, $text_fields ) ) {
    23672402                                                if ( array_search( $fieldtype_lowercased, $text_fields ) < array_search( $tablefield_type_lowercased, $text_fields ) ) {
     
    23762411                                        }
    23772412
    23782413                                        if ( $do_change ) {
     2414                                                /**
     2415                                                 * If we're changing an AI column, we're going to drop and re-add the AI designation
     2416                                                 * so that if we're also modifying an index, we won't trip up that process.
     2417                                                 */
     2418                                                if ( $new_has_ai ) {
     2419                                                        // Remove the AI designation for now.
     2420                                                        $cfields[ $tablefield_field_lowercased ] = str_ireplace( 'auto_increment', '', $cfields[ $tablefield_field_lowercased ] );
     2421
     2422                                                        // Then re-add it afterwards.
     2423                                                        $iqueries[] = "ALTER TABLE {$table} MODIFY COLUMN {$cfields[ $tablefield_field_lowercased ]} AUTO_INCREMENT";
     2424                                                        $for_update[] = "Set column {$tablefield->Field} to use AUTO_INCREMENT";
     2425                                                }
     2426
    23792427                                                // Add a query to change the column type.
    23802428                                                $cqueries[] = "ALTER TABLE {$table} CHANGE COLUMN `{$tablefield->Field}` " . $cfields[ $tablefield_field_lowercased ];
    23812429                                                $for_update[$table.'.'.$tablefield->Field] = "Changed type of {$table}.{$tablefield->Field} from {$tablefield->Type} to {$fieldtype}";
     
    24012449
    24022450                // For every remaining field specified for the table.
    24032451                foreach ($cfields as $fieldname => $fielddef) {
     2452                        /**
     2453                         * A statement tries to add an AUTO_INCREMENT column to an existing table
     2454                         * will trigger an error because an AUTO_INCREMENT column must be indexed.
     2455                         *
     2456                         * We're going to split out the AUTO_INCREMENT piece to handle after we've
     2457                         * added the index.
     2458                         */
     2459                        if ( false !== strpos( strtolower( $fielddef ), 'auto_increment' ) ) {
     2460                                $fielddef = str_ireplace( 'auto_increment', '', $fielddef );
     2461
     2462                                /**
     2463                                 * We want to add the AUTO_INCREMENT properties to the column after all other columns,
     2464                                 * have
     2465                                 * so we add it to $iqueries which run after $cqueries.
     2466                                 */
     2467                                $iqueries[] = "ALTER TABLE {$table} MODIFY COLUMN {$fielddef} AUTO_INCREMENT";
     2468                                $for_update[] = "Set column {$fieldname} to use AUTO_INCREMENT";
     2469                        }
     2470
    24042471                        // Push a query line into $cqueries that adds the field to that table.
    24052472                        $cqueries[] = "ALTER TABLE {$table} ADD COLUMN $fielddef";
    24062473                        $for_update[$table.'.'.$fieldname] = 'Added column '.$table.'.'.$fieldname;
     
    24262493                        // For each actual index in the index array.
    24272494                        foreach ($index_ary as $index_name => $index_data) {
    24282495
     2496                                // Since we don't drop existing indexes unless we have to, we don't need to do this unless we are significantly changing an index.
     2497                                if ( isset( $new_indices_ary[ $index_name ] ) ) {
     2498                                        $drop_this_index = false;
     2499                                        if ( $index_data['unique'] !== $new_indices_ary[$index_name]['unique'] ) { // An index which wasn't unique but now is, or vice-versa.
     2500                                                $drop_this_index = true;
     2501                                        } else if ( null !== $new_indices_ary[$index_name]['index_type'] && $new_indices_ary[$index_name]['index_type'] !== $index_data['index_type'] ) { // If the user has specified an index method ( FULLTEXT, HASH or BTREE).
     2502                                                $drop_this_index = true;
     2503                                        } else if ( count( $new_indices_ary[$index_name]['columns'] ) !== count( $index_data['columns'] ) ) { // If there are a different number of columns in the index.
     2504                                                $drop_this_index = true;
     2505                                        } else {
     2506                                                foreach( $new_indices_ary[$index_name]['columns'] as $column_idx => $new_column ) {
     2507                                                        if ( !array_key_exists($column_idx,$index_data['columns']) || $index_data['columns'][$column_idx]['fieldname'] !== $new_column['fieldname'] ) { // If the columns are in a different order.
     2508                                                                $drop_this_index = true;
     2509                                                                break;
     2510                                                        }
     2511                                                }
     2512                                        }
     2513
     2514                                        if ( $drop_this_index ) {
     2515                                                if ( 'primary' === $index_name ){
     2516
     2517                                                        // If the column is an AUTO_INCREMENT column, we need to drop the AUTO_INCREMENT designation before dropping the index.
     2518                                                        foreach( $tablefields as $tablefield ) {
     2519                                                                if ( 'auto_increment' === $tablefield->Extra && 'PRI' === $tablefield->Key ) {
     2520
     2521                                                                        $column_already_altered = false;
     2522                                                                        foreach( $cqueries as $k => $maybe_alter ) {
     2523                                                                                // However, if we are already altering the column, we won't touch it here, since we would undo any type or sub-type changes.
     2524                                                                                if ( false !== strpos( $maybe_alter, 'ALTER TABLE' ) &&  ( false !== strpos( $maybe_alter, '`' . $tablefield->Field . '`' ) || false !== strpos( $maybe_alter, ' ' . $tablefield->Field . ' ' ) ) ) {
     2525                                                                                        $column_already_altered = true;
     2526                                                                                }
     2527                                                                        }
     2528
     2529                                                                        if ( !$column_already_altered ) {
     2530                                                                                $cqueries[] = "ALTER TABLE {$table} MODIFY {$tablefield->Field} {$tablefield->Type} NOT NULL;";
     2531                                                                                $for_update[] = 'Removed auto_increment from ' . $tablefield->Field . ' in order to remove primary key';
     2532                                                                        }
     2533                                                                }
     2534                                                        }
     2535
     2536                                                        $cqueries[] = "ALTER TABLE {$table} DROP PRIMARY KEY";
     2537                                                        $for_update[] = "Dropped old primary key from {$table}";
     2538                                                } else {
     2539                                                        $cqueries[] = "DROP INDEX {$index_name} ON {$table}";
     2540                                                        $for_update[] = 'Removed index ' . $index_name . ' from ' . $table;
     2541                                                }
     2542
     2543                                                unset( $index_ary[$index_name] );
     2544                                                continue;
     2545                                        }
     2546                                }
     2547
    24292548                                // Build a create string to compare to the query.
    24302549                                $index_string = '';
    24312550                                if ($index_name == 'primary') {