Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/v3' into rewrite-fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
mattbucci committed Feb 27, 2024
2 parents b76a569 + 226ed1f commit 1b6ecce
Show file tree
Hide file tree
Showing 23 changed files with 454 additions and 78 deletions.
31 changes: 31 additions & 0 deletions .github/ISSUE_TEMPLATE/sql-rewriting-issue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
name: SQL Rewriting Issue
about: This is used for filing bugs or problems with PG4WP
title: ''
labels: ''
assignees: ''

---

WP Version:
PG4WP Version:

Error:
```
```

RAW SQL
```
```

Expected Rewritten SQL
```
```

Actual Rewritten SQL
```
```
6 changes: 6 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

Related Issues:
-

Added Tests:
-
2 changes: 1 addition & 1 deletion pg4wp/driver_pgsql_rewrite.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
function createSQLRewriter(string $sql): AbstractSQLRewriter
{
$sql = trim($sql);
if (preg_match('/^(SELECT|INSERT|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")
$type = str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($matches[1]))));
$className = $type . 'SQLRewriter';
Expand Down
63 changes: 53 additions & 10 deletions pg4wp/rewriters/AlterTableSQLRewriter.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@
class AlterTableSQLRewriter extends AbstractSQLRewriter
{
private $stringReplacements = [
' bigint(40)' => ' bigint',
' bigint(20)' => ' bigint',
' bigint(10)' => ' int',
' int(11)' => ' int',
' int(10)' => ' int',
' tinytext' => ' text',
' mediumtext' => ' text',
' longtext' => ' text',
Expand All @@ -16,16 +11,15 @@ class AlterTableSQLRewriter extends AbstractSQLRewriter
'default \'0000-00-00 00:00:00\'' => 'DEFAULT now()',
'\'0000-00-00 00:00:00\'' => 'now()',
' datetime' => ' timestamp',
' DEFAULT CHARACTER SET utf8mb4' => '',
' DEFAULT CHARACTER SET utf8' => '',

// WP 2.7.1 compatibility
' int(4)' => ' smallint',

// For WPMU (starting with WP 3.2)
' tinyint(2)' => ' smallint',
' tinyint(1)' => ' smallint',
" enum('0','1')" => ' smallint',
' COLLATE utf8mb4_unicode_520_ci' => '',
' COLLATE utf8_general_ci' => '',
' CHARACTER SET utf8' => '',
' DEFAULT CHARSET=utf8' => '',

// For flash-album-gallery plugin
' tinyint' => ' smallint'
Expand All @@ -34,11 +28,14 @@ class AlterTableSQLRewriter extends AbstractSQLRewriter
public function rewrite(): string
{
$sql = $this->original();

$sql = $this->rewrite_numeric_type($sql);

if (str_contains($sql, 'ADD INDEX') || str_contains($sql, 'ADD UNIQUE INDEX')) {
$sql = $this->rewriteAddIndex($sql);
return $sql;
}

if (str_contains($sql, 'CHANGE COLUMN')) {
$sql = $this->rewriteChangeColumn($sql);
return $sql;
Expand Down Expand Up @@ -219,4 +216,50 @@ private function rewriteDropPrimaryKey(string $sql): string

return $sql;
}

private function rewrite_numeric_type($sql){
// Numeric types in MySQL which need to be rewritten
$numeric_types = ["bigint", "int", "integer", "smallint", "mediumint", "tinyint", "double", "decimal"];
$numeric_types_imploded = implode('|', $numeric_types);

// Prepare regex pattern to match 'type(x)'
$pattern = "/(" . $numeric_types_imploded . ")\(\d+\)/";

// Execute type find & replace
$sql = preg_replace_callback($pattern, function ($matches) {
return $matches[1];
}, $sql);

// bigint
$pattern = '/bigint(\(\d+\))?([ ]*NOT NULL)?[ ]*auto_increment/i';
preg_match($pattern, $sql, $matches);
if($matches) {
$sql = preg_replace($pattern, 'bigserial', $sql);
}

// int
$pattern = '/int(\(\d+\))?([ ]*NOT NULL)?[ ]*auto_increment/i';
preg_match($pattern, $sql, $matches);
if($matches) {
$sql = preg_replace($pattern, 'serial', $sql);
}

// smallint
$pattern = '/smallint(\(\d+\))?([ ]*NOT NULL)?[ ]*auto_increment/i';
preg_match($pattern, $sql, $matches);
if($matches) {
$sql = preg_replace($pattern, 'smallserial', $sql);
}

// Handle for numeric and decimal -- being replaced with serial
$numeric_patterns = ['/numeric(\(\d+\))?([ ]*NOT NULL)?[ ]*auto_increment/i', '/decimal(\(\d+\))?([ ]*NOT NULL)?[ ]*auto_increment/i'];
foreach($numeric_patterns as $pattern) {
preg_match($pattern, $sql, $matches);
if($matches) {
$sql = preg_replace($pattern, 'serial', $sql);
}
}

return $sql;
}
}
90 changes: 48 additions & 42 deletions pg4wp/rewriters/CreateTableSQLRewriter.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,18 @@
class CreateTableSQLRewriter extends AbstractSQLRewriter
{
private $stringReplacements = [
' bigint(40)' => ' bigint',
' bigint(20)' => ' bigint',
' bigint(10)' => ' int',
' int(11)' => ' int',
' int(10)' => ' int',
' int(1)' => ' smallint',
' tinytext' => ' text',
' mediumtext' => ' text',
' longtext' => ' text',
' unsigned' => ' ',
'gmt datetime NOT NULL default \'0000-00-00 00:00:00\'' => 'gmt timestamp NOT NULL DEFAULT timezone(\'gmt\'::text, now())',
'default \'0000-00-00 00:00:00\'' => 'DEFAULT now()',
'\'0000-00-00 00:00:00\'' => 'now()',
'datetime' => 'timestamp',
' datetime' => ' timestamp',
' DEFAULT CHARACTER SET utf8mb4' => '',
' DEFAULT CHARACTER SET utf8' => '',

// WP 2.7.1 compatibility
' int(4)' => ' smallint',

// For WPMU (starting with WP 3.2)
' tinyint(2)' => ' smallint',
' tinyint(1)' => ' smallint',
" enum('0','1')" => ' smallint',
' COLLATE utf8mb4_unicode_520_ci' => '',
' COLLATE utf8_general_ci' => '',
Expand All @@ -40,7 +29,6 @@ public function rewrite(): string
{
$sql = $this->original();


$tableSQL = str_replace('CREATE TABLE IF NOT EXISTS ', 'CREATE TABLE ', $sql);
$pattern = '/CREATE TABLE [`]?(\w+)[`]?/';
preg_match($pattern, $tableSQL, $matches);
Expand All @@ -66,35 +54,7 @@ public function rewrite(): string
$sql
);

// bigint
$pattern = '/bigint(\(\d+\))?([ ]*NOT NULL)?[ ]*auto_increment/i';
preg_match($pattern, $sql, $matches);
if($matches) {
$sql = preg_replace($pattern, 'bigserial', $sql);
}

// int
$pattern = '/int(\(\d+\))?([ ]*NOT NULL)?[ ]*auto_increment/i';
preg_match($pattern, $sql, $matches);
if($matches) {
$sql = preg_replace($pattern, 'serial', $sql);
}

// smallint
$pattern = '/smallint(\(\d+\))?([ ]*NOT NULL)?[ ]*auto_increment/i';
preg_match($pattern, $sql, $matches);
if($matches) {
$sql = preg_replace($pattern, 'smallserial', $sql);
}

// Handle for numeric and decimal -- being replaced with serial
$numeric_patterns = ['/numeric(\(\d+\))?([ ]*NOT NULL)?[ ]*auto_increment/i', '/decimal(\(\d+\))?([ ]*NOT NULL)?[ ]*auto_increment/i'];
foreach($numeric_patterns as $pattern) {
preg_match($pattern, $sql, $matches);
if($matches) {
$sql = preg_replace($pattern, 'serial', $sql);
}
}
$sql = $this->rewrite_numeric_type($sql);

// Support for UNIQUE INDEX creation
$pattern = '/,\s*(UNIQUE |)KEY\s+(`[^`]+`|\w+)\s+\(((?:[^()]|\([^)]*\))*)\)/';
Expand Down Expand Up @@ -127,4 +87,50 @@ public function rewrite(): string

return $sql;
}

private function rewrite_numeric_type($sql){
// Numeric types in MySQL which need to be rewritten
$numeric_types = ["bigint", "int", "integer", "smallint", "mediumint", "tinyint", "double", "decimal"];
$numeric_types_imploded = implode('|', $numeric_types);

// Prepare regex pattern to match 'type(x)'
$pattern = "/(" . $numeric_types_imploded . ")\(\d+\)/";

// Execute type find & replace
$sql = preg_replace_callback($pattern, function ($matches) {
return $matches[1];
}, $sql);

// bigint
$pattern = '/bigint(\(\d+\))?([ ]*NOT NULL)?[ ]*auto_increment/i';
preg_match($pattern, $sql, $matches);
if($matches) {
$sql = preg_replace($pattern, 'bigserial', $sql);
}

// int
$pattern = '/int(\(\d+\))?([ ]*NOT NULL)?[ ]*auto_increment/i';
preg_match($pattern, $sql, $matches);
if($matches) {
$sql = preg_replace($pattern, 'serial', $sql);
}

// smallint
$pattern = '/smallint(\(\d+\))?([ ]*NOT NULL)?[ ]*auto_increment/i';
preg_match($pattern, $sql, $matches);
if($matches) {
$sql = preg_replace($pattern, 'smallserial', $sql);
}

// Handle for numeric and decimal -- being replaced with serial
$numeric_patterns = ['/numeric(\(\d+\))?([ ]*NOT NULL)?[ ]*auto_increment/i', '/decimal(\(\d+\))?([ ]*NOT NULL)?[ ]*auto_increment/i'];
foreach($numeric_patterns as $pattern) {
preg_match($pattern, $sql, $matches);
if($matches) {
$sql = preg_replace($pattern, 'serial', $sql);
}
}

return $sql;
}
}
5 changes: 3 additions & 2 deletions pg4wp/rewriters/DescribeSQLRewriter.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ protected function extractTableName($sql)
* Generates a PostgreSQL-compatible SQL query to mimic MySQL's "DESCRIBE".
*
* @param string $tableName The table name
* @param string $schema The schema name
* @return string The generated SQL query
*/
public function generatePostgresDescribeTable($tableName)
public function generatePostgresDescribeTable($tableName, $schema = "public")
{
$sql = <<<SQL
SELECT
Expand Down Expand Up @@ -70,7 +71,7 @@ public function generatePostgresDescribeTable($tableName)
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
WHERE c.relkind = 'r'::char
AND n.nspname = 'public'
AND n.nspname = '$schema'
AND c.relname = '$tableName'
AND f.attnum > 0 ORDER BY number
SQL;
Expand Down
9 changes: 0 additions & 9 deletions pg4wp/rewriters/InsertSQLRewriter.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,6 @@ public function rewrite(): string

$sql = $this->original();

$sql = str_replace('(0,', "('0',", $sql);
$sql = str_replace('(1,', "('1',", $sql);

// Fix inserts into wp_categories
if(false !== strpos($sql, 'INSERT INTO ' . $wpdb->categories)) {
$sql = str_replace('"cat_ID",', '', $sql);
$sql = str_replace("VALUES ('0',", "VALUES(", $sql);
}

// Those are used when we need to set the date to now() in gmt time
$sql = str_replace("'0000-00-00 00:00:00'", 'now() AT TIME ZONE \'gmt\'', $sql);

Expand Down
Loading

0 comments on commit 1b6ecce

Please sign in to comment.