From c60d8f90b19675970d65d228d42434bf57b73905 Mon Sep 17 00:00:00 2001 From: Matthew Bucci Date: Tue, 7 Nov 2023 15:26:03 -0800 Subject: [PATCH 1/3] Migrate install rewriting to new rewriters --- pg4wp/core.php | 35 +-- pg4wp/db.php | 34 ++- pg4wp/driver_pgsql_install.php | 297 ------------------- pg4wp/driver_pgsql_rewrite.php | 21 +- pg4wp/rewriters/AlterTableSQLRewriter.php | 126 ++++++++ pg4wp/rewriters/CreateTableSQLRewriter.php | 80 +++++ pg4wp/rewriters/DescribeSQLRewriter.php | 78 +++++ pg4wp/rewriters/DropTableSQLRewriter.php | 17 ++ pg4wp/rewriters/ShowIndexSQLRewriter.php | 60 ++++ pg4wp/rewriters/ShowVariablesSQLRewriter.php | 41 +++ wp-includes/version.php | 47 +++ 11 files changed, 487 insertions(+), 349 deletions(-) delete mode 100644 pg4wp/driver_pgsql_install.php create mode 100644 pg4wp/rewriters/AlterTableSQLRewriter.php create mode 100644 pg4wp/rewriters/CreateTableSQLRewriter.php create mode 100644 pg4wp/rewriters/DescribeSQLRewriter.php create mode 100644 pg4wp/rewriters/DropTableSQLRewriter.php create mode 100644 pg4wp/rewriters/ShowIndexSQLRewriter.php create mode 100644 pg4wp/rewriters/ShowVariablesSQLRewriter.php create mode 100644 wp-includes/version.php diff --git a/pg4wp/core.php b/pg4wp/core.php index fa45e3b..e77cb36 100644 --- a/pg4wp/core.php +++ b/pg4wp/core.php @@ -10,6 +10,7 @@ */ // This is required by class-wpdb so we must load it first +require_once ABSPATH . '/wp-includes/version.php'; require_once ABSPATH . '/wp-includes/cache.php'; require_once ABSPATH . '/wp-includes/l10n.php'; @@ -20,39 +21,31 @@ if (!function_exists('wpsql_is_resource')) { } } -// Logs are put in the pg4wp directory -define( 'PG4WP_LOG', PG4WP_ROOT.'/logs/'); -// Check if the logs directory is needed and exists or create it if possible -if( (PG4WP_DEBUG || PG4WP_LOG_ERRORS) && - !file_exists( PG4WP_LOG) && - is_writable(dirname( PG4WP_LOG))) - mkdir( PG4WP_LOG); - // Load the driver defined in 'db.php' -require_once( PG4WP_ROOT.'/driver_'.DB_DRIVER.'.php'); +require_once(PG4WP_ROOT . '/driver_' . DB_DRIVER . '.php'); // This loads up the wpdb class applying appropriate changes to it $replaces = array( - 'define( ' => '// define( ', - 'class wpdb' => 'class wpdb2', - 'new wpdb' => 'new wpdb2', - 'mysql_' => 'wpsql_', - 'is_resource' => 'wpsql_is_resource', - ' '', - '?>' => '', + 'define( ' => '// define( ', + 'class wpdb' => 'class wpdb2', + 'new wpdb' => 'new wpdb2', + 'mysql_' => 'wpsql_', + 'is_resource' => 'wpsql_is_resource', + ' '', + '?>' => '', ); // Ensure class uses the replaced mysql_ functions rather than mysqli_ if (!defined('WP_USE_EXT_MYSQL')) { - define('WP_USE_EXT_MYSQL', true); + define('WP_USE_EXT_MYSQL', true); } if (WP_USE_EXT_MYSQL != true) { - throw new \Exception("PG4SQL CANNOT BE ENABLED WITH MYSQLI, REMOVE ANY WP_USE_EXT_MYSQL configuration"); + throw new \Exception("PG4SQL CANNOT BE ENABLED WITH MYSQLI, REMOVE ANY WP_USE_EXT_MYSQL configuration"); } eval(str_replace(array_keys($replaces), array_values($replaces), file_get_contents(ABSPATH . '/wp-includes/class-wpdb.php'))); // Create wpdb object if not already done -if (! isset($wpdb) && defined('DB_USER')) { - $wpdb = new wpdb2( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST ); -} \ No newline at end of file +if (!isset($wpdb) && defined('DB_USER')) { + $wpdb = new wpdb2(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST); +} diff --git a/pg4wp/db.php b/pg4wp/db.php index 75fd5cf..f6aa982 100644 --- a/pg4wp/db.php +++ b/pg4wp/db.php @@ -1,11 +1,11 @@ 'bigint', - 'bigint(10)' => 'int', - 'int(11)' => 'int', - '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', - '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 utf8_general_ci' => '', - - // For flash-album-gallery plugin - 'tinyint' => 'smallint', - ); - - function pg4wp_installing( $sql, &$logto) - { - global $wpdb; - - // Emulate SHOW commands - if( 0 === strpos( $sql, 'SHOW') || 0 === strpos( $sql, 'show')) - { - // SHOW VARIABLES LIKE emulation for sql_mode - // Used by nextgen-gallery plugin - if( 0 === strpos( $sql, "SHOW VARIABLES LIKE 'sql_mode'")) - { - // Act like MySQL default configuration, where sql_mode is "" - $sql = 'SELECT \'sql_mode\' AS "Variable_name", \'\' AS "Value";'; - } - // SHOW COLUMNS emulation - elseif( preg_match('/SHOW\s+(FULL\s+)?COLUMNS\s+(?:FROM\s+|IN\s+)`?(\w+)`?(?:\s+LIKE\s+(.+)|\s+WHERE\s+(.+))?/i', $sql, $matches)) - { - $logto = 'SHOWCOLUMN'; - $full = $matches[1]; - $table = $matches[2]; - $like = isset($matches[3]) ? $matches[3] : FALSE; - $where = isset($matches[4]) ? $matches[4] : FALSE; -// Wrap as sub-query to emulate WHERE behavior -$sql = ($where ? 'SELECT * FROM (' : ''). -'SELECT column_name as "Field", - data_type as "Type",'.($full ? ' - NULL as "Collation",' : '').' - is_nullable as "Null", - \'\' as "Key", - column_default as "Default", - \'\' as "Extra"'.($full ? ', - \'select,insert,update,references\' as "Privileges", - \'\' as "Comment"' : '').' -FROM information_schema.columns -WHERE table_name = \''.$table.'\''.($like ? ' - AND column_name LIKE '.$like : '').($where ? ') AS columns -WHERE '.$where : '').';'; - } - // SHOW INDEX emulation - elseif( 0 === strpos( $sql, 'SHOW INDEX')) - { - $logto = 'SHOWINDEX'; - $pattern = '/SHOW INDEX FROM\s+(\w+)/'; - preg_match( $pattern, $sql, $matches); - $table = $matches[1]; - // Note: Row order must be in column index position order -$sql = 'SELECT bc.relname AS "Table", - CASE WHEN i.indisunique THEN \'0\' ELSE \'1\' END AS "Non_unique", - CASE WHEN i.indisprimary THEN \'PRIMARY\' WHEN bc.relname LIKE \'%usermeta\' AND ic.relname = \'umeta_key\' - THEN \'meta_key\' ELSE REPLACE( ic.relname, \''.$table.'_\', \'\') END AS "Key_name", - a.attname AS "Column_name", - NULL AS "Sub_part" -FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a -WHERE bc.oid = i.indrelid - AND ic.oid = i.indexrelid - AND (i.indkey[0] = a.attnum OR i.indkey[1] = a.attnum OR i.indkey[2] = a.attnum OR i.indkey[3] = a.attnum OR i.indkey[4] = a.attnum OR i.indkey[5] = a.attnum OR i.indkey[6] = a.attnum OR i.indkey[7] = a.attnum) - AND a.attrelid = bc.oid - AND bc.relname = \''.$table.'\' - ORDER BY "Key_name", CASE a.attnum - WHEN i.indkey[0] THEN 0 - WHEN i.indkey[1] THEN 1 - WHEN i.indkey[2] THEN 2 - WHEN i.indkey[3] THEN 3 - WHEN i.indkey[4] THEN 4 - WHEN i.indkey[5] THEN 5 - WHEN i.indkey[6] THEN 6 - WHEN i.indkey[7] THEN 7 - END;'; - } - // SHOW TABLES emulation - elseif( preg_match('/SHOW\s+(FULL\s+)?TABLES\s+(?:LIKE\s+(.+)|WHERE\s+(.+))?/i', $sql, $matches)) - { - $logto = 'SHOWTABLES'; - $full = $matches[1]; - $like = $matches[2]; - $where = $matches[3]; -// Wrap as sub-query to emulate WHERE behavior -$sql = ($where ? 'SELECT * FROM (' : ''). -'SELECT table_name as "Tables_in_'.$wpdb->dbname.'"'.($full ? ', - table_type AS "Table_type"' : '').' -FROM information_schema.tables'.($like ? ' -WHERE table_name LIKE '.$like : '').($where ? ') AS tables -WHERE '.$where : '').';'; - } - } - // Table alteration - elseif( 0 === strpos( $sql, 'ALTER TABLE')) - { - $logto = 'ALTER'; - $pattern = '/ALTER TABLE\s+(\w+)\s+CHANGE COLUMN\s+([^\s]+)\s+([^\s]+)\s+([^ ]+)( unsigned|)\s*(NOT NULL|)\s*(default (.+)|)/'; - if( 1 === preg_match( $pattern, $sql, $matches)) - { - $table = $matches[1]; - $col = $matches[2]; - $newname = $matches[3]; - $type = strtolower($matches[4]); - if( isset($GLOBALS['pg4wp_ttr'][$type])) - $type = $GLOBALS['pg4wp_ttr'][$type]; - $unsigned = $matches[5]; - $notnull = $matches[6]; - $default = $matches[7]; - $defval = $matches[8]; - if( isset($GLOBALS['pg4wp_ttr'][$defval])) - $defval = $GLOBALS['pg4wp_ttr'][$defval]; - $newq = "ALTER TABLE $table ALTER COLUMN $col TYPE $type"; - if( !empty($notnull)) - $newq .= ", ALTER COLUMN $col SET NOT NULL"; - if( !empty($default)) - $newq .= ", ALTER COLUMN $col SET DEFAULT $defval"; - if( $col != $newname) - $newq .= ";ALTER TABLE $table RENAME COLUMN $col TO $newcol;"; - $sql = $newq; - } - $pattern = '/ALTER TABLE\s+(\w+)\s+ALTER COLUMN\s+/'; - if( 1 === preg_match( $pattern, $sql)) - { - // Translate default values - $sql = str_replace( - array_keys($GLOBALS['pg4wp_ttr']), array_values($GLOBALS['pg4wp_ttr']), $sql); - } - $pattern = '/ALTER TABLE\s+(\w+)\s+ADD COLUMN\s+([^\s]+)\s+([^ ]+)( unsigned|)\s+(NOT NULL|)\s*(default (.+)|)/'; - if( 1 === preg_match( $pattern, $sql, $matches)) - { - $table = $matches[1]; - $col = $matches[2]; - $type = strtolower($matches[3]); - if( isset($GLOBALS['pg4wp_ttr'][$type])) - $type = $GLOBALS['pg4wp_ttr'][$type]; - $unsigned = $matches[4]; - $notnull = $matches[5]; - $default = $matches[6]; - $defval = $matches[7]; - if( isset($GLOBALS['pg4wp_ttr'][$defval])) - $defval = $GLOBALS['pg4wp_ttr'][$defval]; - $newq = "ALTER TABLE $table ADD COLUMN $col $type"; - if( !empty($default)) - $newq .= " DEFAULT $defval"; - if( !empty($notnull)) - $newq .= " NOT NULL"; - $sql = $newq; - } - $pattern = '/ALTER TABLE\s+(\w+)\s+ADD (UNIQUE |)KEY\s+([^\s]+)\s+\(((?:[^\(\)]+|\([^\(\)]+\))+)\)/'; - if( 1 === preg_match( $pattern, $sql, $matches)) - { - $table = $matches[1]; - $unique = $matches[2]; - $index = $matches[3]; - $columns = $matches[4]; - - // Remove prefix indexing - // Rarely used and apparently unnecessary for current uses - $columns = preg_replace( '/\([^\)]*\)/', '', $columns); - - // Workaround for index name duplicate - $index = $table.'_'.$index; - $sql = "CREATE {$unique}INDEX $index ON $table ($columns)"; - } - $pattern = '/ALTER TABLE\s+(\w+)\s+DROP INDEX\s+([^\s]+)/'; - if( 1 === preg_match( $pattern, $sql, $matches)) - { - $table = $matches[1]; - $index = $matches[2]; - $sql = "DROP INDEX ${table}_${index}"; - } - $pattern = '/ALTER TABLE\s+(\w+)\s+DROP PRIMARY KEY/'; - if( 1 === preg_match( $pattern, $sql, $matches)) - { - $table = $matches[1]; - $sql = "ALTER TABLE ${table} DROP CONSTRAINT ${table}_pkey"; - } - } - // Table description - elseif( 0 === strpos( $sql, 'DESCRIBE')) - { - $logto = 'DESCRIBE'; - preg_match( '/DESCRIBE\s+(\w+)/', $sql, $matches); - $table_name = $matches[1]; -$sql = "SELECT pg_attribute.attname AS \"Field\", - CASE pg_type.typname - WHEN 'int2' THEN 'int(4)' - WHEN 'int4' THEN 'int(11)' - WHEN 'int8' THEN 'bigint(20) unsigned' - WHEN 'varchar' THEN 'varchar(' || pg_attribute.atttypmod-4 || ')' - WHEN 'timestamp' THEN 'datetime' - WHEN 'text' THEN 'longtext' - ELSE pg_type.typname - END AS \"Type\", - CASE WHEN pg_attribute.attnotnull THEN '' - ELSE 'YES' - END AS \"Null\", - CASE pg_type.typname - WHEN 'varchar' THEN substring(pg_get_expr(pg_attrdef.adbin, pg_attrdef.adrelid) FROM '^''(.*)''.*$') - WHEN 'timestamp' THEN CASE WHEN pg_get_expr(pg_attrdef.adbin, pg_attrdef.adrelid) LIKE '%now()%' THEN '0000-00-00 00:00:00' ELSE pg_get_expr(pg_attrdef.adbin, pg_attrdef.adrelid) END - ELSE pg_get_expr(pg_attrdef.adbin, pg_attrdef.adrelid) - END AS \"Default\" -FROM pg_class - INNER JOIN pg_attribute - ON (pg_class.oid=pg_attribute.attrelid) - INNER JOIN pg_type - ON (pg_attribute.atttypid=pg_type.oid) - LEFT JOIN pg_attrdef - ON (pg_class.oid=pg_attrdef.adrelid AND pg_attribute.attnum=pg_attrdef.adnum) -WHERE pg_class.relname='$table_name' AND pg_attribute.attnum>=1 AND NOT pg_attribute.attisdropped;"; - } // DESCRIBE - // Fix table creations - elseif( 0 === strpos($sql, 'CREATE TABLE')) - { - $logto = 'CREATE'; - $sql = str_replace( 'CREATE TABLE IF NOT EXISTS ', 'CREATE TABLE ', $sql); - $pattern = '/CREATE TABLE [`]?(\w+)[`]?/'; - preg_match($pattern, $sql, $matches); - $table = $matches[1]; - - // Remove trailing spaces - $sql = trim( $sql).';'; - - // Translate types and some other replacements - $sql = str_replace( - array_keys($GLOBALS['pg4wp_ttr']), array_values($GLOBALS['pg4wp_ttr']), $sql); - - // Fix auto_increment by adding a sequence - $pattern = '/int[ ]+NOT NULL auto_increment/'; - preg_match($pattern, $sql, $matches); - if($matches) - { - $seq = $table . '_seq'; - $sql = str_replace( 'NOT NULL auto_increment', "NOT NULL DEFAULT nextval('$seq'::text)", $sql); - $sql .= "\nCREATE SEQUENCE $seq;"; - } - - // Support for INDEX creation - $pattern = '/,\s+(UNIQUE |)KEY\s+([^\s]+)\s+\(((?:[\w]+(?:\([\d]+\))?[,]?)*)\)/'; - if( preg_match_all( $pattern, $sql, $matches, PREG_SET_ORDER)) - foreach( $matches as $match) - { - $unique = $match[1]; - $index = $match[2]; - $columns = $match[3]; - $columns = preg_replace( '/\(\d+\)/', '', $columns); - // Workaround for index name duplicate - $index = $table.'_'.$index; - $sql .= "\nCREATE {$unique}INDEX $index ON $table ($columns);"; - } - // Now remove handled indexes - $sql = preg_replace( $pattern, '', $sql); - }// CREATE TABLE - elseif( 0 === strpos($sql, 'DROP TABLE')) - { - $logto = 'DROPTABLE'; - $pattern = '/DROP TABLE.+ [`]?(\w+)[`]?$/'; - preg_match($pattern, $sql, $matches); - $table = $matches[1]; - $seq = $table . '_seq'; - $sql .= ";\nDROP SEQUENCE IF EXISTS $seq;"; - }// DROP TABLE - - return $sql; - } diff --git a/pg4wp/driver_pgsql_rewrite.php b/pg4wp/driver_pgsql_rewrite.php index 83fe2d6..473e895 100644 --- a/pg4wp/driver_pgsql_rewrite.php +++ b/pg4wp/driver_pgsql_rewrite.php @@ -12,7 +12,7 @@ spl_autoload_register(function ($className) { function createSQLRewriter(string $sql): AbstractSQLRewriter { $sql = trim($sql); - if (preg_match('/^(SELECT|INSERT|UPDATE|DELETE|SHOW TABLES|OPTIMIZE TABLE|SET NAMES|SHOW FULL COLUMNS)\b/i', $sql, $matches)) { + 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)) { // 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'; @@ -61,7 +61,6 @@ function pg4wp_rewrite($sql) default: } - $sql = loadInstallFunctions($sql, $logto); $sql = correctMetaValue($sql); $sql = handleInterval($sql); $sql = cleanAndCapitalize($sql); @@ -107,24 +106,6 @@ function pg4wp_rewrite($sql) return $sql; } -/** - * Load upgrade and install functions as required. - * - * @param string $sql SQL query string - * @param string $logto Logging type - * @return string Modified SQL query string - */ -function loadInstallFunctions($sql, &$logto) -{ - $begin = strtoupper(substr($sql, 0, 3)); - $search = array('SHO', 'ALT', 'DES', 'CRE', 'DRO'); - if (in_array($begin, $search)) { - require_once(PG4WP_ROOT . '/driver_pgsql_install.php'); - $sql = pg4wp_installing($sql, $logto); - } - return $sql; -} - /** * Correct the meta_value field for WP 2.9.1 and add type cast. * diff --git a/pg4wp/rewriters/AlterTableSQLRewriter.php b/pg4wp/rewriters/AlterTableSQLRewriter.php new file mode 100644 index 0000000..eba78fb --- /dev/null +++ b/pg4wp/rewriters/AlterTableSQLRewriter.php @@ -0,0 +1,126 @@ + 'bigint', + 'bigint(10)' => 'int', + 'int(11)' => 'int', + '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', + '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 utf8_general_ci' => '', + + // For flash-album-gallery plugin + 'tinyint' => 'smallint', + ); + $pattern = '/ALTER TABLE\s+(\w+)\s+CHANGE COLUMN\s+([^\s]+)\s+([^\s]+)\s+([^ ]+)( unsigned|)\s*(NOT NULL|)\s*(default (.+)|)/'; + if(1 === preg_match($pattern, $sql, $matches)) { + $table = $matches[1]; + $col = $matches[2]; + $newname = $matches[3]; + $type = strtolower($matches[4]); + if(isset($typeTranslations[$type])) { + $type = $typeTranslations[$type]; + } + $unsigned = $matches[5]; + $notnull = $matches[6]; + $default = $matches[7]; + $defval = $matches[8]; + if(isset($typeTranslations[$defval])) { + $defval = $typeTranslations[$defval]; + } + $newq = "ALTER TABLE $table ALTER COLUMN $col TYPE $type"; + if(!empty($notnull)) { + $newq .= ", ALTER COLUMN $col SET NOT NULL"; + } + if(!empty($default)) { + $newq .= ", ALTER COLUMN $col SET DEFAULT $defval"; + } + if($col != $newname) { + $newq .= ";ALTER TABLE $table RENAME COLUMN $col TO $newcol;"; + } + $sql = $newq; + } + $pattern = '/ALTER TABLE\s+(\w+)\s+ALTER COLUMN\s+/'; + if(1 === preg_match($pattern, $sql)) { + // Translate default values + $sql = str_replace( + array_keys($typeTranslations), + array_values($typeTranslations), + $sql + ); + } + $pattern = '/ALTER TABLE\s+(\w+)\s+ADD COLUMN\s+([^\s]+)\s+([^ ]+)( unsigned|)\s+(NOT NULL|)\s*(default (.+)|)/'; + if(1 === preg_match($pattern, $sql, $matches)) { + $table = $matches[1]; + $col = $matches[2]; + $type = strtolower($matches[3]); + if(isset($typeTranslations[$type])) { + $type = $typeTranslations[$type]; + } + $unsigned = $matches[4]; + $notnull = $matches[5]; + $default = $matches[6]; + $defval = $matches[7]; + if(isset($typeTranslations[$defval])) { + $defval = $typeTranslations[$defval]; + } + $newq = "ALTER TABLE $table ADD COLUMN $col $type"; + if(!empty($default)) { + $newq .= " DEFAULT $defval"; + } + if(!empty($notnull)) { + $newq .= " NOT NULL"; + } + $sql = $newq; + } + $pattern = '/ALTER TABLE\s+(\w+)\s+ADD (UNIQUE |)KEY\s+([^\s]+)\s+\(((?:[^\(\)]+|\([^\(\)]+\))+)\)/'; + if(1 === preg_match($pattern, $sql, $matches)) { + $table = $matches[1]; + $unique = $matches[2]; + $index = $matches[3]; + $columns = $matches[4]; + + // Remove prefix indexing + // Rarely used and apparently unnecessary for current uses + $columns = preg_replace('/\([^\)]*\)/', '', $columns); + + // Workaround for index name duplicate + $index = $table . '_' . $index; + $sql = "CREATE {$unique}INDEX $index ON $table ($columns)"; + } + $pattern = '/ALTER TABLE\s+(\w+)\s+DROP INDEX\s+([^\s]+)/'; + if(1 === preg_match($pattern, $sql, $matches)) { + $table = $matches[1]; + $index = $matches[2]; + $sql = "DROP INDEX ${table}_${index}"; + } + $pattern = '/ALTER TABLE\s+(\w+)\s+DROP PRIMARY KEY/'; + if(1 === preg_match($pattern, $sql, $matches)) { + $table = $matches[1]; + $sql = "ALTER TABLE ${table} DROP CONSTRAINT ${table}_pkey"; + } + + return $sql; + } +} + + diff --git a/pg4wp/rewriters/CreateTableSQLRewriter.php b/pg4wp/rewriters/CreateTableSQLRewriter.php new file mode 100644 index 0000000..ce0dc2f --- /dev/null +++ b/pg4wp/rewriters/CreateTableSQLRewriter.php @@ -0,0 +1,80 @@ + 'bigint', + 'bigint(10)' => 'int', + 'int(11)' => 'int', + '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', + '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' => '', + + // For flash-album-gallery plugin + 'tinyint' => 'smallint', + ); + + $sql = $this->original(); + $sql = str_replace('CREATE TABLE IF NOT EXISTS ', 'CREATE TABLE ', $sql); + $pattern = '/CREATE TABLE [`]?(\w+)[`]?/'; + preg_match($pattern, $sql, $matches); + $table = $matches[1]; + + // Remove trailing spaces + $sql = trim($sql) . ';'; + + // Translate types and some other replacements + $sql = str_replace( + array_keys($typeTranslations), + array_values($typeTranslations), + $sql + ); + + // Fix auto_increment by adding a sequence + $pattern = '/int[ ]+NOT NULL auto_increment/'; + preg_match($pattern, $sql, $matches); + if($matches) { + $seq = $table . '_seq'; + $sql = str_replace('NOT NULL auto_increment', "NOT NULL DEFAULT nextval('$seq'::text)", $sql); + $sql .= "\nCREATE SEQUENCE $seq;"; + } + + // Support for INDEX creation + $pattern = '/,\s+(UNIQUE |)KEY\s+([^\s]+)\s+\(((?:[\w]+(?:\([\d]+\))?[,]?)*)\)/'; + if(preg_match_all($pattern, $sql, $matches, PREG_SET_ORDER)) { + foreach($matches as $match) { + $unique = $match[1]; + $index = $match[2]; + $columns = $match[3]; + $columns = preg_replace('/\(\d+\)/', '', $columns); + // Workaround for index name duplicate + $index = $table . '_' . $index; + $sql .= "\nCREATE {$unique}INDEX $index ON $table ($columns);"; + } + } + // Now remove handled indexes + $sql = preg_replace($pattern, '', $sql); + + return $sql; + } +} diff --git a/pg4wp/rewriters/DescribeSQLRewriter.php b/pg4wp/rewriters/DescribeSQLRewriter.php new file mode 100644 index 0000000..79b6c4b --- /dev/null +++ b/pg4wp/rewriters/DescribeSQLRewriter.php @@ -0,0 +1,78 @@ +original(); + $table = $this->extractTableName($sql); + return $this->generatePostgresDescribeTable($table); + } + + /** + * Extracts table name from a "DESCRIBE" SQL statement. + * + * @param string $sql The SQL statement + * @return string|null The table name if found, or null otherwise + */ + protected function extractTableName($sql) { + $pattern = "/DESCRIBE ['\"`]?([^'\"`]+)['\"`]?/i"; + if (preg_match($pattern, $sql, $matches)) { + return $matches[1]; + } + return null; + } + + /** + * Generates a PostgreSQL-compatible SQL query to mimic MySQL's "DESCRIBE". + * + * @param string $tableName The table name + * @return string The generated SQL query + */ + function generatePostgresDescribeTable($tableName) { + $sql = << 0 ORDER BY number + SQL; + + return $sql; + } +} diff --git a/pg4wp/rewriters/DropTableSQLRewriter.php b/pg4wp/rewriters/DropTableSQLRewriter.php new file mode 100644 index 0000000..6473e53 --- /dev/null +++ b/pg4wp/rewriters/DropTableSQLRewriter.php @@ -0,0 +1,17 @@ +original(); + + $pattern = '/DROP TABLE.+ [`]?(\w+)[`]?$/'; + preg_match($pattern, $sql, $matches); + $table = $matches[1]; + $seq = $table . '_seq'; + $sql .= ";\nDROP SEQUENCE IF EXISTS $seq;"; + + return $sql; + } +} diff --git a/pg4wp/rewriters/ShowIndexSQLRewriter.php b/pg4wp/rewriters/ShowIndexSQLRewriter.php new file mode 100644 index 0000000..95b9b07 --- /dev/null +++ b/pg4wp/rewriters/ShowIndexSQLRewriter.php @@ -0,0 +1,60 @@ +original(); + $table = $this->extractTableNameFromShowIndex($sql); + return $this->generatePostgresShowIndexFrom($table); + } + + /** + * Extracts table name from a "SHOW FULL COLUMNS" SQL statement. + * + * @param string $sql The SQL statement + * @return string|null The table name if found, or null otherwise + */ + protected function extractVariableName($sql) { + $pattern = "/SHOW INDEX FROM ['\"`]?([^'\"`]+)['\"`]?/i"; + if (preg_match($pattern, $sql, $matches)) { + return $matches[1]; + } + return null; + } + + /** + * Generates a PostgreSQL-compatible SQL query to mimic MySQL's "SHOW INDEX FROM". + * + * @param string $tableName The table name + * @return string The generated SQL query + */ + function generatePostgresShowIndexFrom($tableName) { + $sql = <<original(); + $table = $this->extractVariableName($sql); + return $this->generatePostgres($sql, $variableName); + } + + /** + * Extracts table name from a "SHOW FULL COLUMNS" SQL statement. + * + * @param string $sql The SQL statement + * @return string|null The table name if found, or null otherwise + */ + protected function extractVariableName($sql) { + $pattern = "/SHOW VARIABLES LIKE ['\"`]?([^'\"`]+)['\"`]?/i"; + if (preg_match($pattern, $sql, $matches)) { + return $matches[1]; + } + return null; + } + + /** + * Generates a PostgreSQL-compatible SQL query to mimic MySQL's "SHOW VARIABLES". + * + * @param string $tableName The table name + * @return string The generated SQL query + */ + function generatePostgres($sql, $variableName) { + if ($variableName == "sql_mode") { + // Act like MySQL default configuration, where sql_mode is "" + return "SELECT '$variableName' AS \"Variable_name\", '' AS \"Value\";"; + } + + // return untransformed sql + return $sql; + } +} diff --git a/wp-includes/version.php b/wp-includes/version.php new file mode 100644 index 0000000..cfe442d --- /dev/null +++ b/wp-includes/version.php @@ -0,0 +1,47 @@ + Date: Tue, 7 Nov 2023 15:29:37 -0800 Subject: [PATCH 2/3] formatting --- pg4wp/db.php | 17 +-- pg4wp/driver_mysql.php | 120 ++++++++++++------ pg4wp/driver_pgsql.php | 2 +- pg4wp/rewriters/AlterTableSQLRewriter.php | 2 - pg4wp/rewriters/DescribeSQLRewriter.php | 6 +- .../rewriters/ShowFullColumnsSQLRewriter.php | 6 +- pg4wp/rewriters/ShowIndexSQLRewriter.php | 6 +- pg4wp/rewriters/ShowVariablesSQLRewriter.php | 6 +- 8 files changed, 104 insertions(+), 61 deletions(-) diff --git a/pg4wp/db.php b/pg4wp/db.php index f6aa982..82a859f 100644 --- a/pg4wp/db.php +++ b/pg4wp/db.php @@ -1,11 +1,11 @@ Date: Tue, 7 Nov 2023 15:32:19 -0800 Subject: [PATCH 3/3] add connection to pg_last_error call --- pg4wp/driver_pgsql.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pg4wp/driver_pgsql.php b/pg4wp/driver_pgsql.php index f873785..a8712be 100644 --- a/pg4wp/driver_pgsql.php +++ b/pg4wp/driver_pgsql.php @@ -174,7 +174,7 @@ function pg4wp_init() $result = pg_query($connection, $sql); if ((PG4WP_DEBUG || PG4WP_LOG_ERRORS) && $result === false) { - $error = pg_last_error(); + $error = pg_last_error($connection); error_log("[" . microtime(true) . "] Error creating MySQL-compatible field function: $error\n", 3, PG4WP_LOG . 'pg4wp_errors.log'); } }