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 . '_term_id_seq\', (SELECT MAX(term_id) FROM ' . $wpdb->terms . ')+1);'; } break; case 'Insert': break; default: } $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 caching if($logto == 'INSERT') { $pattern = '/INSERT INTO "?([\w_]+)"? \(([^)]+)\)/i'; preg_match($pattern, $sql, $matches); if (isset($matches[1])) { $GLOBALS['pg4wp_ins_table'] = $matches[1]; } if (isset($matches[2])) { $columns_str = $matches[2]; $columns = explode(',', $columns_str); $columns = array_map(function ($column) { return trim(trim($column), '"'); }, $columns); if (isset($columns[0])) { $GLOBALS['pg4wp_ins_field'] = $columns[0]; } } $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; } /** * 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; }