Skip to content

Commit 200e80b

Browse files
committed
Change how column meta is pulled so it uses a get_cols_meta function
It previously used a cached values array throughout the code which relied on get_table_charset being run to prime the cache. If the pre_get_table_charset was set then the cache would never be primed and cache checks would throw errors. Fixes #38921 and #59836
1 parent 2a8e315 commit 200e80b

File tree

1 file changed

+124
-51
lines changed

1 file changed

+124
-51
lines changed

src/wp-includes/class-wpdb.php

Lines changed: 124 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -3227,21 +3227,15 @@ protected function get_table_charset( $table ) {
32273227
}
32283228

32293229
$charsets = array();
3230-
$columns = array();
3230+
$columns = $this->get_cols_meta( $table );
32313231

3232-
$table_parts = explode( '.', $table );
3233-
$table = '`' . implode( '`.`', $table_parts ) . '`';
3234-
$results = $this->get_results( "SHOW FULL COLUMNS FROM $table" );
3235-
if ( ! $results ) {
3236-
return new WP_Error( 'wpdb_get_table_charset_failure', __( 'Could not retrieve table charset.' ) );
3232+
if ( is_wp_error( $columns ) ) {
3233+
return $columns;
32373234
}
3238-
3239-
foreach ( $results as $column ) {
3240-
$columns[ strtolower( $column->Field ) ] = $column;
3235+
if ( empty( $columns ) ) {
3236+
$columns = array();
32413237
}
32423238

3243-
$this->col_meta[ $tablekey ] = $columns;
3244-
32453239
foreach ( $columns as $column ) {
32463240
if ( ! empty( $column->Collation ) ) {
32473241
list( $charset ) = explode( '_', $column->Collation );
@@ -3291,6 +3285,109 @@ protected function get_table_charset( $table ) {
32913285
return $charset;
32923286
}
32933287

3288+
/**
3289+
* Retrieves the column metadata for the given column.
3290+
*
3291+
* @since 6.9.1
3292+
*
3293+
* @param string $table Table name.
3294+
* @return object|false|WP_Error Column meta set as an object. False if the column was
3295+
* not found. WP_Error object if there was an error.
3296+
*/
3297+
public function get_cols_meta( $table ) {
3298+
$tablekey = strtolower( $table );
3299+
3300+
/**
3301+
* Filters the columns meta value before the DB is checked.
3302+
*
3303+
* Passing a non-null value to the filter will short-circuit
3304+
* checking the DB for the meta, returning that value instead.
3305+
*
3306+
* @since 6.9.1
3307+
*
3308+
* @param array<object>|null|false|WP_Error $meta The meta to use. Default null.
3309+
* @param string $table The name of the table being checked.
3310+
*/
3311+
$col_meta = apply_filters( 'pre_get_cols_meta', null, $table );
3312+
if ( null !== $col_meta ) {
3313+
return $col_meta;
3314+
}
3315+
3316+
// Skip this entirely if this isn't a MySQL database.
3317+
if ( empty( $this->is_mysql ) ) {
3318+
return false;
3319+
}
3320+
3321+
// If no column information, fetch it from the database.
3322+
if ( empty( $this->col_meta[ $tablekey ] ) ) {
3323+
$columns = array();
3324+
3325+
$table_parts = explode( '.', $table );
3326+
$table = '`' . implode( '`.`', $table_parts ) . '`';
3327+
$results = $this->get_results( "SHOW FULL COLUMNS FROM $table" );
3328+
if ( ! $results ) {
3329+
return new WP_Error( 'wpdb_get_cols_meta_failure', __( 'Could not retrieve column metadata.' ) );
3330+
}
3331+
3332+
foreach ( $results as $column ) {
3333+
$columns[ strtolower( $column->Field ) ] = $column;
3334+
}
3335+
3336+
$this->col_meta[ $tablekey ] = $columns;
3337+
}
3338+
3339+
// If this table data doesn't exist, return false.
3340+
if ( empty( $this->col_meta[ $tablekey ] ) ) {
3341+
return false;
3342+
}
3343+
3344+
return $this->col_meta[ $tablekey ];
3345+
}
3346+
3347+
/**
3348+
* Retrieves the column metadata for the given column.
3349+
*
3350+
* @since 6.9.1
3351+
*
3352+
* @param string $table Table name.
3353+
* @param string $column Column name.
3354+
* @return object|false|WP_Error Column character set as a string. False if the column has
3355+
* no character set. WP_Error object if there was an error.
3356+
*/
3357+
public function get_col_meta( $table, $column ) {
3358+
$columnkey = strtolower( $column );
3359+
3360+
/**
3361+
* Filters the column meta value before the DB is checked.
3362+
*
3363+
* Passing a non-null value to the filter will short-circuit
3364+
* checking the DB for the meta, returning that value instead.
3365+
*
3366+
* @since 6.9.1
3367+
*
3368+
* @param object|null|false|WP_Error $meta The meta to use. Default null.
3369+
* @param string $table The name of the table being checked.
3370+
* @param string $column The name of the column being checked.
3371+
*/
3372+
$col_meta = apply_filters( 'pre_get_col_meta', null, $table, $column );
3373+
if ( null !== $col_meta ) {
3374+
return $col_meta;
3375+
}
3376+
3377+
$cols_meta = $this->get_cols_meta( $table );
3378+
3379+
if ( is_wp_error( $cols_meta ) ) {
3380+
return $cols_meta;
3381+
}
3382+
3383+
// If this column doesn't exist, return false.
3384+
if ( empty( $cols_meta[ $columnkey ] ) ) {
3385+
return false;
3386+
}
3387+
3388+
return $cols_meta[ $columnkey ];
3389+
}
3390+
32943391
/**
32953392
* Retrieves the character set for the given column.
32963393
*
@@ -3302,9 +3399,6 @@ protected function get_table_charset( $table ) {
33023399
* no character set. WP_Error object if there was an error.
33033400
*/
33043401
public function get_col_charset( $table, $column ) {
3305-
$tablekey = strtolower( $table );
3306-
$columnkey = strtolower( $column );
3307-
33083402
/**
33093403
* Filters the column charset value before the DB is checked.
33103404
*
@@ -3322,35 +3416,23 @@ public function get_col_charset( $table, $column ) {
33223416
return $charset;
33233417
}
33243418

3325-
// Skip this entirely if this isn't a MySQL database.
3326-
if ( empty( $this->is_mysql ) ) {
3327-
return false;
3328-
}
3419+
$col_meta = $this->get_col_meta( $table, $column );
33293420

3330-
if ( empty( $this->table_charset[ $tablekey ] ) ) {
3331-
// This primes column information for us.
3332-
$table_charset = $this->get_table_charset( $table );
3333-
if ( is_wp_error( $table_charset ) ) {
3334-
return $table_charset;
3335-
}
3336-
}
3337-
3338-
// If still no column information, return the table charset.
3339-
if ( empty( $this->col_meta[ $tablekey ] ) ) {
3340-
return $this->table_charset[ $tablekey ];
3421+
if ( is_wp_error( $col_meta ) ) {
3422+
return $col_meta;
33413423
}
33423424

33433425
// If this column doesn't exist, return the table charset.
3344-
if ( empty( $this->col_meta[ $tablekey ][ $columnkey ] ) ) {
3345-
return $this->table_charset[ $tablekey ];
3426+
if ( empty( $col_meta ) ) {
3427+
return $this->get_table_charset( $table );
33463428
}
33473429

33483430
// Return false when it's not a string column.
3349-
if ( empty( $this->col_meta[ $tablekey ][ $columnkey ]->Collation ) ) {
3431+
if ( empty( $col_meta->Collation ) ) {
33503432
return false;
33513433
}
33523434

3353-
list( $charset ) = explode( '_', $this->col_meta[ $tablekey ][ $columnkey ]->Collation );
3435+
list( $charset ) = explode( '_', $col_meta->Collation );
33543436
return $charset;
33553437
}
33563438

@@ -3372,27 +3454,17 @@ public function get_col_charset( $table, $column ) {
33723454
* }
33733455
*/
33743456
public function get_col_length( $table, $column ) {
3375-
$tablekey = strtolower( $table );
3376-
$columnkey = strtolower( $column );
3377-
3378-
// Skip this entirely if this isn't a MySQL database.
3379-
if ( empty( $this->is_mysql ) ) {
3380-
return false;
3381-
}
3457+
$col_meta = $this->get_col_meta( $table, $column );
33823458

3383-
if ( empty( $this->col_meta[ $tablekey ] ) ) {
3384-
// This primes column information for us.
3385-
$table_charset = $this->get_table_charset( $table );
3386-
if ( is_wp_error( $table_charset ) ) {
3387-
return $table_charset;
3388-
}
3459+
if ( is_wp_error( $col_meta ) ) {
3460+
return $col_meta;
33893461
}
33903462

3391-
if ( empty( $this->col_meta[ $tablekey ][ $columnkey ] ) ) {
3463+
if ( empty( $col_meta ) ) {
33923464
return false;
33933465
}
33943466

3395-
$typeinfo = explode( '(', $this->col_meta[ $tablekey ][ $columnkey ]->Type );
3467+
$typeinfo = explode( '(', $col_meta->Type );
33963468

33973469
$type = strtolower( $typeinfo[0] );
33983470
if ( ! empty( $typeinfo[1] ) ) {
@@ -3510,8 +3582,9 @@ protected function check_safe_collation( $query ) {
35103582
return true;
35113583
}
35123584

3513-
$table = strtolower( $table );
3514-
if ( empty( $this->col_meta[ $table ] ) ) {
3585+
$cols_meta = $this->get_cols_meta( $table );
3586+
3587+
if ( is_wp_error( $cols_meta ) || empty( $cols_meta ) ) {
35153588
return false;
35163589
}
35173590

@@ -3525,7 +3598,7 @@ protected function check_safe_collation( $query ) {
35253598
'utf8mb4_general_ci',
35263599
);
35273600

3528-
foreach ( $this->col_meta[ $table ] as $col ) {
3601+
foreach ( $cols_meta as $col ) {
35293602
if ( empty( $col->Collation ) ) {
35303603
continue;
35313604
}

0 commit comments

Comments
 (0)