[wp-trac] [WordPress Trac] #37660: RegEx in wpdb::get_table_from_query( $q ) in wp-db.php returns table_alias='a' rather than table_name=wp_999_options
WordPress Trac
noreply at wordpress.org
Mon Aug 15 00:23:25 UTC 2016
#37660: RegEx in wpdb::get_table_from_query( $q ) in wp-db.php returns
table_alias='a' rather than table_name=wp_999_options
--------------------------+-----------------------------
Reporter: webp | Owner:
Type: defect (bug) | Status: new
Priority: normal | Milestone: Awaiting Review
Component: Database | Version: trunk
Severity: normal | Keywords:
Focuses: |
--------------------------+-----------------------------
== WordPress database error ==
{{{
WordPress database error Table 'wp_xyz.wp_999_options' doesn't exist for
query
DELETE a, b FROM wp_999_options a, wp_999_options b
WHERE a.option_name LIKE '\\_transient\\_%'
AND a.option_name NOT LIKE '\\_transient\\_timeout\\_%'
AND b.option_name = CONCAT( '_transient_timeout_', SUBSTRING(
a.option_name, 12 ) )
AND b.option_value < 1470982769 made by populate_options
}}}
== Problem ==
function populate_options() in `wp-admin/includes/schema.php` fires the
SQL query above that goes through hyperdb and then $wpdb in wp-db.php.
class hyperdb extends wpdb in wp-includes/wp-db.php:
{{{
# hyperdb/db.php
class hyperdb extends wpdb {
function get_table_from_query( $q ) {
if( method_exists( get_parent_class( $this ), 'get_table_from_query' )
) {
// WPDB has added support for get_table_from_query, which should
take precedence
return parent::get_table_from_query( $q );
}
# wp-includes/wp-db.php
protected function get_table_from_query( $query ) {
// Quickly match most common queries.
if ( preg_match( '/^\s*(?:'
. 'SELECT.*?\s+FROM'
.
'|INSERT(?:\s+LOW_PRIORITY|\s+DELAYED|\s+HIGH_PRIORITY)?(?:\s+IGNORE)?(?:\s+INTO)?'
. '|REPLACE(?:\s+LOW_PRIORITY|\s+DELAYED)?(?:\s+INTO)?'
. '|UPDATE(?:\s+LOW_PRIORITY)?(?:\s+IGNORE)?'
. '|DELETE(?:\s+LOW_PRIORITY|\s+QUICK|\s+IGNORE)*(?:\s+FROM)?'
. ')\s+((?:[0-9a-zA-Z$_.`-]|[\xC2-\xDF][\x80-\xBF])+)/is', $query,
$maybe ) ) {
return str_replace( '`', '', $maybe[1] );
}
}}}
== Cause ==
$query = `DELETE a, b FROM wp_999_options a, wp_999_options b ....`
RegEx in wpdb::get_table_from_query( $q ) in wp-db.php below returns
table_alias='a' rather than table_name=wp_999_options from $query above:
` . '|DELETE(?:\s+LOW_PRIORITY|\s+QUICK|\s+IGNORE)*(?:\s+FROM)?'`
WordPress database error occurs when Table wp_999_options is not found in
default database wp_xyz. So my hyperdb config directs unknown db name 'a'
to default db wp_xyz, rather than my hyperdb mapped database wp_abc.
== Suggested Fix ==
Change RegEx to:
` . '|DELETE(?:.+FROM)?'`
Is it a good fix? Or am I missing other scenarios?
Core Developers should also watch out if other similar SQL might failed in
wpdb::get_table_from_query( $q ):
SQL `COMMAND table_alias FROM table, table_alias`
If fix confirmed, someone should ask hyperdb to fix as similar RegEx is
used. Not too many WordPress developers use hyperdb so I'm too lazy to
submit a ticket for hyperdb myself.
But wpdb is used everywhere and it should be perfect, or strive to be
perfect. Otherwise, developers like me will be scratching my head for
hours when minor wpdb errors arise. Even though this bug is minor, but
unknown problems might cause database corruption months down the line, at
least for me and my massive number of replicated databases and servers.
--
Ticket URL: <https://core.trac.wordpress.org/ticket/37660>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list