mirror of
https://github.com/PostgreSQL-For-Wordpress/postgresql-for-wordpress.git
synced 2025-07-30 01:37:13 +02:00
Merge pull request #31 from mattbucci/mb-php8-wp6-support
WIP: PHP 8 and Wordpress 6+ support
This commit is contained in:
@ -9,6 +9,17 @@
|
||||
* This file does all the initialisation tasks
|
||||
*/
|
||||
|
||||
// This is required by class-wpdb so we must load it first
|
||||
require_once ABSPATH . '/wp-includes/cache.php';
|
||||
require_once ABSPATH . '/wp-includes/l10n.php';
|
||||
|
||||
if (!function_exists('wpsql_is_resource')) {
|
||||
function wpsql_is_resource($object)
|
||||
{
|
||||
return $object !== false && $object !== null;
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -26,13 +37,22 @@ $replaces = array(
|
||||
'class wpdb' => 'class wpdb2',
|
||||
'new wpdb' => 'new wpdb2',
|
||||
'mysql_' => 'wpsql_',
|
||||
'is_resource' => 'wpsql_is_resource',
|
||||
'<?php' => '',
|
||||
'?>' => '',
|
||||
);
|
||||
|
||||
// Ensure class uses the replaced mysql_ functions rather than mysqli_
|
||||
define( 'WP_USE_EXT_MYSQL', true);
|
||||
eval( str_replace( array_keys($replaces), array_values($replaces), file_get_contents(ABSPATH.'/wp-includes/wp-db.php')));
|
||||
if (!defined('WP_USE_EXT_MYSQL')) {
|
||||
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");
|
||||
}
|
||||
|
||||
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'))
|
||||
if (! isset($wpdb) && defined('DB_USER')) {
|
||||
$wpdb = new wpdb2( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST );
|
||||
}
|
59
pg4wp/db.php
59
pg4wp/db.php
@ -9,32 +9,43 @@ Author URI: http://www.hawkix.net
|
||||
License: GPLv2 or newer.
|
||||
*/
|
||||
|
||||
if( !defined('PG4WP_ROOT'))
|
||||
{
|
||||
// You can choose the driver to load here
|
||||
define('DB_DRIVER', 'pgsql'); // 'pgsql' or 'mysql' are supported for now
|
||||
// Ensure we only load this config once
|
||||
if(!defined('PG4WP_ROOT')) {
|
||||
|
||||
// Set this to 'true' and check that `pg4wp` is writable if you want debug logs to be written
|
||||
define( 'PG4WP_DEBUG', false);
|
||||
// If you just want to log queries that generate errors, leave PG4WP_DEBUG to "false"
|
||||
// and set this to true
|
||||
define( 'PG4WP_LOG_ERRORS', true);
|
||||
// You can choose the driver to load here
|
||||
if (!defined('DB_DRIVER')) {
|
||||
define('DB_DRIVER', pgsql);
|
||||
}
|
||||
|
||||
// If you want to allow insecure configuration (from the author point of view) to work with PG4WP,
|
||||
// change this to true
|
||||
define( 'PG4WP_INSECURE', false);
|
||||
// Set this to 'true' and check that `pg4wp` is writable if you want debug logs to be written
|
||||
if (!defined('PG4WP_DEBUG')) {
|
||||
define('PG4WP_DEBUG', false);
|
||||
}
|
||||
|
||||
// This defines the directory where PG4WP files are loaded from
|
||||
// 3 places checked : wp-content, wp-content/plugins and the base directory
|
||||
if( file_exists( ABSPATH.'/wp-content/pg4wp'))
|
||||
define( 'PG4WP_ROOT', ABSPATH.'/wp-content/pg4wp');
|
||||
else if( file_exists( ABSPATH.'/wp-content/plugins/pg4wp'))
|
||||
define( 'PG4WP_ROOT', ABSPATH.'/wp-content/plugins/pg4wp');
|
||||
else if( file_exists( ABSPATH.'/pg4wp'))
|
||||
define( 'PG4WP_ROOT', ABSPATH.'/pg4wp');
|
||||
else
|
||||
die('PG4WP file directory not found');
|
||||
if (!defined('PG4WP_LOG_ERRORS')) {
|
||||
// If you just want to log queries that generate errors, leave PG4WP_DEBUG to "false"
|
||||
// and set this to true
|
||||
define('PG4WP_LOG_ERRORS', true);
|
||||
}
|
||||
|
||||
// Here happens all the magic
|
||||
require_once( PG4WP_ROOT.'/core.php');
|
||||
if (!defined('PG4WP_INSECURE')) {
|
||||
// If you want to allow insecure configuration (from the author point of view) to work with PG4WP,
|
||||
// change this to true
|
||||
define('PG4WP_INSECURE', false);
|
||||
}
|
||||
|
||||
// This defines the directory where PG4WP files are loaded from
|
||||
// 3 places checked : wp-content, wp-content/plugins and the base directory
|
||||
if(file_exists(ABSPATH . '/wp-content/pg4wp')) {
|
||||
define('PG4WP_ROOT', ABSPATH . '/wp-content/pg4wp');
|
||||
} elseif(file_exists(ABSPATH . '/wp-content/plugins/pg4wp')) {
|
||||
define('PG4WP_ROOT', ABSPATH . '/wp-content/plugins/pg4wp');
|
||||
} elseif(file_exists(ABSPATH . '/pg4wp')) {
|
||||
define('PG4WP_ROOT', ABSPATH . '/pg4wp');
|
||||
} else {
|
||||
die('PG4WP file directory not found');
|
||||
}
|
||||
|
||||
// Here happens all the magic
|
||||
require_once(PG4WP_ROOT . '/core.php');
|
||||
} // Protection against multiple loading
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -228,9 +228,9 @@ $sql = "SELECT pg_attribute.attname AS \"Field\",
|
||||
ELSE 'YES'
|
||||
END AS \"Null\",
|
||||
CASE pg_type.typname
|
||||
WHEN 'varchar' THEN substring(pg_attrdef.adsrc FROM '^''(.*)''.*$')
|
||||
WHEN 'timestamp' THEN CASE WHEN pg_attrdef.adsrc LIKE '%now()%' THEN '0000-00-00 00:00:00' ELSE pg_attrdef.adsrc END
|
||||
ELSE pg_attrdef.adsrc
|
||||
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
|
||||
|
204
pg4wp/driver_pgsql_rewrite.php
Normal file
204
pg4wp/driver_pgsql_rewrite.php
Normal file
@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
// Autoload function to automatically require rewriter classes from the "rewriters" folder
|
||||
spl_autoload_register(function ($className) {
|
||||
$filePath = PG4WP_ROOT . '/rewriters/' . $className . '.php';
|
||||
if (file_exists($filePath)) {
|
||||
require_once $filePath;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
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)) {
|
||||
// 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';
|
||||
|
||||
if (class_exists($className)) {
|
||||
return new $className($sql);
|
||||
} else {
|
||||
throw new Exception("No class defined to handle SQL type: " . $type);
|
||||
}
|
||||
}
|
||||
throw new Exception("Invalid or unsupported SQL statement.");
|
||||
}
|
||||
|
||||
|
||||
function pg4wp_rewrite($sql)
|
||||
{
|
||||
// Note: Can be called from constructor before $wpdb is set
|
||||
global $wpdb;
|
||||
|
||||
$initial = $sql;
|
||||
$logto = 'queries';
|
||||
// The end of the query may be protected against changes
|
||||
$end = '';
|
||||
|
||||
$rewriter = createSQLRewriter(trim($sql));
|
||||
$sql = $rewriter->rewrite();
|
||||
$logto = strtoupper($rewriter->type());
|
||||
switch ($rewriter->type()) {
|
||||
case 'Update':
|
||||
// This will avoid modifications to anything following ' SET '
|
||||
list($sql, $end) = explode(' SET ', $sql, 2);
|
||||
$end = ' SET ' . $end;
|
||||
break;
|
||||
case 'Insert':
|
||||
// This will avoid modifications to anything following ' VALUES'
|
||||
list($sql, $end) = explode(' VALUES', $sql, 2);
|
||||
$end = ' VALUES' . $end;
|
||||
|
||||
// When installing, the sequence for table terms has to be updated
|
||||
if(defined('WP_INSTALLING') && WP_INSTALLING && false !== strpos($sql, 'INSERT INTO `' . $wpdb->terms . '`')) {
|
||||
$end .= ';SELECT setval(\'' . $wpdb->terms . '_seq\', (SELECT MAX(term_id) FROM ' . $wpdb->terms . ')+1);';
|
||||
}
|
||||
break;
|
||||
case 'Insert':
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
$sql = loadInstallFunctions($sql, $logto);
|
||||
$sql = correctMetaValue($sql);
|
||||
$sql = handleInterval($sql);
|
||||
$sql = cleanAndCapitalize($sql);
|
||||
$sql = correctEmptyInStatements($sql);
|
||||
$sql = correctQuoting($sql);
|
||||
|
||||
// Put back the end of the query if it was separated
|
||||
$sql .= $end;
|
||||
|
||||
// For insert ID catching
|
||||
if($logto == 'INSERT') {
|
||||
$pattern = '/INSERT INTO (\w+)\s+\([ a-zA-Z_"]+/';
|
||||
preg_match($pattern, $sql, $matches);
|
||||
$GLOBALS['pg4wp_ins_table'] = $matches[1];
|
||||
$match_list = explode(' ', $matches[0]);
|
||||
if($GLOBALS['pg4wp_ins_table']) {
|
||||
$GLOBALS['pg4wp_ins_field'] = trim($match_list[3], ' () ');
|
||||
if(!$GLOBALS['pg4wp_ins_field']) {
|
||||
$GLOBALS['pg4wp_ins_field'] = trim($match_list[4], ' () ');
|
||||
}
|
||||
}
|
||||
$GLOBALS['pg4wp_last_insert'] = $sql;
|
||||
} elseif(isset($GLOBALS['pg4wp_queued_query'])) {
|
||||
pg_query($GLOBALS['pg4wp_queued_query']);
|
||||
unset($GLOBALS['pg4wp_queued_query']);
|
||||
}
|
||||
|
||||
if(PG4WP_DEBUG) {
|
||||
if($initial != $sql) {
|
||||
error_log('[' . microtime(true) . "] Converting :\n$initial\n---- to ----\n$sql\n---------------------\n", 3, PG4WP_LOG . 'pg4wp_' . $logto . '.log');
|
||||
} else {
|
||||
error_log('[' . microtime(true) . "] $sql\n---------------------\n", 3, PG4WP_LOG . 'pg4wp_unmodified.log');
|
||||
}
|
||||
}
|
||||
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.
|
||||
*
|
||||
* @param string $sql SQL query string
|
||||
* @return string Modified SQL query string
|
||||
*/
|
||||
function correctMetaValue($sql)
|
||||
{
|
||||
// WP 2.9.1 uses a comparison where text data is not quoted
|
||||
$sql = preg_replace('/AND meta_value = (-?\d+)/', 'AND meta_value = \'$1\'', $sql);
|
||||
// Add type cast for meta_value field when it's compared to number
|
||||
$sql = preg_replace('/AND meta_value < (\d+)/', 'AND meta_value::bigint < $1', $sql);
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle interval expressions in SQL query.
|
||||
*
|
||||
* @param string $sql SQL query string
|
||||
* @return string Modified SQL query string
|
||||
*/
|
||||
function handleInterval($sql)
|
||||
{
|
||||
// Generic "INTERVAL xx YEAR|MONTH|DAY|HOUR|MINUTE|SECOND" handler
|
||||
$sql = preg_replace('/INTERVAL[ ]+(\d+)[ ]+(YEAR|MONTH|DAY|HOUR|MINUTE|SECOND)/', "'\$1 \$2'::interval", $sql);
|
||||
// DATE_SUB handling
|
||||
$sql = preg_replace('/DATE_SUB[ ]*\(([^,]+),([^\)]+)\)/', '($1::timestamp - $2)', $sql);
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean SQL query from illegal characters and handle capitalization.
|
||||
*
|
||||
* @param string $sql SQL query string
|
||||
* @return string Modified SQL query string
|
||||
*/
|
||||
function cleanAndCapitalize($sql)
|
||||
{
|
||||
// Remove illegal characters
|
||||
$sql = str_replace('`', '', $sql);
|
||||
// Field names with CAPITALS need special handling
|
||||
if (false !== strpos($sql, 'ID')) {
|
||||
$patterns = [
|
||||
'/ID([^ ])/' => 'ID $1',
|
||||
'/ID$/' => 'ID ',
|
||||
'/\(ID/' => '( ID',
|
||||
'/,ID/' => ', ID',
|
||||
'/[0-9a-zA-Z_]+ID/' => '"$0"',
|
||||
'/\.ID/' => '."ID"',
|
||||
'/[\s]ID /' => ' "ID" ',
|
||||
'/"ID "/' => ' "ID" '
|
||||
];
|
||||
foreach ($patterns as $pattern => $replacement) {
|
||||
$sql = preg_replace($pattern, $replacement, $sql);
|
||||
}
|
||||
}
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct empty IN statements in SQL query.
|
||||
*
|
||||
* @param string $sql SQL query string
|
||||
* @return string Modified SQL query string
|
||||
*/
|
||||
function correctEmptyInStatements($sql)
|
||||
{
|
||||
$search = ['IN (\'\')', 'IN ( \'\' )', 'IN ()'];
|
||||
$replace = 'IN (NULL)';
|
||||
$sql = str_replace($search, $replace, $sql);
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct quoting for PostgreSQL 9.1+ compatibility.
|
||||
*
|
||||
* @param string $sql SQL query string
|
||||
* @return string Modified SQL query string
|
||||
*/
|
||||
function correctQuoting($sql)
|
||||
{
|
||||
$sql = str_replace("\\'", "''", $sql);
|
||||
$sql = str_replace('\"', '"', $sql);
|
||||
return $sql;
|
||||
}
|
26
pg4wp/rewriters/AbstractSQLRewriter.php
Normal file
26
pg4wp/rewriters/AbstractSQLRewriter.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
abstract class AbstractSQLRewriter
|
||||
{
|
||||
protected string $originalSQL;
|
||||
|
||||
public function __construct(string $sql)
|
||||
{
|
||||
$this->originalSQL = $sql;
|
||||
}
|
||||
|
||||
abstract public function rewrite(): string;
|
||||
|
||||
public function original(): string
|
||||
{
|
||||
return $this->originalSQL;
|
||||
}
|
||||
|
||||
public function type(): string
|
||||
{
|
||||
// Get the called class name and remove the "SQLRewriter" suffix to get the SQL type
|
||||
$className = get_called_class();
|
||||
$type = str_replace('SQLRewriter', '', $className);
|
||||
return $type;
|
||||
}
|
||||
}
|
60
pg4wp/rewriters/DeleteSQLRewriter.php
Normal file
60
pg4wp/rewriters/DeleteSQLRewriter.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
class DeleteSQLRewriter extends AbstractSQLRewriter
|
||||
{
|
||||
public function rewrite(): string
|
||||
{
|
||||
global $wpdb;
|
||||
|
||||
$sql = $this->original();
|
||||
|
||||
// ORDER BY is not supported in DELETE queries, and not required
|
||||
// when LIMIT is not present
|
||||
if(false !== strpos($sql, 'ORDER BY') && false === strpos($sql, 'LIMIT')) {
|
||||
$pattern = '/ORDER BY \S+ (ASC|DESC)?/';
|
||||
$sql = preg_replace($pattern, '', $sql);
|
||||
}
|
||||
|
||||
// LIMIT is not allowed in DELETE queries
|
||||
$sql = str_replace('LIMIT 1', '', $sql);
|
||||
$sql = str_replace(' REGEXP ', ' ~ ', $sql);
|
||||
|
||||
// This handles removal of duplicate entries in table options
|
||||
if(false !== strpos($sql, 'DELETE o1 FROM ')) {
|
||||
$sql = "DELETE FROM $wpdb->options WHERE option_id IN " .
|
||||
"(SELECT o1.option_id FROM $wpdb->options AS o1, $wpdb->options AS o2 " .
|
||||
"WHERE o1.option_name = o2.option_name " .
|
||||
"AND o1.option_id < o2.option_id)";
|
||||
}
|
||||
// Rewrite _transient_timeout multi-table delete query
|
||||
elseif(0 === strpos($sql, 'DELETE a, b FROM wp_options a, wp_options b')) {
|
||||
$where = substr($sql, strpos($sql, 'WHERE ') + 6);
|
||||
$where = rtrim($where, " \t\n\r;");
|
||||
// Fix string/number comparison by adding check and cast
|
||||
$where = str_replace('AND b.option_value', 'AND b.option_value ~ \'^[0-9]+$\' AND CAST(b.option_value AS BIGINT)', $where);
|
||||
// Mirror WHERE clause to delete both sides of self-join.
|
||||
$where2 = strtr($where, array('a.' => 'b.', 'b.' => 'a.'));
|
||||
$sql = 'DELETE FROM wp_options a USING wp_options b WHERE ' .
|
||||
'(' . $where . ') OR (' . $where2 . ');';
|
||||
}
|
||||
|
||||
// Rewrite _transient_timeout multi-table delete query
|
||||
elseif(0 === strpos($sql, 'DELETE a, b FROM wp_sitemeta a, wp_sitemeta b')) {
|
||||
$where = substr($sql, strpos($sql, 'WHERE ') + 6);
|
||||
$where = rtrim($where, " \t\n\r;");
|
||||
// Fix string/number comparison by adding check and cast
|
||||
$where = str_replace('AND b.meta_value', 'AND b.meta_value ~ \'^[0-9]+$\' AND CAST(b.meta_value AS BIGINT)', $where);
|
||||
// Mirror WHERE clause to delete both sides of self-join.
|
||||
$where2 = strtr($where, array('a.' => 'b.', 'b.' => 'a.'));
|
||||
$sql = 'DELETE FROM wp_sitemeta a USING wp_sitemeta b WHERE ' .
|
||||
'(' . $where . ') OR (' . $where2 . ');';
|
||||
}
|
||||
|
||||
// Akismet sometimes doesn't write 'comment_ID' with 'ID' in capitals where needed ...
|
||||
if(false !== strpos($sql, $wpdb->comments)) {
|
||||
$sql = str_replace(' comment_id ', ' comment_ID ', $sql);
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
}
|
124
pg4wp/rewriters/InsertSQLRewriter.php
Normal file
124
pg4wp/rewriters/InsertSQLRewriter.php
Normal file
@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
class InsertSQLRewriter extends AbstractSQLRewriter
|
||||
{
|
||||
public function rewrite(): string
|
||||
{
|
||||
global $wpdb;
|
||||
|
||||
$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);
|
||||
|
||||
// Multiple values group when calling INSERT INTO don't always work
|
||||
if(false !== strpos($sql, $wpdb->options) && false !== strpos($sql, '), (')) {
|
||||
$pattern = '/INSERT INTO.+VALUES/';
|
||||
preg_match($pattern, $sql, $matches);
|
||||
$insert = $matches[0];
|
||||
$sql = str_replace('), (', ');' . $insert . '(', $sql);
|
||||
}
|
||||
|
||||
// Swap ON DUPLICATE KEY SYNTAX
|
||||
if(false !== $pos = strpos($sql, 'ON DUPLICATE KEY UPDATE')) {
|
||||
$splitStatements = function (string $sql): array {
|
||||
$statements = [];
|
||||
$buffer = '';
|
||||
$quote = null;
|
||||
|
||||
for ($i = 0, $len = strlen($sql); $i < $len; $i++) {
|
||||
$char = $sql[$i];
|
||||
|
||||
if ($quote) {
|
||||
if ($char === $quote && $sql[$i - 1] !== '\\') {
|
||||
$quote = null;
|
||||
}
|
||||
} elseif ($char === '"' || $char === "'") {
|
||||
$quote = $char;
|
||||
} elseif ($char === ';') {
|
||||
$statements[] = $buffer . ';';
|
||||
$buffer = '';
|
||||
continue;
|
||||
}
|
||||
|
||||
$buffer .= $char;
|
||||
}
|
||||
|
||||
if (!empty($buffer)) {
|
||||
$statements[] = $buffer;
|
||||
}
|
||||
|
||||
return $statements;
|
||||
};
|
||||
|
||||
$statements = $splitStatements($sql);
|
||||
|
||||
foreach ($statements as $statement) {
|
||||
$statement = trim($statement);
|
||||
|
||||
// Skip empty statements
|
||||
if (empty($statement)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Replace backticks with double quotes for PostgreSQL compatibility
|
||||
$statement = str_replace('`', '"', $statement);
|
||||
|
||||
// Find index positions for the SQL components
|
||||
$insertIndex = strpos($statement, 'INSERT INTO');
|
||||
$valuesIndex = strpos($statement, 'VALUES');
|
||||
$onDuplicateKeyIndex = strpos($statement, 'ON DUPLICATE KEY UPDATE');
|
||||
|
||||
// Extract SQL components
|
||||
$tableSection = trim(substr($statement, $insertIndex, $valuesIndex - $insertIndex));
|
||||
$valuesSection = trim(substr($statement, $valuesIndex, $onDuplicateKeyIndex - $valuesIndex));
|
||||
$updateSection = trim(str_replace('ON DUPLICATE KEY UPDATE', '', substr($statement, $onDuplicateKeyIndex)));
|
||||
|
||||
// Extract and clean up column names from the update section
|
||||
$updateCols = explode(',', $updateSection);
|
||||
$updateCols = array_map(function ($col) {
|
||||
return trim(explode('=', $col)[0]);
|
||||
}, $updateCols);
|
||||
|
||||
// Choose a primary key for ON CONFLICT
|
||||
$primaryKey = 'option_name';
|
||||
if (!in_array($primaryKey, $updateCols)) {
|
||||
$primaryKey = 'meta_name';
|
||||
if (!in_array($primaryKey, $updateCols)) {
|
||||
$primaryKey = $updateCols[0] ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the PostgreSQL ON CONFLICT DO UPDATE section
|
||||
$updateSection = implode(', ', array_map(fn($col) => "$col = EXCLUDED.$col", $updateCols));
|
||||
|
||||
// Construct the PostgreSQL query
|
||||
$postgresSQL = sprintf('%s %s ON CONFLICT (%s) DO UPDATE SET %s', $tableSection, $valuesSection, $primaryKey, $updateSection);
|
||||
|
||||
// Append to the converted statements list
|
||||
$convertedStatements[] = $postgresSQL;
|
||||
}
|
||||
|
||||
$sql = implode('; ', $convertedStatements);
|
||||
} elseif(0 === strpos($sql, 'INSERT IGNORE')) {
|
||||
// Note: Requires PostgreSQL 9.5
|
||||
$sql = 'INSERT' . substr($sql, 13) . ' ON CONFLICT DO NOTHING';
|
||||
}
|
||||
|
||||
// To avoid Encoding errors when inserting data coming from outside
|
||||
if(preg_match('/^.{1}/us', $sql, $ar) != 1) {
|
||||
$sql = utf8_encode($sql);
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
}
|
10
pg4wp/rewriters/OptimizeTableSQLRewriter.php
Normal file
10
pg4wp/rewriters/OptimizeTableSQLRewriter.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
class OptimizeTableSQLRewriter extends AbstractSQLRewriter
|
||||
{
|
||||
public function rewrite(): string
|
||||
{
|
||||
$sql = $this->original();
|
||||
return str_replace('OPTIMIZE TABLE', 'VACUUM', $sql);
|
||||
}
|
||||
}
|
324
pg4wp/rewriters/SelectSQLRewriter.php
Normal file
324
pg4wp/rewriters/SelectSQLRewriter.php
Normal file
@ -0,0 +1,324 @@
|
||||
<?php
|
||||
|
||||
class SelectSQLRewriter extends AbstractSQLRewriter
|
||||
{
|
||||
public function rewrite(): string
|
||||
{
|
||||
global $wpdb;
|
||||
|
||||
$sql = $this->original();
|
||||
|
||||
// SQL_CALC_FOUND_ROWS doesn't exist in PostgreSQL but it's needed for correct paging
|
||||
if(false !== strpos($sql, 'SQL_CALC_FOUND_ROWS')) {
|
||||
$sql = str_replace('SQL_CALC_FOUND_ROWS', '', $sql);
|
||||
$GLOBALS['pg4wp_numrows_query'] = $sql;
|
||||
if(PG4WP_DEBUG) {
|
||||
error_log('[' . microtime(true) . "] Number of rows required for :\n$sql\n---------------------\n", 3, PG4WP_LOG . 'pg4wp_NUMROWS.log');
|
||||
}
|
||||
}
|
||||
|
||||
if(false !== strpos($sql, 'FOUND_ROWS()')) {
|
||||
// Here we convert the latest query into a COUNT query
|
||||
$sql = $GLOBALS['pg4wp_numrows_query'];
|
||||
|
||||
// Remove the LIMIT clause if it exists
|
||||
$sql = preg_replace('/\s+LIMIT\s+\d+(\s*,\s*\d+)?/i', '', $sql);
|
||||
|
||||
// Remove the ORDER BY clause if it exists
|
||||
$sql = preg_replace('/\s+ORDER\s+BY\s+[^)]+/i', '', $sql);
|
||||
|
||||
// Replace the fields in the SELECT clause with COUNT(*)
|
||||
$sql = preg_replace('/SELECT\s+.*?\s+FROM\s+/is', 'SELECT COUNT(*) FROM ', $sql, 1);
|
||||
}
|
||||
|
||||
$sql = $this->ensureOrderByInSelect($sql);
|
||||
|
||||
// Convert CONVERT to CAST
|
||||
$pattern = '/CONVERT\(([^()]*(\(((?>[^()]+)|(?-2))*\))?[^()]*),\s*([^\s]+)\)/x';
|
||||
$sql = preg_replace($pattern, 'CAST($1 AS $4)', $sql);
|
||||
|
||||
// Handle CAST( ... AS CHAR)
|
||||
$sql = preg_replace('/CAST\((.+) AS CHAR\)/', 'CAST($1 AS TEXT)', $sql);
|
||||
|
||||
// Handle CAST( ... AS SIGNED)
|
||||
$sql = preg_replace('/CAST\((.+) AS SIGNED\)/', 'CAST($1 AS INTEGER)', $sql);
|
||||
|
||||
// Handle COUNT(*)...ORDER BY...
|
||||
$sql = preg_replace('/COUNT(.+)ORDER BY.+/s', 'COUNT$1', $sql);
|
||||
|
||||
// In order for users counting to work...
|
||||
$matches = array();
|
||||
if(preg_match_all('/COUNT[^C]+\),/', $sql, $matches)) {
|
||||
foreach($matches[0] as $num => $one) {
|
||||
$sub = substr($one, 0, -1);
|
||||
$sql = str_replace($sub, $sub . ' AS count' . $num, $sql);
|
||||
}
|
||||
}
|
||||
|
||||
$sql = $this->convertToPostgresLimitSyntax($sql);
|
||||
$sql = $this->ensureGroupByOrAggregate($sql);
|
||||
|
||||
$pattern = '/DATE_ADD[ ]*\(([^,]+),([^\)]+)\)/';
|
||||
$sql = preg_replace($pattern, '($1 + $2)', $sql);
|
||||
|
||||
// Convert MySQL FIELD function to CASE statement
|
||||
$pattern = '/FIELD[ ]*\(([^\),]+),([^\)]+)\)/';
|
||||
// https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_field
|
||||
// Other implementations: https://stackoverflow.com/q/1309624
|
||||
$sql = preg_replace_callback($pattern, function ($matches) {
|
||||
$case = 'CASE ' . trim($matches[1]);
|
||||
$comparands = explode(',', $matches[2]);
|
||||
foreach($comparands as $i => $comparand) {
|
||||
$case .= ' WHEN ' . trim($comparand) . ' THEN ' . ($i + 1);
|
||||
}
|
||||
$case .= ' ELSE 0 END';
|
||||
return $case;
|
||||
}, $sql);
|
||||
|
||||
$pattern = '/GROUP_CONCAT\(([^()]*(\(((?>[^()]+)|(?-2))*\))?[^()]*)\)/x';
|
||||
$sql = preg_replace($pattern, "string_agg($1, ',')", $sql);
|
||||
|
||||
// Convert MySQL RAND function to PostgreSQL RANDOM function
|
||||
$pattern = '/RAND[ ]*\([ ]*\)/';
|
||||
$sql = preg_replace($pattern, 'RANDOM()', $sql);
|
||||
|
||||
// UNIX_TIMESTAMP in MYSQL returns an integer
|
||||
$pattern = '/UNIX_TIMESTAMP\(([^\)]+)\)/';
|
||||
$sql = preg_replace($pattern, 'ROUND(DATE_PART(\'epoch\',$1))', $sql);
|
||||
|
||||
$date_funcs = array(
|
||||
'DAYOFMONTH(' => 'EXTRACT(DAY FROM ',
|
||||
'YEAR(' => 'EXTRACT(YEAR FROM ',
|
||||
'MONTH(' => 'EXTRACT(MONTH FROM ',
|
||||
'DAY(' => 'EXTRACT(DAY FROM ',
|
||||
);
|
||||
|
||||
$sql = str_replace('ORDER BY post_date DESC', 'ORDER BY YEAR(post_date) DESC, MONTH(post_date) DESC', $sql);
|
||||
$sql = str_replace('ORDER BY post_date ASC', 'ORDER BY YEAR(post_date) ASC, MONTH(post_date) ASC', $sql);
|
||||
$sql = str_replace(array_keys($date_funcs), array_values($date_funcs), $sql);
|
||||
$curryear = date('Y');
|
||||
$sql = str_replace('FROM \'' . $curryear, 'FROM TIMESTAMP \'' . $curryear, $sql);
|
||||
|
||||
// MySQL 'IF' conversion - Note : NULLIF doesn't need to be corrected
|
||||
$pattern = '/ (?<!NULL)IF[ ]*\(([^,]+),([^,]+),([^\)]+)\)/';
|
||||
$sql = preg_replace($pattern, ' CASE WHEN $1 THEN $2 ELSE $3 END', $sql);
|
||||
|
||||
// Act like MySQL default configuration, where sql_mode is ""
|
||||
$pattern = '/@@SESSION.sql_mode/';
|
||||
$sql = preg_replace($pattern, "''", $sql);
|
||||
|
||||
if(isset($wpdb)) {
|
||||
$sql = str_replace('GROUP BY ' . $wpdb->prefix . 'posts.ID', '', $sql);
|
||||
}
|
||||
$sql = str_replace("!= ''", '<> 0', $sql);
|
||||
|
||||
// MySQL 'LIKE' is case insensitive by default, whereas PostgreSQL 'LIKE' is
|
||||
$sql = str_replace(' LIKE ', ' ILIKE ', $sql);
|
||||
|
||||
// INDEXES are not yet supported
|
||||
if(false !== strpos($sql, 'USE INDEX (comment_date_gmt)')) {
|
||||
$sql = str_replace('USE INDEX (comment_date_gmt)', '', $sql);
|
||||
}
|
||||
|
||||
// HB : timestamp fix for permalinks
|
||||
$sql = str_replace('post_date_gmt > 1970', 'post_date_gmt > to_timestamp (\'1970\')', $sql);
|
||||
|
||||
// Akismet sometimes doesn't write 'comment_ID' with 'ID' in capitals where needed ...
|
||||
if(isset($wpdb) && $wpdb->comments && false !== strpos($sql, $wpdb->comments)) {
|
||||
$sql = str_replace(' comment_id ', ' comment_ID ', $sql);
|
||||
}
|
||||
|
||||
// MySQL treats a HAVING clause without GROUP BY like WHERE
|
||||
if(false !== strpos($sql, 'HAVING') && false === strpos($sql, 'GROUP BY')) {
|
||||
if(false === strpos($sql, 'WHERE')) {
|
||||
$sql = str_replace('HAVING', 'WHERE', $sql);
|
||||
} else {
|
||||
$pattern = '/WHERE\s+(.*?)\s+HAVING\s+(.*?)(\s*(?:ORDER|LIMIT|PROCEDURE|INTO|FOR|LOCK|$))/';
|
||||
$sql = preg_replace($pattern, 'WHERE ($1) AND ($2) $3', $sql);
|
||||
}
|
||||
}
|
||||
|
||||
// MySQL allows integers to be used as boolean expressions
|
||||
// where 0 is false and all other values are true.
|
||||
//
|
||||
// Although this could occur anywhere with any number, so far it
|
||||
// has only been observed as top-level expressions in the WHERE
|
||||
// clause and only with 0. For performance, limit current
|
||||
// replacements to that.
|
||||
$pattern_after_where = '(?:\s*$|\s+(GROUP|HAVING|ORDER|LIMIT|PROCEDURE|INTO|FOR|LOCK))';
|
||||
$pattern = '/(WHERE\s+)0(\s+AND|\s+OR|' . $pattern_after_where . ')/';
|
||||
$sql = preg_replace($pattern, '$1false$2', $sql);
|
||||
|
||||
$pattern = '/(AND\s+|OR\s+)0(' . $pattern_after_where . ')/';
|
||||
$sql = preg_replace($pattern, '$1false$2', $sql);
|
||||
|
||||
// MySQL supports strings as names, PostgreSQL needs identifiers.
|
||||
// Limit to after closing parenthesis to reduce false-positives
|
||||
// Currently only an issue for nextgen-gallery plugin
|
||||
$pattern = '/\) AS \'([^\']+)\'/';
|
||||
$sql = preg_replace($pattern, ') AS "$1"', $sql);
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the columns used in the ORDER BY clause are also present in the SELECT clause.
|
||||
*
|
||||
* @param string $sql Original SQL query string.
|
||||
* @return string Modified SQL query string.
|
||||
*/
|
||||
protected function ensureOrderByInSelect(string $sql): string
|
||||
{
|
||||
// Extract the SELECT and ORDER BY clauses
|
||||
preg_match('/SELECT\s+(.*?)\s+FROM/si', $sql, $selectMatches);
|
||||
preg_match('/ORDER BY(.*?)(ASC|DESC|$)/si', $sql, $orderMatches);
|
||||
preg_match('/GROUP BY(.*?)(ASC|DESC|$)/si', $sql, $groupMatches);
|
||||
|
||||
// If the SELECT clause is missing, return the original query
|
||||
if (!$selectMatches) {
|
||||
return $sql;
|
||||
}
|
||||
|
||||
// If both ORDER BY and GROUP BY clauses are missing, return the original query
|
||||
if (!$orderMatches && !$groupMatches) {
|
||||
return $sql;
|
||||
}
|
||||
|
||||
$selectClause = trim($selectMatches[1]);
|
||||
$orderByClause = $orderMatches ? trim($orderMatches[1]) : null;
|
||||
$groupClause = $groupMatches ? trim($groupMatches[1]) : null;
|
||||
$modified = false;
|
||||
|
||||
// Check for wildcard in SELECT
|
||||
if (strpos($selectClause, '*') !== false) {
|
||||
return $sql; // Cannot handle wildcards, return original query
|
||||
}
|
||||
|
||||
// Handle ORDER BY columns
|
||||
if ($orderByClause) {
|
||||
$orderByColumns = explode(',', $orderByClause);
|
||||
foreach ($orderByColumns as $col) {
|
||||
$col = trim($col);
|
||||
if (strpos($selectClause, $col) === false) {
|
||||
$selectClause .= ', ' . $col;
|
||||
$modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle GROUP BY columns
|
||||
if ($groupClause && !$modified) {
|
||||
$groupColumns = explode(',', $groupClause);
|
||||
foreach ($groupColumns as $col) {
|
||||
$col = trim($col);
|
||||
if (strpos($selectClause, $col) === false) {
|
||||
$selectClause .= ', ' . $col;
|
||||
$modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$modified) {
|
||||
return $sql;
|
||||
}
|
||||
|
||||
// Find the exact position for the replacement
|
||||
$selectStartPos = strpos($sql, $selectMatches[1]);
|
||||
if ($selectStartPos === false) {
|
||||
return $sql; // If for some reason the exact match is not found, return the original query
|
||||
}
|
||||
$postgresSql = substr_replace($sql, $selectClause, $selectStartPos, strlen($selectMatches[1]));
|
||||
|
||||
return $postgresSql;
|
||||
}
|
||||
|
||||
protected function ensureGroupByOrAggregate(string $sql): string
|
||||
{
|
||||
// Check for system or session variables
|
||||
if (preg_match('/@@[a-zA-Z0-9_]+/', $sql)) {
|
||||
return $sql;
|
||||
}
|
||||
|
||||
// Regular expression to capture main SQL components
|
||||
$regex = '/(SELECT\s+)(.*?)(\s+FROM\s+)([^ ]+)(\s+WHERE\s+.*?(?= ORDER BY | GROUP BY | LIMIT |$))?(ORDER BY.*?(?= LIMIT |$))?(LIMIT.*?$)?/is';
|
||||
|
||||
// Capture main SQL components using regex
|
||||
if (!preg_match($regex, $sql, $matches)) {
|
||||
return $sql;
|
||||
}
|
||||
|
||||
$selectClause = $matches[2] ?? '';
|
||||
$fromClause = $matches[4] ?? '';
|
||||
$whereClause = $matches[5] ?? '';
|
||||
$orderClause = $matches[6] ?? '';
|
||||
$limitClause = $matches[7] ?? '';
|
||||
|
||||
if (empty($selectClause) || empty($fromClause)) {
|
||||
return $sql;
|
||||
}
|
||||
|
||||
$columns = explode(',', $selectClause);
|
||||
$aggregateColumns = [];
|
||||
$nonAggregateColumns = [];
|
||||
|
||||
foreach ($columns as $col) {
|
||||
$col = trim($col);
|
||||
if (preg_match('/(COUNT|SUM|AVG|MIN|MAX)\s*?\(/i', $col)) {
|
||||
$aggregateColumns[] = $col;
|
||||
} else {
|
||||
$nonAggregateColumns[] = $col;
|
||||
}
|
||||
}
|
||||
|
||||
// Only add a GROUP BY clause if there are both aggregate and non-aggregate columns in SELECT
|
||||
if (empty($aggregateColumns) || empty($nonAggregateColumns)) {
|
||||
return $sql;
|
||||
}
|
||||
|
||||
$groupByClause = "GROUP BY " . implode(", ", $nonAggregateColumns);
|
||||
|
||||
// Assemble new SQL query
|
||||
$postgresSql = "SELECT $selectClause FROM $fromClause";
|
||||
|
||||
if (!empty(trim($whereClause))) {
|
||||
$postgresSql .= " $whereClause";
|
||||
}
|
||||
|
||||
$postgresSql .= " $groupByClause";
|
||||
|
||||
if (!empty(trim($orderClause))) {
|
||||
$postgresSql .= " $orderClause";
|
||||
}
|
||||
|
||||
if (!empty(trim($limitClause))) {
|
||||
$postgresSql .= " $limitClause";
|
||||
}
|
||||
|
||||
return $postgresSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert MySQL LIMIT syntax to PostgreSQL LIMIT syntax
|
||||
*
|
||||
* @param string $sql MySQL query string
|
||||
* @return string PostgreSQL query string
|
||||
*/
|
||||
protected function convertToPostgresLimitSyntax($sql)
|
||||
{
|
||||
// Use regex to find "LIMIT m, n" syntax in query
|
||||
if (preg_match('/LIMIT\s+(\d+),\s*(\d+)/i', $sql, $matches)) {
|
||||
$offset = $matches[1];
|
||||
$limit = $matches[2];
|
||||
|
||||
// Replace MySQL LIMIT syntax with PostgreSQL LIMIT syntax
|
||||
$postgresLimitSyntax = "LIMIT $limit OFFSET $offset";
|
||||
$postgresSql = preg_replace('/LIMIT\s+\d+,\s*\d+/i', $postgresLimitSyntax, $sql);
|
||||
|
||||
return $postgresSql;
|
||||
}
|
||||
|
||||
// Return original query if no MySQL LIMIT syntax is found
|
||||
return $sql;
|
||||
}
|
||||
|
||||
}
|
9
pg4wp/rewriters/SetNamesSQLRewriter.php
Normal file
9
pg4wp/rewriters/SetNamesSQLRewriter.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
class SetNamesSQLRewriter extends AbstractSQLRewriter
|
||||
{
|
||||
public function rewrite(): string
|
||||
{
|
||||
return "SET NAMES 'utf8'";
|
||||
}
|
||||
}
|
71
pg4wp/rewriters/ShowFullColumnsSQLRewriter.php
Normal file
71
pg4wp/rewriters/ShowFullColumnsSQLRewriter.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
class ShowFullColumnsSQLRewriter extends AbstractSQLRewriter
|
||||
{
|
||||
public function rewrite(): string
|
||||
{
|
||||
$sql = $this->original();
|
||||
$table = $this->extractTableNameFromShowColumns($sql);
|
||||
return $this->generatePostgresShowColumns($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 extractTableNameFromShowColumns($sql) {
|
||||
$pattern = "/SHOW FULL COLUMNS FROM ['\"`]?([^'\"`]+)['\"`]?/i";
|
||||
if (preg_match($pattern, $sql, $matches)) {
|
||||
return $matches[1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a PostgreSQL-compatible SQL query to mimic MySQL's "SHOW FULL COLUMNS".
|
||||
*
|
||||
* @param string $tableName The table name
|
||||
* @return string The generated SQL query
|
||||
*/
|
||||
function generatePostgresShowColumns($tableName) {
|
||||
$sql = <<<SQL
|
||||
SELECT
|
||||
a.attname AS "Field",
|
||||
pg_catalog.format_type(a.atttypid, a.atttypmod) AS "Type",
|
||||
(CASE
|
||||
WHEN a.attnotnull THEN 'NO'
|
||||
ELSE 'YES'
|
||||
END) AS "Null",
|
||||
(CASE
|
||||
WHEN i.indisprimary THEN 'PRI'
|
||||
WHEN i.indisunique THEN 'UNI'
|
||||
ELSE ''
|
||||
END) AS "Key",
|
||||
pg_catalog.pg_get_expr(ad.adbin, ad.adrelid) AS "Default",
|
||||
'' AS "Extra",
|
||||
'select,insert,update,references' AS "Privileges",
|
||||
d.description AS "Comment"
|
||||
FROM
|
||||
pg_catalog.pg_attribute a
|
||||
LEFT JOIN pg_catalog.pg_description d ON (a.attrelid = d.objoid AND a.attnum = d.objsubid)
|
||||
LEFT JOIN pg_catalog.pg_attrdef ad ON (a.attrelid = ad.adrelid AND a.attnum = ad.adnum)
|
||||
LEFT JOIN pg_catalog.pg_index i ON (a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey))
|
||||
WHERE
|
||||
a.attnum > 0
|
||||
AND NOT a.attisdropped
|
||||
AND a.attrelid = (
|
||||
SELECT c.oid
|
||||
FROM pg_catalog.pg_class c
|
||||
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
||||
WHERE c.relname = '$tableName'
|
||||
AND n.nspname = 'public'
|
||||
)
|
||||
ORDER BY
|
||||
a.attnum;
|
||||
SQL;
|
||||
|
||||
return $sql;
|
||||
}
|
||||
}
|
9
pg4wp/rewriters/ShowTablesSQLRewriter.php
Normal file
9
pg4wp/rewriters/ShowTablesSQLRewriter.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
class ShowTablesSQLRewriter extends AbstractSQLRewriter
|
||||
{
|
||||
public function rewrite(): string
|
||||
{
|
||||
return 'SELECT tablename FROM pg_tables WHERE schemaname = \'public\';';
|
||||
}
|
||||
}
|
32
pg4wp/rewriters/UpdateSQLRewriter.php
Normal file
32
pg4wp/rewriters/UpdateSQLRewriter.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
class UpdateSQLRewriter extends AbstractSQLRewriter
|
||||
{
|
||||
public function rewrite(): string
|
||||
{
|
||||
global $wpdb;
|
||||
|
||||
$sql = $this->original();
|
||||
|
||||
$pattern = '/LIMIT[ ]+\d+/';
|
||||
$sql = preg_replace($pattern, '', $sql);
|
||||
|
||||
// Fix update wp_options
|
||||
$pattern = "/UPDATE `wp_options` SET `option_value` = NULL WHERE `option_name` = '(.+)'/";
|
||||
$match = "UPDATE `wp_options` SET `option_value` = '' WHERE `option_name` = '$1'";
|
||||
$sql = preg_replace($pattern, $match, $sql);
|
||||
|
||||
// For correct bactick removal
|
||||
$pattern = '/[ ]*`([^` ]+)`[ ]*=/';
|
||||
$sql = preg_replace($pattern, ' $1 =', $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);
|
||||
|
||||
// For correct ID quoting
|
||||
$pattern = '/(,|\s)[ ]*([^ \']*ID[^ \']*)[ ]*=/';
|
||||
$sql = preg_replace($pattern, '$1 "$2" =', $sql);
|
||||
|
||||
return $sql;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user