Merge pull request #100 from PostgreSQL-For-Wordpress/site-health

add rewrite logic for SHOW TABLE STATUS and a catch for calls to information_schema
This commit is contained in:
Matthew Bucci
2024-02-26 12:31:34 -08:00
committed by GitHub
6 changed files with 98 additions and 6 deletions

View File

@ -12,7 +12,7 @@ spl_autoload_register(function ($className) {
function createSQLRewriter(string $sql): AbstractSQLRewriter function createSQLRewriter(string $sql): AbstractSQLRewriter
{ {
$sql = trim($sql); $sql = trim($sql);
if (preg_match('/^(SELECT|INSERT|REPLACE INTO|UPDATE|DELETE|DESCRIBE|ALTER TABLE|CREATE TABLE|DROP TABLE|SHOW INDEX|SHOW VARIABLES|SHOW TABLES|OPTIMIZE TABLE|SET NAMES|SHOW FULL COLUMNS)\b/i', $sql, $matches)) { if (preg_match('/^(SELECT|INSERT|REPLACE INTO|UPDATE|DELETE|DESCRIBE|ALTER TABLE|CREATE TABLE|DROP TABLE|SHOW INDEX|SHOW VARIABLES|SHOW TABLES|OPTIMIZE TABLE|SET NAMES|SHOW FULL COLUMNS|SHOW TABLE STATUS)\b/i', $sql, $matches)) {
// Convert to a format suitable for class names (e.g., "SHOW TABLES" becomes "ShowTables") // Convert to a format suitable for class names (e.g., "SHOW TABLES" becomes "ShowTables")
$type = str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($matches[1])))); $type = str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($matches[1]))));
$className = $type . 'SQLRewriter'; $className = $type . 'SQLRewriter';

View File

@ -28,9 +28,10 @@ class DescribeSQLRewriter extends AbstractSQLRewriter
* Generates a PostgreSQL-compatible SQL query to mimic MySQL's "DESCRIBE". * Generates a PostgreSQL-compatible SQL query to mimic MySQL's "DESCRIBE".
* *
* @param string $tableName The table name * @param string $tableName The table name
* @param string $schema The schema name
* @return string The generated SQL query * @return string The generated SQL query
*/ */
public function generatePostgresDescribeTable($tableName) public function generatePostgresDescribeTable($tableName, $schema = "public")
{ {
$sql = <<<SQL $sql = <<<SQL
SELECT SELECT
@ -70,7 +71,7 @@ class DescribeSQLRewriter extends AbstractSQLRewriter
LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey) LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey)
LEFT JOIN pg_class AS g ON p.confrelid = g.oid LEFT JOIN pg_class AS g ON p.confrelid = g.oid
WHERE c.relkind = 'r'::char WHERE c.relkind = 'r'::char
AND n.nspname = 'public' AND n.nspname = '$schema'
AND c.relname = '$tableName' AND c.relname = '$tableName'
AND f.attnum > 0 ORDER BY number AND f.attnum > 0 ORDER BY number
SQL; SQL;

View File

