125 lines
4.7 KiB
PHP
125 lines
4.7 KiB
PHP
<?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;
|
|
}
|
|
}
|