@ -34,6 +34,16 @@ class SelectSQLRewriter extends AbstractSQLRewriter
$sql = preg_replace('/SELECT\s+.*?\s+FROM\s+/is', 'SELECT COUNT(*) FROM ', $sql, 1); $sql = preg_replace('/SELECT\s+.*?\s+FROM\s+/is', 'SELECT COUNT(*) FROM ', $sql, 1);
} }
if(false !== strpos($sql, 'information_schema')) {
// WP Site Health rewrites
if (false !== strpos($sql, "SELECT TABLE_NAME AS 'table', TABLE_ROWS AS 'rows', SUM(data_length + index_length)")) {
$sql = $this->postgresTableSizeRewrite();
return $sql;
}
throw new Exception("Unsupported call to information_schema, this probably won't work correctly and needs to be specifically handled, open a github issue with the SQL");
}
$sql = $this->ensureOrderByInSelect($sql); $sql = $this->ensureOrderByInSelect($sql);
// Convert CONVERT to CAST // Convert CONVERT to CAST
@ -350,4 +360,29 @@ class SelectSQLRewriter extends AbstractSQLRewriter
return $sql; return $sql;
} }
// This method is specifically to handle should_suggest_persistent_object_cache in wp site health
protected function postgresTableSizeRewrite($schema = 'public')
{
$sql = <<<SQL
SELECT
C.relname AS "table",
S.n_live_tup AS "rows",
pg_total_relation_size(C.oid) AS "bytes"
FROM
pg_class C
LEFT JOIN
pg_namespace N ON (N.oid = C.relnamespace)
INNER JOIN
pg_stat_user_tables S ON (S.relid = C.oid)
WHERE
N.nspname = '$schema' AND
C.relname IN ('wp_comments','wp_options','wp_posts','wp_terms','wp_users')
GROUP BY
C.relname, pg_total_relation_size(C.oid), S.n_live_tup;
SQL;
return $sql;
}
} }

View File

@ -28,9 +28,10 @@ class ShowFullColumnsSQLRewriter extends AbstractSQLRewriter
* Generates a PostgreSQL-compatible SQL query to mimic MySQL's "SHOW FULL COLUMNS". * Generates a PostgreSQL-compatible SQL query to mimic MySQL's "SHOW FULL COLUMNS".
* *
* @param string $tableName The table name * @param string $tableName The table name
* @param string $schema The schema name
* @return string The generated SQL query * @return string The generated SQL query
*/ */
public function generatePostgresShowColumns($tableName) public function generatePostgresShowColumns($tableName, $schema = "public")
{ {
$sql = <<<SQL $sql = <<<SQL
SELECT SELECT
@ -62,7 +63,7 @@ class ShowFullColumnsSQLRewriter extends AbstractSQLRewriter
FROM pg_catalog.pg_class c FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname = '$tableName' WHERE c.relname = '$tableName'
AND n.nspname = 'public' AND n.nspname = '$schema'
) )
ORDER BY ORDER BY
a.attnum; a.attnum;

View File

@ -0,0 +1,54 @@
<?php
class ShowTableStatusSQLRewriter extends AbstractSQLRewriter
{
public function rewrite(): string
{
$sql = $this->original();
return $this->generatePostgresShowTableStatus();
}
/**
* Generates a PostgreSQL-compatible SQL query to mimic MySQL's "SHOW TABLE STATUS".
*
* @return string The generated SQL query
*/
public function generatePostgresShowTableStatus($schema = "public")
{
$sql = <<<SQL
SELECT
'Postgres' AS Engine,
cls.relname AS TableName,
NULL AS Version,
NULL AS Row_format,
cls.reltuples AS Rows,
NULL AS Avg_row_length,
pg_size_pretty(pg_relation_size(cls.oid)) AS Data_length,
NULL AS Max_data_length,
pg_size_pretty(pg_indexes_size(cls.oid)) AS Index_length,
NULL AS Data_free,
NULL AS Auto_increment,
NULL AS Create_time,
NULL AS Update_time,
NULL AS Check_time,
'UTF8' AS Table_collation,
NULL AS Checksum,
NULL AS Create_options,
obj_description(cls.oid) AS Comment
FROM
pg_class cls
JOIN
pg_namespace nsp ON cls.relnamespace = nsp.oid
WHERE
cls.relkind = 'r'
AND nsp.nspname NOT LIKE 'pg_%'
AND nsp.nspname != 'information_schema'
AND nsp.nspname = '$schema'
ORDER BY
cls.relname ASC;
SQL;
return $sql;
}
}

View File

@ -4,6 +4,7 @@ class ShowTablesSQLRewriter extends AbstractSQLRewriter
{ {
public function rewrite(): string public function rewrite(): string
{ {
return 'SELECT tablename FROM pg_tables WHERE schemaname = \'public\';'; $schema = "public";
return 'SELECT tablename FROM pg_tables WHERE schemaname = \'$schema\';';
} }
} }